<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Android × DDD on 設計で、迷わなくなるために | 奥田智紘</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/</link><description>Recent content in Android × DDD on 設計で、迷わなくなるために | 奥田智紘</description><generator>Hugo -- 0.159.2</generator><language>ja</language><lastBuildDate>Mon, 01 Jan 0001 00:00:00 +0000</lastBuildDate><atom:link href="https://design.okuda-studio.com/books/005-android-with-ddd/index.xml" rel="self" type="application/rss+xml"/><item><title>はじめに</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/01/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/01/</guid><description>&lt;hr&gt;
&lt;h2 id="はじめに"&gt;はじめに&lt;/h2&gt;
&lt;p&gt;「DDD（ドメイン駆動設計）は Android には重い」&lt;/p&gt;
&lt;p&gt;おそらく多くの Android エンジニアが、一度はそう感じたことがあるはずです。&lt;/p&gt;
&lt;p&gt;Clean Architecture を参考に層を分け、UseCase を作り、Repository を定義し、気づけばクラスは増え続け、変更はむしろやりにくくなっている──そんな経験は珍しくありません。&lt;/p&gt;
&lt;p&gt;一方で、Web や業務系の世界では「DDD は当たり前」のように語られています。その温度差の中で、Android エンジニアはこう悩みます。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DDD をやらないと設計力が低いと思われるのではないか&lt;/li&gt;
&lt;li&gt;でも、全部やると明らかにオーバーエンジニアリングになる&lt;/li&gt;
&lt;li&gt;結局、どこまでやれば“正解”なのか分からない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本書は、その迷いに対する &lt;strong&gt;現実的な答え&lt;/strong&gt; を提示するために書きました。&lt;/p&gt;
&lt;p&gt;ここで扱う DDD は、教科書的なフルセットの DDD ではありません。Aggregate Root を厳密に守る話も、巨大なエンタープライズシステムを前提とした話も、基本的にはしません。&lt;/p&gt;
&lt;p&gt;代わりに本書が重視するのは、次の一点です。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Android アプリという制約の中で、設計が“役に立つ”状態をどう作るか。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Android アプリ開発は、UI と状態の変更が中心です。仕様変更の多くは画面に現れ、非同期処理とライフサイクルが複雑さを生みます。この文脈を無視したまま DDD の型だけを持ち込むと、設計はすぐに形骸化します。&lt;/p&gt;
&lt;p&gt;本書では、DDD を「守るべきルール」ではなく、「判断のための視点」として扱います。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;どこに境界を引くと変更が楽になるのか&lt;/li&gt;
&lt;li&gt;どの責務はドメインに置く価値があり、どれは置かなくていいのか&lt;/li&gt;
&lt;li&gt;なぜその設計を選んだのかを、言葉で説明できる状態とは何か&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これらを、Android の実装文脈と結びつけながら解説していきます。&lt;/p&gt;
&lt;p&gt;想定読者は、次のような方です。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MVVM や Clean Architecture は一通り実装したことがある&lt;/li&gt;
&lt;li&gt;UseCase や Repository を作ってはみたが、しっくりきていない&lt;/li&gt;
&lt;li&gt;「設計が大事なのは分かるが、何が大事なのか分からない」と感じている&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;逆に、DDD の原理や用語を網羅的に学びたい方や、厳密な理論体系を求める方には、本書は向いていないかもしれません。&lt;/p&gt;
&lt;p&gt;この本のゴールは、あなたが次に設計をするとき、&lt;/p&gt;
&lt;p&gt;「Android アプリという文脈で、なぜこの構造にするのか」を自分の言葉で説明できるようになること。&lt;/p&gt;
&lt;p&gt;そして、設計がプロダクトの足かせではなく、&lt;strong&gt;変更に耐えるための武器&lt;/strong&gt; になることです。&lt;/p&gt;</description></item><item><title>第1章：Android アプリ開発の現実</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/02/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/02/</guid><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="#android-%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AFui-%E9%A7%86%E5%8B%95%E7%8A%B6%E6%85%8B%E9%A7%86%E5%8B%95%E3%81%A7%E3%81%82%E3%82%8B"&gt;Android アプリは「UI 駆動・状態駆動」である&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E5%A4%89%E6%9B%B4%E7%90%86%E7%94%B1%E3%81%AE%E5%A4%A7%E5%8D%8A%E3%81%AF%E3%83%93%E3%82%B8%E3%83%8D%E3%82%B9%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84"&gt;変更理由の大半は「ビジネスロジック」ではない&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%83%AC%E3%82%A4%E3%83%A4%E3%83%BC%E3%83%89%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3%E3%81%8C%E7%A0%B4%E7%B6%BB%E3%81%97%E3%82%84%E3%81%99%E3%81%84%E7%90%86%E7%94%B1"&gt;レイヤードアーキテクチャが破綻しやすい理由&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#mvvm--usecase-%E3%81%8C%E9%87%8F%E7%94%A3%E3%81%95%E3%82%8C%E3%81%A6%E4%BE%A1%E5%80%A4%E3%82%92%E5%A4%B1%E3%81%86%E5%A0%B4%E5%90%88"&gt;MVVM + UseCase が量産されて価値を失う場合&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E6%9C%AC%E6%9B%B8%E3%81%8C%E5%89%8D%E6%8F%90%E3%81%A8%E3%81%99%E3%82%8B%E7%8F%BE%E5%AE%9F"&gt;本書が前提とする現実&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="android-アプリはui-駆動状態駆動である"&gt;Android アプリは「UI 駆動・状態駆動」である&lt;/h3&gt;
&lt;p&gt;Android アプリ開発の現実を一言で表すなら、「UI と状態の変更がすべて」と言っても過言ではありません。&lt;/p&gt;
&lt;p&gt;多くの仕様変更は、次のような形で現れます。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;画面に表示する項目が増える／減る&lt;/li&gt;
&lt;li&gt;表示条件が変わる&lt;/li&gt;
&lt;li&gt;ローディングやエラーの出し方が変わる&lt;/li&gt;
&lt;li&gt;画面遷移の分岐が増える&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;つまり、変更の起点はほぼ常に UI にあります。&lt;/p&gt;
&lt;p&gt;Web や業務系システムのように「ドメインロジックが主役で、UI はその結果を表示するだけ」という構造とは、前提が大きく異なります。Android では、UI と状態管理が設計の中心に座らざるを得ません。&lt;/p&gt;
&lt;p&gt;この事実を無視して設計を始めると、あとで必ず歪みが生まれます。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="変更理由の大半はビジネスロジックではない"&gt;変更理由の大半は「ビジネスロジック」ではない&lt;/h3&gt;
&lt;p&gt;DDD という言葉を聞くと、多くの人は「複雑なビジネスロジック」を思い浮かべます。しかし、実際の Android アプリ開発で頻発する変更理由は、それとは少し違います。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文言の変更&lt;/li&gt;
&lt;li&gt;表示順の変更&lt;/li&gt;
&lt;li&gt;UI の状態分岐の追加&lt;/li&gt;
&lt;li&gt;API レスポンスの仕様変更への追従&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これらは、いわゆる「ビジネスルールの変更」とは言いづらいものです。&lt;/p&gt;
&lt;p&gt;それにもかかわらず、すべてをドメインロジックとして抽象化しようとすると、設計は一気に重くなります。結果として、「変更が楽になるはずの設計」が、逆に変更の足かせになります。&lt;/p&gt;
&lt;p&gt;ここで重要なのは、&lt;strong&gt;すべての判断をドメインに集約しなくていい&lt;/strong&gt; という認識です。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="レイヤードアーキテクチャが破綻しやすい理由"&gt;レイヤードアーキテクチャが破綻しやすい理由&lt;/h3&gt;
&lt;p&gt;多くの Android プロジェクトは、次のような構成から始まります。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI（View / Compose）&lt;/li&gt;
&lt;li&gt;ViewModel&lt;/li&gt;
&lt;li&gt;UseCase&lt;/li&gt;
&lt;li&gt;Repository&lt;/li&gt;
&lt;li&gt;DataSource&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一見すると、責務がきれいに分離されているように見えます。しかし、プロジェクトが成長するにつれて、次のような問題が表面化します。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UseCase が単なる中継層になる&lt;/li&gt;
&lt;li&gt;ViewModel が肥大化する&lt;/li&gt;
&lt;li&gt;Repository に判断ロジックが混入する&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これは、設計が悪いから起きる問題ではありません。&lt;strong&gt;Android の変更特性と、この構造が噛み合っていない&lt;/strong&gt; ことが原因です。&lt;/p&gt;
&lt;p&gt;UI 起点の変更が増えるほど、「どこにロジックを置くべきか」の判断が曖昧になり、結果としてレイヤー間の責務が崩れていきます。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="mvvm--usecase-が量産されて価値を失う場合"&gt;MVVM + UseCase が量産されて価値を失う場合&lt;/h3&gt;
&lt;p&gt;MVVM + UseCase という構成は、多くの Android チームで採用されています。しかし、一定規模を超えたあたりから、次のような兆候が見え始めます。&lt;/p&gt;</description></item><item><title>第2章：DDD の要点だけを Android に持ち込む</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/03/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/03/</guid><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="#ddd-%E3%81%AE%E3%83%95%E3%83%AB%E3%82%BB%E3%83%83%E3%83%88%E3%81%AF-android-%E3%81%AB%E3%81%AF%E9%81%8E%E5%89%B0%E3%81%AB%E3%81%AA%E3%82%8A%E3%82%84%E3%81%99%E3%81%84"&gt;DDD のフルセットは Android には過剰になりやすい&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#android-%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E3%81%AE%E3%81%AF%E3%81%93%E3%81%AE-3-%E3%81%A4%E3%81%A0%E3%81%91"&gt;Android に必要なのは、この 3 つだけ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E5%A2%83%E7%95%8C%E3%81%AF%E5%B1%A4%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%E7%90%86%E7%94%B1%E3%81%A7%E5%BC%95%E3%81%8F"&gt;境界は「層」ではなく「理由」で引く&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%83%A6%E3%83%93%E3%82%AD%E3%82%BF%E3%82%B9%E8%A8%80%E8%AA%9E%E3%81%AF%E3%82%AF%E3%83%A9%E3%82%B9%E5%90%8D%E3%82%88%E3%82%8A%E3%82%82%E4%BC%9A%E8%A9%B1%E3%81%AB%E7%8F%BE%E3%82%8C%E3%82%8B"&gt;ユビキタス言語はクラス名よりも会話に現れる&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E5%A4%89%E6%9B%B4%E3%81%AB%E8%80%90%E3%81%88%E3%82%8B%E6%A7%8B%E9%80%A0%E3%81%A8%E3%81%AF%E5%A3%8A%E3%81%97%E3%82%84%E3%81%99%E3%81%84%E3%81%93%E3%81%A8"&gt;変更に耐える構造とは「壊しやすい」こと&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E6%8D%A8%E3%81%A6%E3%81%A6%E3%81%84%E3%81%84-ddd-%E3%81%AE%E8%A6%81%E7%B4%A0%E6%85%8E%E9%87%8D%E3%81%AB%E4%BD%BF%E3%81%86%E8%A6%81%E7%B4%A0"&gt;捨てていい DDD の要素、慎重に使う要素&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81"&gt;この章のまとめ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="ddd-のフルセットは-android-には過剰になりやすい"&gt;DDD のフルセットは Android には過剰になりやすい&lt;/h3&gt;
&lt;p&gt;DDD には多くの構成要素があります。Aggregate、Repository、Factory、Domain Service、Specification など&amp;hellip;。これらは、複雑で長寿命なドメインを扱うシステムでは強力に機能します。&lt;/p&gt;
&lt;p&gt;しかし、Android アプリの多くは、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;画面と状態の変更が中心&lt;/li&gt;
&lt;li&gt;要件の変化が早い&lt;/li&gt;
&lt;li&gt;チーム規模が小さい&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という前提のもとで開発されます。この文脈に DDD のフルセットをそのまま持ち込むと、構造はすぐに過剰になります。&lt;/p&gt;
&lt;p&gt;ここで大事なのは、「DDD をどこまで削っても本質は残るのか」を見極めることです。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="android-に必要なのはこの-3-つだけ"&gt;Android に必要なのは、この 3 つだけ&lt;/h3&gt;
&lt;p&gt;本書では、Android において最低限持ち込むべき DDD の要点を、次の 3 つに絞ります。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;境界（責務の分離）&lt;/li&gt;
&lt;li&gt;言葉（ユビキタス言語）&lt;/li&gt;
&lt;li&gt;変更に耐える構造&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;この 3 つが守られていれば、DDD の「考え方」は十分に機能します。逆に言えば、これ以外は文脈次第で捨てて構いません。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="境界は層ではなく理由で引く"&gt;境界は「層」ではなく「理由」で引く&lt;/h3&gt;
&lt;p&gt;多くの設計議論では、「どの層に置くか」が主語になりがちです。しかし DDD の本質は、層ではなく&lt;strong&gt;変更理由&lt;/strong&gt;にあります。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;なぜ、このロジックはここにあるのか&lt;/li&gt;
&lt;li&gt;どんな変更が入ったら、このコードを触ることになるのか&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;この問いに答えられる場所に、コードを置くべきです。&lt;/p&gt;
&lt;p&gt;Android では、UI 変更とドメイン（意味やルール）の変更の頻度が極端に違うことが多く、層だけで境界を引くと責務が混ざります。本書では、「変更理由が違うものは分ける」という単純なルールを、設計判断の軸にします。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="ユビキタス言語はクラス名よりも会話に現れる"&gt;ユビキタス言語はクラス名よりも会話に現れる&lt;/h3&gt;
&lt;p&gt;ユビキタス言語というと、難しいドメイン用語を正確にクラス名に落とすことだと思われがちです。しかし、本当に重要なのは、チーム内の会話で言葉が揃っていることです。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;その「状態」は何を指しているのか&lt;/li&gt;
&lt;li&gt;「有効」とは、どの条件を満たした状態なのか&lt;/li&gt;
&lt;li&gt;「未設定」と「空」は同じ意味なのか&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これらが曖昧なまま実装が進むと、設計はすぐに崩れます。&lt;/p&gt;
&lt;p&gt;本書では、ユビキタス言語を「コードを書く前に合意しておく言葉」として扱い、クラス設計よりも前段の思考として重視します。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="変更に耐える構造とは壊しやすいこと"&gt;変更に耐える構造とは「壊しやすい」こと&lt;/h3&gt;
&lt;p&gt;DDD の文脈では、「変更に強い設計」という言い方がよくされます。しかし Android 開発では、これは少し誤解を生みやすい表現です。&lt;/p&gt;</description></item><item><title>第3章：Android における「ドメイン」とは何か</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/04/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/04/</guid><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3--%E3%83%93%E3%82%B8%E3%83%8D%E3%82%B9%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF%E3%81%AF%E5%8D%8A%E5%88%86%E9%96%93%E9%81%95%E3%81%84"&gt;「ドメイン = ビジネスロジック」は半分間違い&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#android-%E3%81%AE%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%A8%E3%83%AB%E3%83%BC%E3%83%AB"&gt;Android のドメインは「判断」と「ルール」&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#ui-%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF%E3%81%A8%E3%81%AE%E5%A2%83%E7%95%8C%E7%B7%9A"&gt;UI ロジックとの境界線&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#data-%E5%B1%A4%E3%81%AB%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92%E7%BD%AE%E3%81%84%E3%81%A6%E3%81%AF%E3%81%84%E3%81%91%E3%81%AA%E3%81%84%E7%90%86%E7%94%B1"&gt;Data 層にドメインを置いてはいけない理由&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AF%E8%96%84%E3%81%8F%E3%81%A6%E3%81%84%E3%81%84%E3%81%A7%E3%82%82%E6%9B%96%E6%98%A7%E3%81%AB%E3%81%97%E3%81%A6%E3%81%AF%E3%81%84%E3%81%91%E3%81%AA%E3%81%84"&gt;ドメインは薄くていい、でも曖昧にしてはいけない&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81"&gt;この章のまとめ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="ドメイン--ビジネスロジックは半分間違い"&gt;「ドメイン = ビジネスロジック」は半分間違い&lt;/h3&gt;
&lt;p&gt;「ドメインとはビジネスロジックである」&lt;/p&gt;
&lt;p&gt;この説明は、間違いではありません。しかし、Android アプリ開発の文脈では&lt;strong&gt;それだけでは足りない&lt;/strong&gt;、というのが本書の立場です。&lt;/p&gt;
&lt;p&gt;Android アプリで頻繁に書かれているのは、次のようなコードです。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;どの状態のときに、どの UI を出すか&lt;/li&gt;
&lt;li&gt;どの条件を満たしたら操作を許可するか&lt;/li&gt;
&lt;li&gt;どの値を正とみなし、どの値を無効とみなすか&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これらは純粋なビジネスロジックとは言いづらい一方で、&lt;strong&gt;アプリとしての振る舞いを決定する重要な判断&lt;/strong&gt;です。Android におけるドメインは、この「判断」を含んだ領域だと捉える方が、実態に近いと言えます。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="android-のドメインは判断とルール"&gt;Android のドメインは「判断」と「ルール」&lt;/h3&gt;
&lt;p&gt;本書では、Android におけるドメインを、次のように定義します。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;アプリがどう振る舞うかを決める、判断とルールの集合&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;それは必ずしも、サーバー側のビジネスルールと一致する必要はありません。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;表示対象をどう選ぶか&lt;/li&gt;
&lt;li&gt;ユーザー操作をいつ無効にするか&lt;/li&gt;
&lt;li&gt;状態遷移をどの順序で許可するか&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これらは UI ロジックとも密接に関わりますが、UI そのものではありません。View や Compose の中に散らばると、変更時に全体像が見えなくなります。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="ui-ロジックとの境界線"&gt;UI ロジックとの境界線&lt;/h3&gt;
&lt;p&gt;「これは UI ロジックか、ドメインロジックか」という問いは、しばしば議論になります。しかし、白黒をはっきり分けようとすると、設計は硬直します。&lt;/p&gt;
&lt;p&gt;本書では、次の問いを境界判断の基準にします。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;この判断は、画面が変わっても同じか&lt;/li&gt;
&lt;li&gt;このルールは、UI を捨てても意味が残るか&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;どちらか一方でも「Yes」なら、そのロジックはドメイン側に寄せる価値があります。逆に、特定の UI 表現に強く依存しているなら、UI 側に残した方が自然です。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="data-層にドメインを置いてはいけない理由"&gt;Data 層にドメインを置いてはいけない理由&lt;/h3&gt;
&lt;p&gt;Android プロジェクトでは、ドメインロジックが Data 層に入り込んでしまうケースが少なくありません。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Repository 内で条件分岐が増える&lt;/li&gt;
&lt;li&gt;API レスポンスをその場で解釈し始める&lt;/li&gt;
&lt;li&gt;キャッシュ有無によって振る舞いが変わる&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これらは一見便利ですが、結果として「なぜそうなるのか」が見えなくなります。Data 層は、あくまで &lt;strong&gt;データを取得・保存する責務&lt;/strong&gt; に集中させるべきです。&lt;/p&gt;</description></item><item><title>第4章：UseCase 地獄からの脱出</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/05/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/05/</guid><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="#%E3%81%AA%E3%81%9C-usecase-%E3%81%8C%E8%82%A5%E5%A4%A7%E5%8C%96%E3%81%99%E3%82%8B%E3%81%AE%E3%81%8B"&gt;なぜ UseCase が肥大化するのか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#usecase-%E3%81%AF%E5%BF%85%E9%A0%88%E3%83%AC%E3%82%A4%E3%83%A4%E3%83%BC%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84"&gt;UseCase は「必須レイヤー」ではない&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#flow-%E3%82%92%E8%BF%94%E3%81%99-usecase-%E3%81%A8-suspend-usecase-%E3%81%AE%E5%A2%83%E7%95%8C"&gt;Flow を返す UseCase と suspend UseCase の境界&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#command-%E3%81%A8-query-%E3%82%92%E5%88%86%E3%81%91%E3%82%8B%E3%81%A8%E3%81%84%E3%81%86%E7%8F%BE%E5%AE%9F%E8%A7%A3"&gt;Command と Query を分けるという現実解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#usecase-%E3%82%92%E4%BD%9C%E3%82%89%E3%81%AA%E3%81%84%E3%81%A8%E3%81%84%E3%81%86%E9%81%B8%E6%8A%9E%E8%82%A2"&gt;UseCase を作らないという選択肢&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E9%9D%9E%E5%90%8C%E6%9C%9F%E3%82%92-usecase-%E3%81%AB%E9%96%89%E3%81%98%E8%BE%BC%E3%82%81%E3%81%99%E3%81%8E%E3%81%AA%E3%81%84"&gt;非同期を UseCase に閉じ込めすぎない&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81"&gt;この章のまとめ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="なぜ-usecase-が肥大化するのか"&gt;なぜ UseCase が肥大化するのか&lt;/h3&gt;
&lt;p&gt;UseCase は、本来「アプリケーションとしての振る舞い」を表現するための概念です。しかし Android 開発の現場では、次のような理由で簡単に肥大化します。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;画面単位で UseCase を作り始める&lt;/li&gt;
&lt;li&gt;Repository を直接触らせないための中継層になる&lt;/li&gt;
&lt;li&gt;非同期処理（Flow / suspend）の置き場として使われる&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;その結果、UseCase は「何をしているのか分からないが、とりあえずここを通す場所」になりがちです。これは設計ミスというより、&lt;strong&gt;役割が曖昧なまま使われ続けた結果&lt;/strong&gt; です。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="usecase-は必須レイヤーではない"&gt;UseCase は「必須レイヤー」ではない&lt;/h3&gt;
&lt;p&gt;多くのアーキテクチャ解説では、UseCase（あるいは Interactor）は必須レイヤーとして描かれます。しかし、本書の立場は明確です。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UseCase は、必要になったときにだけ導入する道具である。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;UseCase が価値を持つのは、次のような場合です。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;複数の UI から同じ振る舞いを呼び出す&lt;/li&gt;
&lt;li&gt;一連の操作を「1つの意味ある処理」としてまとめたい&lt;/li&gt;
&lt;li&gt;ドメインの判断を UI から切り離したい&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;逆に言えば、単に Repository を呼ぶだけの処理や、画面専用の薄い処理に UseCase を挟む必然性はありません。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="flow-を返す-usecase-と-suspend-usecase-の境界"&gt;Flow を返す UseCase と suspend UseCase の境界&lt;/h3&gt;
&lt;p&gt;Android では、UseCase が Flow を返すのか、suspend 関数なのかで悩む場面が頻発します。この問題の本質は、非同期 API の選択ではありません。&lt;/p&gt;</description></item><item><title>第5章：エンティティとモデルのリアルな設計</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/06/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/06/</guid><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="#android-%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B-entity-%E3%81%AE%E5%AF%BF%E5%91%BD%E3%81%AF%E7%9F%AD%E3%81%84"&gt;Android における Entity の寿命は短い&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#android-%E3%81%A7%E8%A8%80%E3%82%8F%E3%82%8C%E3%82%8B-entity-%E3%81%AE%E5%A4%9A%E3%81%8F%E3%81%AF-ui-model-%E3%81%A7%E3%81%82%E3%82%8B"&gt;Android で言われる Entity の多くは UI Model である&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#data-class-%E3%82%92%E6%81%90%E3%82%8C%E3%81%AA%E3%81%84"&gt;data class を恐れない&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#immutable-%E3%81%AB%E3%81%93%E3%81%A0%E3%82%8F%E3%82%8A%E3%81%99%E3%81%8E%E3%81%AA%E3%81%84"&gt;Immutable にこだわりすぎない&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#sealed-class--value-object-%E3%81%AE%E4%BD%BF%E3%81%84%E3%81%A9%E3%81%93%E3%82%8D"&gt;sealed class / value object の使いどころ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#ui-model-%E3%81%A8-domain-model-%E3%82%92%E5%88%86%E3%81%91%E3%82%8B%E6%84%8F%E5%91%B3%E5%88%86%E3%81%91%E3%81%AA%E3%81%84%E6%84%8F%E5%91%B3"&gt;UI Model と Domain Model を分ける意味・分けない意味&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#model-%E5%A4%89%E6%8F%9B%E3%81%AF%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AE%E8%B2%AC%E5%8B%99%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84"&gt;Model 変換はドメインの責務ではない&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81"&gt;この章のまとめ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="android-における-entity-の寿命は短い"&gt;Android における Entity の寿命は短い&lt;/h3&gt;
&lt;p&gt;DDD で語られる Entity は、長い時間を生き続け、同一性を保ち続ける存在として説明されます。しかし Android アプリでは、この前提がそのまま当てはまることは多くありません。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;画面仕様の変更で形がすぐに変わる&lt;/li&gt;
&lt;li&gt;API 仕様変更の影響を強く受ける&lt;/li&gt;
&lt;li&gt;UI の都合で一時的な形に変換される&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;このような環境では、Entity を「長寿命で不変な存在」として扱おうとすると、設計が無理をし始めます。&lt;/p&gt;
&lt;p&gt;本書では、Android における Entity を &lt;strong&gt;「ID による同一性を持つが、形は変わりやすい存在」&lt;/strong&gt; と捉えます。寿命が短いことを前提にすることで、過剰な抽象化を避けられます。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="android-で言われる-entity-の多くは-ui-model-である"&gt;Android で言われる Entity の多くは UI Model である&lt;/h3&gt;
&lt;p&gt;Android 開発では、データベースのテーブルや API レスポンスを
「Entity」と呼ぶことがよくあります。&lt;/p&gt;
&lt;p&gt;これらは id を持っており、一見すると DDD における Entity のように見えます。
しかし実際には、&lt;strong&gt;DDD が想定する Entity とは異なる役割&lt;/strong&gt;を担っていることがほとんどです。&lt;/p&gt;</description></item><item><title>第6章：状態管理と DDD の接点</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/07/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/07/</guid><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="#jetpack-compose-%E3%81%8C%E8%A8%AD%E8%A8%88%E3%82%92%E5%BC%B7%E5%88%B6%E3%81%99%E3%82%8B%E3%82%82%E3%81%AE"&gt;Jetpack Compose が設計を強制するもの&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#ui-state-%E3%81%AF%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AE%E6%8A%95%E5%BD%B1%E3%81%A7%E3%81%82%E3%82%8B"&gt;UI State は「ドメインの投影」である&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E9%9D%9E%E5%90%8C%E6%9C%9F%E7%8A%B6%E6%85%8B%E3%82%92%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AB%E6%8C%81%E3%81%A1%E8%BE%BC%E3%81%BE%E3%81%AA%E3%81%84"&gt;非同期状態をドメインに持ち込まない&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#stateholder--reducer-%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%81%AE%E7%8F%BE%E5%AE%9F%E7%9A%84%E3%81%AA%E4%BD%BF%E3%81%84%E6%96%B9"&gt;StateHolder / Reducer パターンの現実的な使い方&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#viewmodel-%E3%81%AF%E7%8A%B6%E6%85%8B%E3%81%AE%E7%BF%BB%E8%A8%B3%E8%80%85"&gt;ViewModel は「状態の翻訳者」&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E7%8A%B6%E6%85%8B%E3%82%92%E6%8C%81%E3%81%A1%E3%81%99%E3%81%8E%E3%81%AA%E3%81%84%E3%81%A8%E3%81%84%E3%81%86%E9%81%B8%E6%8A%9E"&gt;状態を持ちすぎないという選択&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81"&gt;この章のまとめ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="jetpack-compose-が設計を強制するもの"&gt;Jetpack Compose が設計を強制するもの&lt;/h3&gt;
&lt;p&gt;Jetpack Compose の登場によって、Android の設計は大きく変わりました。特に影響が大きいのが、「状態を中心に UI を組み立てる」という考え方です。&lt;/p&gt;
&lt;p&gt;Compose では、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI は状態の結果として描画される&lt;/li&gt;
&lt;li&gt;状態が変われば UI が再描画される&lt;/li&gt;
&lt;li&gt;状態を正しく持てないと UI が破綻する&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という前提が、半ば強制されます。&lt;/p&gt;
&lt;p&gt;これは単なる UI フレームワークの違いではなく、&lt;strong&gt;設計の中心が状態管理に移った&lt;/strong&gt; ことを意味します。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="ui-state-はドメインの投影である"&gt;UI State は「ドメインの投影」である&lt;/h3&gt;
&lt;p&gt;UI State は、しばしば「画面表示のためのデータ」として扱われます。しかし、本書では UI State を次のように捉えます。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UI State は、ドメイン上の判断結果を UI 用に投影したもの&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;つまり、UI State 自体が判断を持つべきではありません。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;表示してよいかどうか&lt;/li&gt;
&lt;li&gt;操作を許可するかどうか&lt;/li&gt;
&lt;li&gt;次にどの状態へ遷移するか&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これらはドメイン側で決まり、その結果が UI State として表現されます。この関係を意識すると、状態管理の責務が明確になります。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="非同期状態をドメインに持ち込まない"&gt;非同期状態をドメインに持ち込まない&lt;/h3&gt;
&lt;p&gt;Loading / Error / Success といった非同期状態を、ドメインモデルに含めてしまう設計を見かけることがあります。しかし、これはドメインの関心事を曖昧にします。&lt;/p&gt;</description></item><item><title>参考：Reducer を使う場合・使わない場合のサンプル</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/07-01/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/07-01/</guid><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="#%E6%83%B3%E5%AE%9A%E3%81%99%E3%82%8B%E7%94%BB%E9%9D%A2%E8%A6%81%E4%BB%B6%E5%85%B1%E9%80%9A"&gt;想定する画面要件（共通）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#reducer-%E3%82%92%E4%BD%BF%E3%82%8F%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88"&gt;Reducer を使わない場合&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#ui-state"&gt;UI State&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#viewmodel"&gt;ViewModel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E7%89%B9%E5%BE%B4"&gt;特徴&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#reducer-%E3%82%92%E4%BD%BF%E3%81%86%E5%A0%B4%E5%90%88"&gt;Reducer を使う場合&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#ui-state%E5%90%8C%E3%81%98"&gt;UI State（同じ）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#event"&gt;Event&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#reducer%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%E3%81%AE%E5%AE%9A%E7%BE%A9"&gt;Reducer（状態遷移の定義）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#viewmodelstateholder"&gt;ViewModel（StateHolder）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E7%89%B9%E5%BE%B4-1"&gt;特徴&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%A9%E3%81%A1%E3%82%89%E3%82%92%E9%81%B8%E3%81%B6%E3%81%B9%E3%81%8D%E3%81%8B"&gt;どちらを選ぶべきか&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#reducer-%E3%82%92%E4%BD%BF%E3%82%8F%E3%81%AA%E3%81%84%E6%96%B9%E3%81%8C%E3%82%88%E3%81%84%E5%A0%B4%E5%90%88"&gt;Reducer を使わない方がよい場合&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#reducer-%E3%82%92%E4%BD%BF%E3%81%86%E4%BE%A1%E5%80%A4%E3%81%8C%E5%87%BA%E3%82%8B%E5%A0%B4%E5%90%88"&gt;Reducer を使う価値が出る場合&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81"&gt;この章のまとめ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;この章では、同じ要件の画面を題材に、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reducer パターンを &lt;strong&gt;使わない場合&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Reducer パターンを &lt;strong&gt;使う場合&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;の 2 つの実装を比較します。&lt;/p&gt;
&lt;p&gt;目的は、
&lt;strong&gt;Reducer が「必要になる瞬間」がどこにあるのかを体感すること&lt;/strong&gt; です。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="想定する画面要件共通"&gt;想定する画面要件（共通）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;初期表示時にデータを読み込む&lt;/li&gt;
&lt;li&gt;読み込み中はローディング表示&lt;/li&gt;
&lt;li&gt;成功したら一覧を表示&lt;/li&gt;
&lt;li&gt;失敗したらエラーメッセージを表示&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;よくある、シンプルだが &lt;strong&gt;状態は 3 種類ある画面&lt;/strong&gt; です。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="reducer-を使わない場合"&gt;Reducer を使わない場合&lt;/h2&gt;
&lt;h3 id="ui-state"&gt;UI State&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-kotlin" data-lang="kotlin"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;data&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UiState&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;val&lt;/span&gt; isLoading: Boolean = &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;val&lt;/span&gt; items: List&amp;lt;Item&amp;gt; = emptyList(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;val&lt;/span&gt; error: String? = &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h3 id="viewmodel"&gt;ViewModel&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-kotlin" data-lang="kotlin"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SampleViewModel&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;val&lt;/span&gt; repository: ItemRepository
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) : ViewModel() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;val&lt;/span&gt; _state = MutableStateFlow(UiState())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;val&lt;/span&gt; state: StateFlow&amp;lt;UiState&amp;gt; = _state
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fun&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;load&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _state.update { &lt;span style="color:#66d9ef"&gt;it&lt;/span&gt;.copy(isLoading = &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;, error = &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;) }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; viewModelScope.launch {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; runCatching {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; repository.loadItems()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }.onSuccess { items &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _state.update {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;it&lt;/span&gt;.copy(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; isLoading = &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; items = items
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }.onFailure { e &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _state.update {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;it&lt;/span&gt;.copy(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; isLoading = &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error = e.message
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h3 id="特徴"&gt;特徴&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;コード量が少ない&lt;/li&gt;
&lt;li&gt;処理の流れが直線的で追いやすい&lt;/li&gt;
&lt;li&gt;小規模な画面では十分に読みやすい&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一方で、&lt;/p&gt;</description></item><item><title>第7章：Repository はどこまで責務を持つべきか</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/08/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/08/</guid><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="#repository-%E3%81%AF%E6%B0%B8%E7%B6%9A%E5%8C%96%E3%81%AE%E6%8A%BD%E8%B1%A1%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84"&gt;Repository は「永続化の抽象」ではない&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#android-%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B-repository-%E3%81%AE%E6%9C%80%E9%81%A9%E8%B2%AC%E5%8B%99"&gt;Android における Repository の最適責務&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#repository-%E3%81%AB%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF%E3%81%8C%E9%9B%86%E3%81%BE%E3%82%8A%E3%82%84%E3%81%99%E3%81%84%E7%90%86%E7%94%B1"&gt;Repository にロジックが集まりやすい理由&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#datasource-%E3%82%92%E5%88%86%E3%81%91%E3%81%99%E3%81%8E%E3%82%8B%E5%95%8F%E9%A1%8C"&gt;DataSource を分けすぎる問題&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5%E6%88%A6%E7%95%A5%E3%81%A8%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E6%B1%9A%E6%9F%93"&gt;キャッシュ戦略とドメイン汚染&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#repository-%E3%81%AF%E8%96%84%E3%81%8F%E3%81%A6%E3%81%84%E3%81%84%E3%81%8C%E9%9B%91%E3%81%A7%E3%81%82%E3%81%A3%E3%81%A6%E3%81%AF%E3%81%84%E3%81%91%E3%81%AA%E3%81%84"&gt;Repository は「薄くていい」が「雑であってはいけない」&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81"&gt;この章のまとめ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="repository-は永続化の抽象ではない"&gt;Repository は「永続化の抽象」ではない&lt;/h3&gt;
&lt;p&gt;DDD の文脈では、Repository はしばしば「永続化の抽象」と説明されます。しかし、この説明を Android にそのまま当てはめると、Repository の責務は一気に分かりづらくなります。&lt;/p&gt;
&lt;p&gt;Android アプリの Repository が相手にしているのは、必ずしも「永続化」だけではありません。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API 通信&lt;/li&gt;
&lt;li&gt;ローカル DB&lt;/li&gt;
&lt;li&gt;キャッシュ&lt;/li&gt;
&lt;li&gt;インメモリ状態&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これらをすべて「永続化」と呼ぶのは、少し無理があります。&lt;/p&gt;
&lt;p&gt;本書では、Android における Repository を次のように捉えます。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Repository は、ドメインから見た「データ取得・保存の窓口」である&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;重要なのは、「どこから取ってくるか」や「どう保存するか」をドメインが知らなくてよい状態を作ることです。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="android-における-repository-の最適責務"&gt;Android における Repository の最適責務&lt;/h3&gt;
&lt;p&gt;Android の Repository が担うべき責務は、非常にシンプルです。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;必要なデータを取得する&lt;/li&gt;
&lt;li&gt;必要なデータを保存する&lt;/li&gt;
&lt;li&gt;データ取得手段の違いを隠蔽する&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;逆に言えば、次のようなことは Repository の責務ではありません。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ビジネス判断&lt;/li&gt;
&lt;li&gt;状態遷移の決定&lt;/li&gt;
&lt;li&gt;UI 表示の都合による変換&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Repository が「判断」を持ち始めた瞬間、設計は濁り始めます。&lt;/p&gt;
&lt;p&gt;たとえば、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;この場合はキャッシュを返す／返さない&lt;/li&gt;
&lt;li&gt;この条件なら空リストにする&lt;/li&gt;
&lt;li&gt;エラーを成功として扱う&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;といった判断が Repository に入り込むと、「なぜそうなるのか」を追うのが非常に難しくなります。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="repository-にロジックが集まりやすい理由"&gt;Repository にロジックが集まりやすい理由&lt;/h3&gt;
&lt;p&gt;Repository は、設計が崩れ始めたときに、もっともロジックが集まりやすい場所です。その理由は単純です。&lt;/p&gt;</description></item><item><title>第8章：DI・Hilt と DDD の付き合い方</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/09/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/09/</guid><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="#hilt-%E3%81%AF%E8%A8%AD%E8%A8%88%E3%82%92%E8%89%AF%E3%81%8F%E3%82%82%E3%81%97%E3%81%AA%E3%81%84%E3%81%97%E6%82%AA%E3%81%8F%E3%82%82%E3%81%97%E3%81%AA%E3%81%84"&gt;Hilt は設計を良くもしないし悪くもしない&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#di-%E5%B0%8E%E5%85%A5%E3%81%AE%E6%9C%AC%E5%BD%93%E3%81%AE%E7%9B%AE%E7%9A%84"&gt;DI 導入の本当の目的&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E5%88%86%E5%89%B2%E3%81%AB%E3%82%88%E3%82%8B%E7%89%A9%E7%90%86%E7%9A%84%E5%88%B6%E7%B4%84"&gt;モジュール分割による物理的制約&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#module-%E5%9C%B0%E7%8D%84%E3%81%AF%E3%81%AA%E3%81%9C%E8%B5%B7%E3%81%8D%E3%82%8B%E3%81%AE%E3%81%8B"&gt;Module 地獄はなぜ起きるのか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#di-%E3%81%97%E3%81%AA%E3%81%8F%E3%81%A6%E3%81%84%E3%81%84%E3%82%82%E3%81%AE%E3%82%92%E8%A6%8B%E6%A5%B5%E3%82%81%E3%82%8B"&gt;DI しなくていいものを見極める&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#repository-%E3%81%A8-hilt-%E3%81%AE%E3%81%A1%E3%82%87%E3%81%86%E3%81%A9%E3%81%84%E3%81%84%E8%B7%9D%E9%9B%A2%E6%84%9F"&gt;Repository と Hilt のちょうどいい距離感&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#baseactivity--baseviewmodel-%E3%82%92%E4%BD%9C%E3%82%89%E3%81%AA%E3%81%84%E7%90%86%E7%94%B1"&gt;BaseActivity / BaseViewModel を作らない理由&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#compositionlocal-%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E4%BE%9D%E5%AD%98%E3%81%AE%E6%B8%A1%E3%81%97%E6%96%B9"&gt;CompositionLocal を使った依存の渡し方&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#di-%E3%81%8C%E8%A8%AD%E8%A8%88%E3%82%92%E5%A3%8A%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%82%B5%E3%82%A4%E3%83%B3"&gt;DI が設計を壊しているサイン&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81"&gt;この章のまとめ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="hilt-は設計を良くもしないし悪くもしない"&gt;Hilt は設計を良くもしないし悪くもしない&lt;/h3&gt;
&lt;p&gt;DI（Dependency Injection）や Hilt は、しばしば「設計を良くする魔法の道具」のように語られます。しかし、本書ではまずこの幻想をはっきり否定しておきます。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hilt は、設計を良くもしないし、悪くもしない。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hilt がやってくれるのは、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;依存関係の生成を肩代わりすること&lt;/li&gt;
&lt;li&gt;オブジェクトのライフサイクルを管理すること&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;だけです。&lt;/p&gt;
&lt;p&gt;依存の向きが正しいか、責務が分離されているか、境界が妥当か──それらは Hilt では一切保証されません。むしろ、設計が曖昧なまま Hilt を使うと、その曖昧さがコード全体に固定されてしまいます。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="di-導入の本当の目的"&gt;DI 導入の本当の目的&lt;/h3&gt;
&lt;p&gt;DI を導入する目的は、テスト容易性や疎結合化だと説明されることが多いですが、Android × DDD の文脈では、もう一つ重要な目的があります。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;「依存の方向」をコードとして固定すること&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ViewModel は Domain に依存してよい&lt;/li&gt;
&lt;li&gt;Domain は Data に依存してはいけない&lt;/li&gt;
&lt;li&gt;Data は Domain を知らなくてよい&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;この関係を、new ではなく DI によって表現することで、「間違った依存」を作りにくくなります。Hilt は、この構造を &lt;em&gt;楽に維持するための道具&lt;/em&gt; です。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="モジュール分割による物理的制約"&gt;モジュール分割による物理的制約&lt;/h3&gt;
&lt;p&gt;DI 導入するだけでは、間違った依存を制限することはできません。しかし、モジュール分割も合わせて導入することで、制限することができます。&lt;/p&gt;</description></item><item><title>第9章：Android × DDD で起こりやすい設計の落とし穴</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/10/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/10/</guid><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="#clean-architecture-%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E6%8C%81%E3%81%A1%E8%BE%BC%E3%82%93%E3%81%A0%E4%BE%8B"&gt;Clean Architecture をそのまま持ち込んだ例&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#%E4%BD%95%E3%81%8C%E8%B5%B7%E3%81%8D%E3%81%9F%E3%81%8B"&gt;何が起きたか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%AA%E3%81%9C%E5%A4%B1%E6%95%97%E3%81%97%E3%81%9F%E3%81%AE%E3%81%8B"&gt;なぜ失敗したのか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E4%BD%95%E3%82%92%E5%AD%A6%E3%81%B6%E3%81%B9%E3%81%8D%E3%81%8B"&gt;何を学ぶべきか&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#usecase-%E3%81%8C-100-%E5%80%8B%E3%82%92%E8%B6%85%E3%81%88%E3%81%9F%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88"&gt;UseCase が 100 個を超えたプロジェクト&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#%E4%BD%95%E3%81%8C%E8%B5%B7%E3%81%8D%E3%81%9F%E3%81%8B-1"&gt;何が起きたか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%AA%E3%81%9C%E5%A4%B1%E6%95%97%E3%81%97%E3%81%9F%E3%81%AE%E3%81%8B-1"&gt;なぜ失敗したのか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E4%BD%95%E3%82%92%E5%AD%A6%E3%81%B6%E3%81%B9%E3%81%8D%E3%81%8B-1"&gt;何を学ぶべきか&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E5%B1%A4%E3%81%8C-util-%E5%B1%A4%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E8%A9%B1"&gt;ドメイン層が util 層になった話&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#%E4%BD%95%E3%81%8C%E8%B5%B7%E3%81%8D%E3%81%9F%E3%81%8B-2"&gt;何が起きたか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%AA%E3%81%9C%E5%A4%B1%E6%95%97%E3%81%97%E3%81%9F%E3%81%AE%E3%81%8B-2"&gt;なぜ失敗したのか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E4%BD%95%E3%82%92%E5%AD%A6%E3%81%B6%E3%81%B9%E3%81%8D%E3%81%8B-2"&gt;何を学ぶべきか&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%83%86%E3%82%B9%E3%83%88%E3%81%97%E3%82%84%E3%81%99%E3%81%84%E3%81%AF%E3%81%9A%E3%81%8C%E8%AA%B0%E3%82%82%E3%83%86%E3%82%B9%E3%83%88%E3%82%92%E6%9B%B8%E3%81%8B%E3%81%AA%E3%81%84%E6%A7%8B%E9%80%A0"&gt;テストしやすいはずが、誰もテストを書かない構造&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#%E4%BD%95%E3%81%8C%E8%B5%B7%E3%81%8D%E3%81%9F%E3%81%8B-3"&gt;何が起きたか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%AA%E3%81%9C%E5%A4%B1%E6%95%97%E3%81%97%E3%81%9F%E3%81%AE%E3%81%8B-3"&gt;なぜ失敗したのか&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E4%BD%95%E3%82%92%E5%AD%A6%E3%81%B6%E3%81%B9%E3%81%8D%E3%81%8B-3"&gt;何を学ぶべきか&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;この章では、Android アプリに DDD の考え方を真面目に適用しようとしたときに、構造上起こりやすい失敗例を取り上げる。&lt;/p&gt;
&lt;p&gt;いずれも「考え方としては間違っていない」からこそ起きるものであり、設計を真剣に考えた結果として現れる。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="clean-architecture-をそのまま持ち込んだ例"&gt;Clean Architecture をそのまま持ち込んだ例&lt;/h2&gt;
&lt;h3 id="何が起きたか"&gt;何が起きたか&lt;/h3&gt;
&lt;p&gt;Web や書籍で学んだ Clean Architecture を、そのまま Android アプリに適用したプロジェクトでは、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;presentation / domain / data が厳密に分離され&lt;/li&gt;
&lt;li&gt;すべての依存は内側に向き&lt;/li&gt;
&lt;li&gt;あらゆる処理が UseCase を経由する&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という構造が作られた。&lt;/p&gt;
&lt;p&gt;構造としては美しく、レビューでも「設計は正しい」と評価されていた。しかし、実装が進むにつれて次のような問題が顕在化した。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ちょっとした画面修正でも複数レイヤーに修正が必要&lt;/li&gt;
&lt;li&gt;UI 変更のたびに Domain 側の調整が発生&lt;/li&gt;
&lt;li&gt;実装コストが高く、改善のスピードが落ちる&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="なぜ失敗したのか"&gt;なぜ失敗したのか&lt;/h3&gt;
&lt;p&gt;Clean Architecture 自体が悪いのではない。問題は、&lt;strong&gt;Android アプリの特性を考慮せずに、そのまま当てはめたこと&lt;/strong&gt;にある。&lt;/p&gt;
&lt;p&gt;Android アプリでは、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI の変更頻度が高い&lt;/li&gt;
&lt;li&gt;画面単位のロジックが多い&lt;/li&gt;
&lt;li&gt;永続的な業務ルールが存在しないケースも多い&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;にもかかわらず、すべてを「安定した Domain がある前提」で設計してしまったことで、構造が過剰になった。&lt;/p&gt;</description></item><item><title>第10章：小さく始める DDD</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/11/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/11/</guid><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="#ddd-%E3%81%AF%E6%9C%80%E5%88%9D%E3%81%8B%E3%82%89%E5%AE%8C%E6%88%90%E3%81%95%E3%81%9B%E3%82%8B%E3%82%82%E3%81%AE%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84"&gt;DDD は「最初から完成させるもの」ではない&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%84%E3%81%8D%E3%81%AA%E3%82%8A%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E5%B1%A4%E3%82%92%E4%BD%9C%E3%82%89%E3%81%AA%E3%81%84"&gt;いきなりドメイン層を作らない&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E5%A2%83%E7%95%8C%E3%82%92-1-%E7%AE%87%E6%89%80%E3%81%A0%E3%81%91%E6%B1%BA%E3%82%81%E3%82%8B"&gt;境界を 1 箇所だけ決める&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E8%A8%80%E8%91%89%E3%82%92%E6%8F%83%E3%81%88%E3%82%8B%E3%81%A8%E3%81%93%E3%82%8D%E3%81%8B%E3%82%89%E5%A7%8B%E3%82%81%E3%82%8B"&gt;言葉を揃えるところから始める&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%83%AA%E3%83%95%E3%82%A1%E3%82%AF%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0%E5%89%8D%E6%8F%90%E3%81%AE%E8%A8%AD%E8%A8%88"&gt;リファクタリング前提の設計&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E5%B0%8F%E3%81%95%E3%81%8F%E5%A7%8B%E3%82%81%E3%81%9F-ddd-%E3%81%AF%E3%81%82%E3%81%A8%E3%81%8B%E3%82%89%E8%82%B2%E3%81%A6%E3%82%89%E3%82%8C%E3%82%8B"&gt;小さく始めた DDD は、あとから育てられる&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81"&gt;この章のまとめ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="ddd-は最初から完成させるものではない"&gt;DDD は「最初から完成させるもの」ではない&lt;/h3&gt;
&lt;p&gt;DDD という言葉には、どうしても「最初にきれいな構造を作らなければならない」という印象がつきまといます。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ドメイン層を用意する&lt;/li&gt;
&lt;li&gt;UseCase を定義する&lt;/li&gt;
&lt;li&gt;Repository を抽象化する&lt;/li&gt;
&lt;li&gt;Entity を厳密に設計する&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これらを &lt;em&gt;一気に&lt;/em&gt; やろうとした瞬間、設計は重くなります。
そして多くの場合、その重さに耐えきれず、DDD は「途中で放置される構造」になります。&lt;/p&gt;
&lt;p&gt;本書が提案する DDD の始め方は、その逆です。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;最初から正解を作らない。
あとで壊す前提で、小さく置く。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="いきなりドメイン層を作らない"&gt;いきなりドメイン層を作らない&lt;/h3&gt;
&lt;p&gt;DDD を始めようとすると、真っ先にやりたくなるのが「domain パッケージを作ること」です。
しかし、これはもっとも失敗しやすい第一歩でもあります。&lt;/p&gt;
&lt;p&gt;理由は単純です。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;何がドメインなのか、まだ分かっていない&lt;/li&gt;
&lt;li&gt;どこが変わりやすいか、まだ見えていない&lt;/li&gt;
&lt;li&gt;判断とロジックがどこに集まるか、まだ確信がない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;この状態でドメイン層を作ると、そこはすぐに &lt;strong&gt;“よく分からないコード置き場”&lt;/strong&gt; になります。&lt;/p&gt;
&lt;p&gt;本書では、次のような始め方を推奨します。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;まずは ViewModel と Repository だけで作る&lt;/li&gt;
&lt;li&gt;判断ロジックを「ここ怪しいな」と思う場所に集める&lt;/li&gt;
&lt;li&gt;それが固まり始めたら、初めて「ここがドメインだ」と名付ける&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;ドメインは作るものではなく、浮かび上がってくるもの&lt;/strong&gt; です。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="境界を-1-箇所だけ決める"&gt;境界を 1 箇所だけ決める&lt;/h3&gt;
&lt;p&gt;DDD を導入しようとすると、つい「すべての境界を正しく引こう」としてしまいます。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI と Domain&lt;/li&gt;
&lt;li&gt;Domain と Data&lt;/li&gt;
&lt;li&gt;UseCase と Repository&lt;/li&gt;
&lt;li&gt;Entity と Model&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;しかし、最初から全部やる必要はありません。&lt;/p&gt;</description></item><item><title>第11章：口座振替メモアプリの設計</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/12/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/12/</guid><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="#%E8%A6%81%E4%BB%B6%E6%95%B4%E7%90%86%E3%81%A8%E8%A8%80%E8%91%89%E3%81%AE%E5%AE%9A%E7%BE%A9"&gt;要件整理と言葉の定義&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E5%A2%83%E7%95%8C%E3%81%AE%E6%B1%BA%E5%AE%9A"&gt;境界の決定&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%83%87%E3%83%BC%E3%82%BF--%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3--ui-%E3%81%AE%E6%B5%81%E3%82%8C"&gt;データ → ドメイン → UI の流れ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E5%AE%9F%E8%A3%85%E3%82%B9%E3%82%B1%E3%83%83%E3%83%81"&gt;実装スケッチ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E5%AE%9F%E4%BE%8B%E3%81%8B%E3%82%89%E5%88%86%E3%81%8B%E3%82%8B%E3%81%93%E3%81%A8"&gt;実例から分かること&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81"&gt;この章のまとめ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;この章では、本書で扱ってきた考え方を、
&lt;strong&gt;実在する小さな Android アプリ&lt;/strong&gt;に当てはめてみます。&lt;/p&gt;
&lt;p&gt;題材は「口座振替メモアプリ」です。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;電気料金&lt;/li&gt;
&lt;li&gt;クレジットカード&lt;/li&gt;
&lt;li&gt;サブスクリプション&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;といった &lt;em&gt;引き落とし元&lt;/em&gt; と &lt;em&gt;引き落とし先&lt;/em&gt; を記録し、
「どこから、何が、どう引き落とされているのか」を把握するためのアプリです。&lt;/p&gt;
&lt;p&gt;DDD の用語を説明する章ではありません。
&lt;strong&gt;どう判断し、どこに線を引いたか&lt;/strong&gt; を追う章です。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="要件整理と言葉の定義"&gt;要件整理と言葉の定義&lt;/h3&gt;
&lt;p&gt;最初にやったのは、クラス設計ではありません。
&lt;strong&gt;言葉を揃えること&lt;/strong&gt; でした。&lt;/p&gt;
&lt;p&gt;このアプリでは、次のような言葉が登場します。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;口座&lt;/li&gt;
&lt;li&gt;引き落とし&lt;/li&gt;
&lt;li&gt;引き落とし元&lt;/li&gt;
&lt;li&gt;引き落とし先&lt;/li&gt;
&lt;li&gt;メモ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ここで重要なのは、「それぞれが何を指すのか」を明確にすることです。&lt;/p&gt;
&lt;p&gt;たとえば、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;「口座」は銀行口座だけを指すのか&lt;/li&gt;
&lt;li&gt;クレジットカードは口座なのか&lt;/li&gt;
&lt;li&gt;引き落とし元と引き落とし先は対等な存在か&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;この時点で、次のように定義しました。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;引き落とし元
&lt;ul&gt;
&lt;li&gt;実際にお金が減る側（銀行口座やクレジットカード）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;引き落とし先
&lt;ul&gt;
&lt;li&gt;電気料金やサブスクなど、支払いの理由となるもの&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;口座振替
&lt;ul&gt;
&lt;li&gt;「引き落とし元」と「引き落とし先」を結びつける関係&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;この定義は、&lt;strong&gt;コードより先に決まっています&lt;/strong&gt;。
そして、この言葉がそのままクラス名や変数名になります。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="境界の決定"&gt;境界の決定&lt;/h3&gt;
&lt;p&gt;このアプリで最初に決めた境界は、たった一つです。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;「UI は、引き落としの判断をしない」&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;有効かどうか&lt;/li&gt;
&lt;li&gt;表示すべきかどうか&lt;/li&gt;
&lt;li&gt;どちらが元で、どちらが先か&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;こういった判断は、UI に書かないと決めました。&lt;/p&gt;
&lt;p&gt;その結果、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI は「表示するだけ」&lt;/li&gt;
&lt;li&gt;判断は ViewModel より下に集まる&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という自然な流れが生まれます。&lt;/p&gt;
&lt;p&gt;この時点では、&lt;/p&gt;</description></item><item><title>おわりに</title><link>https://design.okuda-studio.com/books/005-android-with-ddd/13/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://design.okuda-studio.com/books/005-android-with-ddd/13/</guid><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="#ddd-%E3%81%AF%E7%9B%AE%E7%9A%84%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%E6%89%8B%E6%AE%B5"&gt;DDD は目的ではなく手段&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#android-%E9%96%8B%E7%99%BA%E3%81%A7%E4%B8%80%E7%95%AA%E5%A4%A7%E4%BA%8B%E3%81%AA%E3%81%AE%E3%81%AF%E5%A3%8A%E3%81%97%E3%82%84%E3%81%99%E3%81%95"&gt;Android 開発で一番大事なのは「壊しやすさ」&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#%E8%A8%AD%E8%A8%88%E3%81%AF%E3%83%81%E3%83%BC%E3%83%A0%E3%81%A8%E3%83%97%E3%83%AD%E3%83%80%E3%82%AF%E3%83%88%E3%81%AE%E6%96%87%E8%84%88%E3%81%A7%E5%A4%89%E3%82%8F%E3%82%8B"&gt;設計はチームとプロダクトの文脈で変わる&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;本書では、ドメイン駆動設計（DDD）を Android 開発の文脈で、できるだけ現実的に扱ってきました。
理論を網羅することや、正統派の実装を示すことが目的ではありません。
ここで伝えたかったのは、&lt;strong&gt;DDD をどう「使うか」&lt;/strong&gt; という視点です。&lt;/p&gt;
&lt;h3 id="ddd-は目的ではなく手段"&gt;DDD は目的ではなく手段&lt;/h3&gt;
&lt;p&gt;DDD を採用すること自体に価値があるわけではありません。
価値があるのは、DDD が &lt;strong&gt;判断を助けてくれること&lt;/strong&gt;、&lt;strong&gt;会話を整理してくれること&lt;/strong&gt;、そして &lt;strong&gt;設計の迷いを減らしてくれること&lt;/strong&gt; です。&lt;/p&gt;
&lt;p&gt;もし DDD を導入した結果、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;クラスが増えすぎて全体が見えなくなった&lt;/li&gt;
&lt;li&gt;抽象が先行して実装が進まなくなった&lt;/li&gt;
&lt;li&gt;チーム内で言葉が通じなくなった&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;のであれば、それは設計が目的化してしまっています。&lt;/p&gt;
&lt;p&gt;設計は、プロダクトを前に進めるための道具です。
DDD もまた、そのための選択肢のひとつに過ぎません。&lt;/p&gt;
&lt;h3 id="android-開発で一番大事なのは壊しやすさ"&gt;Android 開発で一番大事なのは「壊しやすさ」&lt;/h3&gt;
&lt;p&gt;Android アプリは、要件が変わります。
画面が増え、仕様が揺れ、API が変わり、ビジネスの都合も介入します。&lt;/p&gt;
&lt;p&gt;その現実の中で重要なのは、
&lt;strong&gt;「最初から正しい設計」ではなく「あとから直せる設計」&lt;/strong&gt; です。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;境界があるから、影響範囲が読める&lt;/li&gt;
&lt;li&gt;言葉が揃っているから、変更点を議論できる&lt;/li&gt;
&lt;li&gt;責務が分かれているから、壊す勇気を持てる&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本書で扱ってきた DDD の要素は、すべてこの &lt;strong&gt;壊しやすさ&lt;/strong&gt; に収束します。
堅牢さのためではなく、柔らかさのための設計です。&lt;/p&gt;
&lt;h3 id="設計はチームとプロダクトの文脈で変わる"&gt;設計はチームとプロダクトの文脈で変わる&lt;/h3&gt;
&lt;p&gt;最後に、強調しておきたいことがあります。&lt;/p&gt;
&lt;p&gt;設計に「唯一の正解」はありません。
あなたがいるチーム、扱っているプロダクト、求められるスピードや品質によって、
最適な設計は必ず変わります。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 人開発なら、境界は最小でいい&lt;/li&gt;
&lt;li&gt;小さなアプリなら、ドメインは薄くていい&lt;/li&gt;
&lt;li&gt;チームが育ってきたら、言葉と責務を強く意識すればいい&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;DDD はフルセットで導入するものではありません。
必要な部分だけを、必要なタイミングで取り入れていく。
それで十分です。&lt;/p&gt;
&lt;p&gt;もし本書を読み終えて、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;設計について少し考える余裕が生まれた&lt;/li&gt;
&lt;li&gt;「これはドメインの話だな」と立ち止まれるようになった&lt;/li&gt;
&lt;li&gt;設計を言葉で説明できる感覚が掴めた&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;のであれば、この本の役割は果たせています。&lt;/p&gt;
&lt;p&gt;DDD は、あなたの開発を縛るものではありません。
あなたの判断を、少しだけ楽にしてくれる存在であってほしい。&lt;/p&gt;</description></item></channel></rss>