[{"content":"本書の主張は、次の一文に集約されます。\n良い設計とは、壊そうと思っても壊せない構造を作ることである。\nここで言う「壊れない」とは、 バグが一切出ないという意味ではありません。 気合や注意力、経験年数に依存しないコードである、という意味です。\n良い設計がされたコードは、 間違った使い方をしようとすると、\nそもそもコンパイルできない。 あるいは、実行する前の段階で違和感として現れる。 これは、 構造そのものが人を正しい方向に導くから成り立つものです。\n多くの現場では、 「速く書けること」が価値として評価されがちです。 短期間で動くものを作れること自体は、確かに意味があります。\nただし本書では、 速さそのものを価値だとは定義しません。\nなぜなら、 速く書かれたコードは、 将来の時間を消費することが多いからです。\n一方で、良い設計は、\n読めば意図が伝わる構造 変更点が局所に閉じる構成 間違ったコードを書けない制約 引き継ぎ時の説明コストの低下 未来の時間を買う といった性質を持ちます。\nこれらは、 設計という構造の力によって生まれます。\n本書では、シニアエンジニアが 「センス」や「経験則」として扱ってきた設計を、 明確に言語化された「文章」として記し、 設計するための思考の土台 としての役割を果たします。\n例えば、設計の土台には次のようなものがあります。\n判断をどこで完了させるか 状態に嘘をつかせないこと 責務の境界を明確にすること 変更理由が一つになるように構造を作ること 設計とは、 未来の自分や他人の行動を、構造によって制限すること だと考えています。\nドキュメントをどれだけ丁寧に整備しても、 時間が経てば読まれなくなります。 コードとの乖離が起き、 存在していないのと同じ状態になることもあります。\n一方で、良い設計は、 ドキュメントを必要としません。\nコードそのものがルールであり、 コンパイラがそのルールを強制する からです。\n本書では、 この「コンパイラに仕事をさせる設計」を重視します。\n設計がきれいなコードは、属人化しません。\n特定の人がいなければ回らない状態は、 人の問題ではなく、設計の問題です。\n後から参加した人が、 コードを読み、構造を理解し、 安心して変更できる。\nその状態を作ることが、 設計に責任を持つということ だと考えています。\n本書は、 特定の言語やフレームワークを解説する本ではありません。\nAndroid、iOS、サーバーサイドなど、 分野が違っても共通する 設計の本質 を言語化することを目的としています。\n早く書くための本ではなく、 壊れない構造を作るための本です。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/00-overview/","summary":"\u003cp\u003e本書の主張は、次の一文に集約されます。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e良い設計とは、壊そうと思っても壊せない構造を作ることである。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eここで言う「壊れない」とは、\nバグが一切出ないという意味ではありません。\n気合や注意力、経験年数に依存しないコードである、という意味です。\u003c/p\u003e\n\u003cp\u003e良い設計がされたコードは、\n間違った使い方をしようとすると、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eそもそもコンパイルできない。\u003c/li\u003e\n\u003cli\u003eあるいは、実行する前の段階で違和感として現れる。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれは、\n\u003cstrong\u003e構造そのものが人を正しい方向に導くから成り立つものです。\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e多くの現場では、\n「速く書けること」が価値として評価されがちです。\n短期間で動くものを作れること自体は、確かに意味があります。\u003c/p\u003e\n\u003cp\u003eただし本書では、\n\u003cstrong\u003e速さそのものを価値だとは定義しません。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eなぜなら、\n速く書かれたコードは、\n将来の時間を消費することが多いからです。\u003c/p\u003e\n\u003cp\u003e一方で、良い設計は、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e読めば意図が伝わる構造\u003c/li\u003e\n\u003cli\u003e変更点が局所に閉じる構成\u003c/li\u003e\n\u003cli\u003e間違ったコードを書けない制約\u003c/li\u003e\n\u003cli\u003e引き継ぎ時の説明コストの低下\u003c/li\u003e\n\u003cli\u003e未来の時間を買う\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった性質を持ちます。\u003c/p\u003e\n\u003cp\u003eこれらは、\n\u003cstrong\u003e設計という構造の力によって生まれます。\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e本書では、シニアエンジニアが\n「センス」や「経験則」として扱ってきた設計を、\n明確に言語化された「文章」として記し、\n\u003cstrong\u003e設計するための思考の土台\u003c/strong\u003e としての役割を果たします。\u003c/p\u003e\n\u003cp\u003e例えば、設計の土台には次のようなものがあります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e判断をどこで完了させるか\u003c/li\u003e\n\u003cli\u003e状態に嘘をつかせないこと\u003c/li\u003e\n\u003cli\u003e責務の境界を明確にすること\u003c/li\u003e\n\u003cli\u003e変更理由が一つになるように構造を作ること\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003e設計とは、\n\u003cstrong\u003e未来の自分や他人の行動を、構造によって制限すること\u003c/strong\u003e\nだと考えています。\u003c/p\u003e\n\u003cp\u003eドキュメントをどれだけ丁寧に整備しても、\n時間が経てば読まれなくなります。\nコードとの乖離が起き、\n存在していないのと同じ状態になることもあります。\u003c/p\u003e\n\u003cp\u003e一方で、良い設計は、\nドキュメントを必要としません。\u003c/p\u003e\n\u003cp\u003eコードそのものがルールであり、\n\u003cstrong\u003eコンパイラがそのルールを強制する\u003c/strong\u003e からです。\u003c/p\u003e\n\u003cp\u003e本書では、\nこの「コンパイラに仕事をさせる設計」を重視します。\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e設計がきれいなコードは、属人化しません。\u003c/p\u003e\n\u003cp\u003e特定の人がいなければ回らない状態は、\n人の問題ではなく、設計の問題です。\u003c/p\u003e\n\u003cp\u003e後から参加した人が、\nコードを読み、構造を理解し、\n安心して変更できる。\u003c/p\u003e\n\u003cp\u003eその状態を作ることが、\n\u003cstrong\u003e設計に責任を持つということ\u003c/strong\u003e\nだと考えています。\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e本書は、\n特定の言語やフレームワークを解説する本ではありません。\u003c/p\u003e\n\u003cp\u003eAndroid、iOS、サーバーサイドなど、\n分野が違っても共通する\n\u003cstrong\u003e設計の本質\u003c/strong\u003e を言語化することを目的としています。\u003c/p\u003e\n\u003cp\u003e早く書くための本ではなく、\n壊れない構造を作るための本です。\u003c/p\u003e","title":"本書の主張"},{"content":" 設計ができないのではなく、判断が残っていないだけ 設計が壊れるのは、いつか 良い設計者は、うまいコードを書いているとは限らない モノリスは、問題そのものではない 構造より先に、判断がある 再現できなかったのは、技術ではない この本が扱うのは「正解」ではない 設計とは、未来に対する判断である 設計ができないのではなく、判断が残っていないだけ 多くの現場では、\n「設計が弱い」「設計ができていない」\nという言葉が使われます。\nコードが複雑になっている。\n変更に弱い。\n触るのが怖い。\nそうした状態をまとめて、\n「設計の問題」と呼ぶことは珍しくありません。\nただし本書では、\nこの捉え方を少しだけ変えます。\n多くの場合、\n問題は設計そのものではありません。\n判断が、残っていないのです。\n設計が壊れるのは、いつか 設計が壊れる瞬間は、\n突然訪れるわけではありません。\nある日いきなり破綻するのではなく、\n小さな判断が、少しずつ積み重なった結果として現れます。\nたとえば、\nとりあえず今はこれでいい。\n前からこうなっている。\nあとで直せばいい。\nここまで影響しないと思った。\nこうした判断自体が、\n必ずしも間違っているわけではありません。\n問題は、\nその判断がどんな前提で行われたのかが、\nコードにも、ドキュメントにも、\n残っていないことです。\n設計が壊れるのは、判断の理由が失われたときです。\n良い設計者は、うまいコードを書いているとは限らない 設計ができる人、という言葉から、\n次のような人物像を思い浮かべる人も多いかもしれません。\n抽象化がうまい人。\n新しいアーキテクチャに詳しい人。\nきれいなコードを書ける人。\nしかし本書では、\nそれを設計者の条件だとは考えません。\n良い設計者とは、\n判断を説明できる人です。\nなぜこの構造にしたのか。\nなぜ今はやらなかったのか。\nなぜ将来の変更を見送ったのか。\nそれらを、\n感覚や雰囲気ではなく、\n後付けの理由でもなく、\n当時の制約と目的を使って説明できること。\n設計とは、構造ではなく、説明可能な判断です。\nモノリスは、問題そのものではない モノリスは、\nしばしば問題視されます。\nただし本書では、\nモノリスを悪者にはしません。\nモノリスとは、\n過去の判断が積み重なった結果です。\n問題になるのは、\nその判断が今も有効なのか分からない。\nなぜそうなったのか説明できない。\n変えようとしても、判断材料が残っていない。\nこうした状態に陥っていることです。\n問題は構造ではなく、判断の履歴が失われていることです。\n構造より先に、判断がある ここで、補足しておきたいことがあります。\n本書では、\n設計を「構造を作る行為」そのものとは捉えていません。\nしかしそれは、\n構造の重要性を否定しているわけではありません。\n構造は、\n設計の結果として残るものです。\nどの構造を選ぶかは、\n必ず何らかの判断の結果です。\n以前の著作では、\n「構造によって不具合が起きないようにする」\nという観点を中心に扱いました。\n本書は、\nその一つ手前に焦点を当てています。\nなぜその構造を選んだのか。\nどの前提で、その判断を下したのか。\n構造は成果物であり、設計そのものではありません。\n再現できなかったのは、技術ではない 「この設計を採用すればうまくいく」\n「この構成にすればスケールする」\nそうした話を真似して、\n同じことをやってみたけれど、\nうまくいかなかった経験はないでしょうか。\nその理由は、\n技術が間違っていたからではありません。\n判断の前提が、\n再現されていなかっただけです。\nチームの規模。\nメンバーの経験。\n変更頻度。\n失敗の許容度。\n将来の不確実性。\nこれらが違えば、\n同じ設計が同じ結果を生むことはありません。\n再現できなかったのは、判断の前提です。\nこの本が扱うのは「正解」ではない 本書は、\n最適なアーキテクチャ。\n失敗しない設計手法。\n万能なリファクタリング手順。\nを教える本ではありません。\n本書が扱うのは、\n判断の質です。\nどんな制約のもとで、\n何を選び、\n何を捨て、\nどこまで責任を持つと決めたのか。\nそれを、\n後から説明できる形で残すこと。\n設計とは、未来に対する判断である 設計は、\n構造を作る行為ではありません。\n設計とは、\n未来に対する判断を、今下すことです。\nそこには、\n不確実性があります。\n失敗の可能性があります。\n後悔が含まれます。\nそれでも判断する。\nそして、その判断を説明できる形で残す。\n本書が扱う設計とは、その判断そのものです。\nこの章のまとめとして、\n一つだけ述べておきます。\n設計ができないのではありません。\n多くの場合、\n判断が残っていないだけです。\n構造を見る前に、\n判断を見る。\nコードを見る前に、\n判断の前提を見る。\n次の章では、\n判断がどのように散らばり、\n失われていくのかについて、\nもう少し具体的に見ていきます。\n","permalink":"https://design.okuda-studio.com/books/002-design-starts-with-decisions/01-there-is-no-judgment-left/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E3%81%AE%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%E5%88%A4%E6%96%AD%E3%81%8C%E6%AE%8B%E3%81%A3%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%81%A0%E3%81%91\"\u003e設計ができないのではなく、判断が残っていないだけ\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E5%A3%8A%E3%82%8C%E3%82%8B%E3%81%AE%E3%81%AF%E3%81%84%E3%81%A4%E3%81%8B\"\u003e設計が壊れるのは、いつか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E8%A8%AD%E8%A8%88%E8%80%85%E3%81%AF%E3%81%86%E3%81%BE%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%84%E3%82%8B%E3%81%A8%E3%81%AF%E9%99%90%E3%82%89%E3%81%AA%E3%81%84\"\u003e良い設計者は、うまいコードを書いているとは限らない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A2%E3%83%8E%E3%83%AA%E3%82%B9%E3%81%AF%E5%95%8F%E9%A1%8C%E3%81%9D%E3%81%AE%E3%82%82%E3%81%AE%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003eモノリスは、問題そのものではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%A7%8B%E9%80%A0%E3%82%88%E3%82%8A%E5%85%88%E3%81%AB%E5%88%A4%E6%96%AD%E3%81%8C%E3%81%82%E3%82%8B\"\u003e構造より先に、判断がある\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%86%8D%E7%8F%BE%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%AF%E6%8A%80%E8%A1%93%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e再現できなかったのは、技術ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E6%9C%AC%E3%81%8C%E6%89%B1%E3%81%86%E3%81%AE%E3%81%AF%E6%AD%A3%E8%A7%A3%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003eこの本が扱うのは「正解」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%A8%E3%81%AF%E6%9C%AA%E6%9D%A5%E3%81%AB%E5%AF%BE%E3%81%99%E3%82%8B%E5%88%A4%E6%96%AD%E3%81%A7%E3%81%82%E3%82%8B\"\u003e設計とは、未来に対する判断である\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"設計ができないのではなく判断が残っていないだけ\"\u003e設計ができないのではなく、判断が残っていないだけ\u003c/h2\u003e\n\u003chr\u003e\n\u003cp\u003e多くの現場では、\u003cbr\u003e\n「設計が弱い」「設計ができていない」\u003cbr\u003e\nという言葉が使われます。\u003c/p\u003e\n\u003cp\u003eコードが複雑になっている。\u003cbr\u003e\n変更に弱い。\u003cbr\u003e\n触るのが怖い。\u003c/p\u003e\n\u003cp\u003eそうした状態をまとめて、\u003cbr\u003e\n「設計の問題」と呼ぶことは珍しくありません。\u003c/p\u003e\n\u003cp\u003eただし本書では、\u003cbr\u003e\nこの捉え方を少しだけ変えます。\u003c/p\u003e\n\u003cp\u003e多くの場合、\u003cbr\u003e\n問題は設計そのものではありません。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e判断が、残っていないのです。\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"設計が壊れるのはいつか\"\u003e設計が壊れるのは、いつか\u003c/h3\u003e\n\u003cp\u003e設計が壊れる瞬間は、\u003cbr\u003e\n突然訪れるわけではありません。\u003c/p\u003e\n\u003cp\u003eある日いきなり破綻するのではなく、\u003cbr\u003e\n小さな判断が、少しずつ積み重なった結果として現れます。\u003c/p\u003e\n\u003cp\u003eたとえば、\u003c/p\u003e\n\u003cp\u003eとりあえず今はこれでいい。\u003cbr\u003e\n前からこうなっている。\u003cbr\u003e\nあとで直せばいい。\u003cbr\u003e\nここまで影響しないと思った。\u003c/p\u003e\n\u003cp\u003eこうした判断自体が、\u003cbr\u003e\n必ずしも間違っているわけではありません。\u003c/p\u003e\n\u003cp\u003e問題は、\u003cbr\u003e\nその判断がどんな前提で行われたのかが、\u003cbr\u003e\nコードにも、ドキュメントにも、\u003cbr\u003e\n残っていないことです。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e設計が壊れるのは、判断の理由が失われたときです。\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"良い設計者はうまいコードを書いているとは限らない\"\u003e良い設計者は、うまいコードを書いているとは限らない\u003c/h3\u003e\n\u003cp\u003e設計ができる人、という言葉から、\u003cbr\u003e\n次のような人物像を思い浮かべる人も多いかもしれません。\u003c/p\u003e\n\u003cp\u003e抽象化がうまい人。\u003cbr\u003e\n新しいアーキテクチャに詳しい人。\u003cbr\u003e\nきれいなコードを書ける人。\u003c/p\u003e\n\u003cp\u003eしかし本書では、\u003cbr\u003e\nそれを設計者の条件だとは考えません。\u003c/p\u003e\n\u003cp\u003e良い設計者とは、\u003cbr\u003e\n\u003cstrong\u003e判断を説明できる人\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp\u003eなぜこの構造にしたのか。\u003cbr\u003e\nなぜ今はやらなかったのか。\u003cbr\u003e\nなぜ将来の変更を見送ったのか。\u003c/p\u003e\n\u003cp\u003eそれらを、\u003cbr\u003e\n感覚や雰囲気ではなく、\u003cbr\u003e\n後付けの理由でもなく、\u003cbr\u003e\n当時の制約と目的を使って説明できること。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e設計とは、構造ではなく、説明可能な判断です。\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"モノリスは問題そのものではない\"\u003eモノリスは、問題そのものではない\u003c/h3\u003e\n\u003cp\u003eモノリスは、\u003cbr\u003e\nしばしば問題視されます。\u003c/p\u003e\n\u003cp\u003eただし本書では、\u003cbr\u003e\nモノリスを悪者にはしません。\u003c/p\u003e\n\u003cp\u003eモノリスとは、\u003cbr\u003e\n\u003cstrong\u003e過去の判断が積み重なった結果\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp\u003e問題になるのは、\u003c/p\u003e\n\u003cp\u003eその判断が今も有効なのか分からない。\u003cbr\u003e\nなぜそうなったのか説明できない。\u003cbr\u003e\n変えようとしても、判断材料が残っていない。\u003c/p\u003e\n\u003cp\u003eこうした状態に陥っていることです。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e問題は構造ではなく、判断の履歴が失われていることです。\u003c/strong\u003e\u003c/p\u003e","title":"第1章：設計ができないのではなく、判断が残っていないだけ"},{"content":" 設計の話が、なぜ噛み合わないのか 「良い構造」を真似ても、うまくいかない理由 設計とは、何をしている行為なのか 判断は、コードのどこに現れるのか 判断が「にじみ出る」と何が起きるか 「閉じ込める」という発想 この本で扱わないこと まとめ 設計の話が、なぜ噛み合わないのか 設計の話をしているはずなのに、会話がどこか噛み合わない。 そんな経験はないだろうか。\n「このクラス、責務が重くないですか？」 「ここ、MVVM 的におかしくない？」 「もう少し共通化できそうですよね」\n言っていることは、どれもそれなりに正しい。 しかし次の瞬間、場の空気は微妙になる。\nなぜそれが“悪い”のか、うまく説明できない 相手もなんとなく納得していない 結局「今回はこのままで…」となる 設計の議論が難しいのは、知識が足りないからではない。 多くの場合、話題にしているレイヤがズレているだけだ。\n私たちは「構造」について話しているつもりで、 本当はそこに含まれている 判断 について語れていない。\n「良い構造」を真似ても、うまくいかない理由 世の中には、良いとされる設計がたくさんある。 レイヤードアーキテクチャ、MVVM、Clean Architecture、DDD。\nそれらを学び、 「正しい形」に沿ってコードを書いたはずなのに、 しばらくするとシステムはまた苦しくなる。\n変更のたびに広範囲を確認する必要がある 触ってはいけない雰囲気のコードが増える なぜこの構造なのか、誰も説明できない これは「構造の選択を間違えた」から起きているのではない。\n問題はもっと単純で、 その構造が前提としている判断と、現実の判断が一致していなかっただけだ。\n設計はレシピではない。 同じ構造でも、 どんな判断を閉じ込めるために使うかによって、結果はまったく変わる。\n設計とは、何をしている行為なのか ここで、本書における設計の定義をはっきりさせておきたい。\n設計とは、 不確実な判断を、どこに、どの強さで閉じ込めるかを決める行為である。\n判断とは、次のようなものだ。\n将来、変わるかもしれない決定 特定の文脈に強く依存した選択 あとから「間違っていた」と分かる可能性があるもの 設計が難しいのは、 これらの判断が 必ず間違える前提 で存在しているからだ。\n設計の仕事は、 判断をなくすことではない。\n判断が壊れたときに、 被害がどこまで広がるかを制御することにある。\n判断は、コードのどこに現れるのか 「判断」と聞くと、 if 文や分岐ロジックを思い浮かべるかもしれない。\nしかし実際には、 判断はコードのあらゆる場所に現れる。\nクラスを分けたという事実 ファイルを分けたという事実 名前を付けたという事実 共通化した、しなかったという決定 たとえば、2 つのクラスを別々にした瞬間、 あなたはこう判断している。\n「この 2 つは、将来別々に変わる可能性がある」\n構造とは、 判断を固定化した結果の集合体 にすぎない。\n判断が「にじみ出る」と何が起きるか 判断が一箇所に閉じ込められていれば、 修正は比較的容易だ。\nしかし判断がにじみ出ると、状況は一変する。\n同じ前提が複数箇所に散らばる どこを直せばよいか分からなくなる 修正のたびに全体確認が必要になる 設計が壊れるのは、 新しい判断をしたときではない。\n古い判断が、どこにあるか分からなくなったとき だ。\n「閉じ込める」という発想 本書では、 判断を扱う方法として「閉じ込める」という言葉を使う。\n閉じ込めるとは、 隠すことでも、押し込めることでもない。\n境界を作ること 触っていい場所を決めること 触ってはいけない場所を決めること つまり、 判断に責任を持つ場所を明確にする ということだ。\nもちろん、閉じ込めすぎれば身動きが取れなくなる。 このバランスについては、後の章で詳しく扱う。\nこの本で扱わないこと 本書は、次のようなことを目的としていない。\n最新フレームワークの解説 正解のアーキテクチャ提示 テンプレート設計の紹介 本書が扱うのは、 設計の 答え ではなく、 判断の 考え方 だ。\nまとめ 設計は構造の話ではない 設計は判断を扱う技術である 問題は判断が存在することではない 問題は判断が制御されていないことだ 次章では、 なぜ判断がシステムを壊すのか を、 もう一段深く掘り下げていく。\n","permalink":"https://design.okuda-studio.com/books/003-design-that-locks-in-judgment/01-/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AE%E8%A9%B1%E3%81%8C%E3%81%AA%E3%81%9C%E5%99%9B%E3%81%BF%E5%90%88%E3%82%8F%E3%81%AA%E3%81%84%E3%81%AE%E3%81%8B\"\u003e設計の話が、なぜ噛み合わないのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E6%A7%8B%E9%80%A0%E3%82%92%E7%9C%9F%E4%BC%BC%E3%81%A6%E3%82%82%E3%81%86%E3%81%BE%E3%81%8F%E3%81%84%E3%81%8B%E3%81%AA%E3%81%84%E7%90%86%E7%94%B1\"\u003e「良い構造」を真似ても、うまくいかない理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%A8%E3%81%AF%E4%BD%95%E3%82%92%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E8%A1%8C%E7%82%BA%E3%81%AA%E3%81%AE%E3%81%8B\"\u003e設計とは、何をしている行為なのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AF%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E3%81%A9%E3%81%93%E3%81%AB%E7%8F%BE%E3%82%8C%E3%82%8B%E3%81%AE%E3%81%8B\"\u003e判断は、コードのどこに現れるのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%8C%E3%81%AB%E3%81%98%E3%81%BF%E5%87%BA%E3%82%8B%E3%81%A8%E4%BD%95%E3%81%8C%E8%B5%B7%E3%81%8D%E3%82%8B%E3%81%8B\"\u003e判断が「にじみ出る」と何が起きるか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%96%89%E3%81%98%E8%BE%BC%E3%82%81%E3%82%8B%E3%81%A8%E3%81%84%E3%81%86%E7%99%BA%E6%83%B3\"\u003e「閉じ込める」という発想\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E6%9C%AC%E3%81%A7%E6%89%B1%E3%82%8F%E3%81%AA%E3%81%84%E3%81%93%E3%81%A8\"\u003eこの本で扱わないこと\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"設計の話がなぜ噛み合わないのか\"\u003e設計の話が、なぜ噛み合わないのか\u003c/h3\u003e\n\u003cp\u003e設計の話をしているはずなのに、会話がどこか噛み合わない。\nそんな経験はないだろうか。\u003c/p\u003e\n\u003cp\u003e「このクラス、責務が重くないですか？」\n「ここ、MVVM 的におかしくない？」\n「もう少し共通化できそうですよね」\u003c/p\u003e\n\u003cp\u003e言っていることは、どれもそれなりに正しい。\nしかし次の瞬間、場の空気は微妙になる。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eなぜそれが“悪い”のか、うまく説明できない\u003c/li\u003e\n\u003cli\u003e相手もなんとなく納得していない\u003c/li\u003e\n\u003cli\u003e結局「今回はこのままで…」となる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e設計の議論が難しいのは、知識が足りないからではない。\n多くの場合、\u003cstrong\u003e話題にしているレイヤがズレている\u003c/strong\u003eだけだ。\u003c/p\u003e\n\u003cp\u003e私たちは「構造」について話しているつもりで、\n本当はそこに含まれている \u003cstrong\u003e判断\u003c/strong\u003e について語れていない。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"良い構造を真似てもうまくいかない理由\"\u003e「良い構造」を真似ても、うまくいかない理由\u003c/h3\u003e\n\u003cp\u003e世の中には、良いとされる設計がたくさんある。\nレイヤードアーキテクチャ、MVVM、Clean Architecture、DDD。\u003c/p\u003e\n\u003cp\u003eそれらを学び、\n「正しい形」に沿ってコードを書いたはずなのに、\nしばらくするとシステムはまた苦しくなる。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e変更のたびに広範囲を確認する必要がある\u003c/li\u003e\n\u003cli\u003e触ってはいけない雰囲気のコードが増える\u003c/li\u003e\n\u003cli\u003eなぜこの構造なのか、誰も説明できない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれは「構造の選択を間違えた」から起きているのではない。\u003c/p\u003e\n\u003cp\u003e問題はもっと単純で、\n\u003cstrong\u003eその構造が前提としている判断と、現実の判断が一致していなかった\u003c/strong\u003eだけだ。\u003c/p\u003e\n\u003cp\u003e設計はレシピではない。\n同じ構造でも、\nどんな判断を閉じ込めるために使うかによって、結果はまったく変わる。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"設計とは何をしている行為なのか\"\u003e設計とは、何をしている行為なのか\u003c/h3\u003e\n\u003cp\u003eここで、本書における設計の定義をはっきりさせておきたい。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e設計とは、\n\u003cstrong\u003e不確実な判断を、どこに、どの強さで閉じ込めるかを決める行為である\u003c/strong\u003e。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e判断とは、次のようなものだ。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e将来、変わるかもしれない決定\u003c/li\u003e\n\u003cli\u003e特定の文脈に強く依存した選択\u003c/li\u003e\n\u003cli\u003eあとから「間違っていた」と分かる可能性があるもの\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e設計が難しいのは、\nこれらの判断が \u003cstrong\u003e必ず間違える前提\u003c/strong\u003e で存在しているからだ。\u003c/p\u003e\n\u003cp\u003e設計の仕事は、\n判断をなくすことではない。\u003c/p\u003e\n\u003cp\u003e判断が壊れたときに、\n被害がどこまで広がるかを制御することにある。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断はコードのどこに現れるのか\"\u003e判断は、コードのどこに現れるのか\u003c/h3\u003e\n\u003cp\u003e「判断」と聞くと、\nif 文や分岐ロジックを思い浮かべるかもしれない。\u003c/p\u003e\n\u003cp\u003eしかし実際には、\n判断はコードのあらゆる場所に現れる。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eクラスを分けたという事実\u003c/li\u003e\n\u003cli\u003eファイルを分けたという事実\u003c/li\u003e\n\u003cli\u003e名前を付けたという事実\u003c/li\u003e\n\u003cli\u003e共通化した、しなかったという決定\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eたとえば、2 つのクラスを別々にした瞬間、\nあなたはこう判断している。\u003c/p\u003e","title":"第1章：設計とは「判断」を扱う行為である"},{"content":" なぜ「速さ」は評価されやすいのか 「まず動くものを作る」は間違いなのか 速く書かれたコードが抱える問題 速さが生む「負債」は、あとからやってくる 設計は「速さ」と対立するものではない この章のまとめ 多くの現場では、 「速く書けるエンジニア」が高く評価されます。\n短期間で動くものを作れる。 仕様変更にもすぐに対応できる。 多少バグが残っていても、とりあえず形にできる。\nこうした姿は、 一見するととても頼もしく見えます。\n実際、 プロジェクトの初期段階や、 期限が迫った場面では、 速さが価値を持つこともあります。\nただし本書では、 速さが絶対的な価値であるとは考えていません。\nなぜ「速さ」は評価されやすいのか 速さが評価される理由は、 とてもシンプルです。\n速さは、目に見えるからです。\n何日で終わったか 何機能実装できたか どれだけ早くリリースできたか これらは数値として観測できます。\n一方で、 設計の良し悪しは、 すぐには見えません。\n設計の差が表に出るのは、\n仕様変更が入ったとき メンバーが入れ替わったとき 数か月、数年が経過したとき です。つまり、\n速さは「今すぐ評価できる価値」 設計は「後から効いてくる価値」 だと言えます。\n「まず動くものを作る」は間違いなのか ここで、一つはっきりさせておきたいことがあります。\n本書は、 「まず動くものを作る」 こと自体を 否定しているわけではありません。\n要件が曖昧な段階で、 いきなり完成形の設計を書くことは、 シニアエンジニアであっても難しいと思います。\nまず動くものを作ることで、\n他の実装と比較できる 問題の輪郭が見える 本当に難しい部分が浮かび上がる ということは、確かにあります。\nこの段階のコードは、 思考のラフスケッチ です。\n問題は、そのラフスケッチを 完成した設計 だと誤認してしまうことにあります。\n速く書かれたコードが抱える問題 速く書かれたコードは、 多くの場合、次のような特徴を持ちます。\n一ヶ所修正すると、影響が爆発的に発生する 一つの部品が複数の責任を負っている 影響確認が人の注意力に委ねられている 変更時に、どこを直せばよいかわからない これらは、 「書いた人が賢いから私にはわからない」 「書いた人がわかるなら私にもわかるはず」 という問題ではありません。\n暗黙の前提が、コードの外にある可能性があります。\n結果として、 その人がいなくなると壊れるコード が生まれます。\n速さが生む「負債」は、あとからやってくる 速さを優先して書かれたコードは、 最初は軽く、扱いやすく見えます。\nしかし時間が経つにつれて、\n小さな修正に時間がかかる 触ってはいけない場所が増える 誰も全体を把握できなくなる といった状態に変わっていきます。\nこれは、 過去に支払わなかった設計のコストを、 後からまとめて支払っている状態です。\n速さは、 時間を節約しているように見えて、 未来の時間を前借りしている ことがあります。\n設計は「速さ」と対立するものではない 設計は、 速さの対極にあるものではありません。\n良い設計がされたコードは、\n変更の影響範囲が小さく 安心して触ることができ 結果として作業が速くなります ただしそれは、 最初の一瞬の速さ ではなく、 長く続く速さ です。\nこの違いは、 短期的な評価指標では測れません。\nだからこそ、 設計の価値は見落とされやすいのだと思います。\nこの章のまとめ 速さには、たしかに価値があります。\nしかしその速さが、\n構造によって支えられているのか 人の頑張りによって成り立っているのか を見極める必要があります。\n本書が扱う設計は、 後者を前者に変えるためのものです。\n次の章では、 速さの裏側で起きている 「判断の散在」 について、 もう少し具体的に見ていきます。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/01-why-does-speed-seem-valuable/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E9%80%9F%E3%81%95%E3%81%AF%E8%A9%95%E4%BE%A1%E3%81%95%E3%82%8C%E3%82%84%E3%81%99%E3%81%84%E3%81%AE%E3%81%8B\"\u003eなぜ「速さ」は評価されやすいのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%9A%E5%8B%95%E3%81%8F%E3%82%82%E3%81%AE%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%AF%E9%96%93%E9%81%95%E3%81%84%E3%81%AA%E3%81%AE%E3%81%8B\"\u003e「まず動くものを作る」は間違いなのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%80%9F%E3%81%8F%E6%9B%B8%E3%81%8B%E3%82%8C%E3%81%9F%E3%82%B3%E3%83%BC%E3%83%89%E3%81%8C%E6%8A%B1%E3%81%88%E3%82%8B%E5%95%8F%E9%A1%8C\"\u003e速く書かれたコードが抱える問題\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%80%9F%E3%81%95%E3%81%8C%E7%94%9F%E3%82%80%E8%B2%A0%E5%82%B5%E3%81%AF%E3%81%82%E3%81%A8%E3%81%8B%E3%82%89%E3%82%84%E3%81%A3%E3%81%A6%E3%81%8F%E3%82%8B\"\u003e速さが生む「負債」は、あとからやってくる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AF%E9%80%9F%E3%81%95%E3%81%A8%E5%AF%BE%E7%AB%8B%E3%81%99%E3%82%8B%E3%82%82%E3%81%AE%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e設計は「速さ」と対立するものではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e多くの現場では、\n「速く書けるエンジニア」が高く評価されます。\u003c/p\u003e\n\u003cp\u003e短期間で動くものを作れる。\n仕様変更にもすぐに対応できる。\n多少バグが残っていても、とりあえず形にできる。\u003c/p\u003e\n\u003cp\u003eこうした姿は、\n一見するととても頼もしく見えます。\u003c/p\u003e\n\u003cp\u003e実際、\nプロジェクトの初期段階や、\n期限が迫った場面では、\n速さが価値を持つこともあります。\u003c/p\u003e\n\u003cp\u003eただし本書では、\n\u003cstrong\u003e速さが絶対的な価値であるとは考えていません。\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"なぜ速さは評価されやすいのか\"\u003eなぜ「速さ」は評価されやすいのか\u003c/h2\u003e\n\u003cp\u003e速さが評価される理由は、\nとてもシンプルです。\u003c/p\u003e\n\u003cp\u003e速さは、目に見えるからです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e何日で終わったか\u003c/li\u003e\n\u003cli\u003e何機能実装できたか\u003c/li\u003e\n\u003cli\u003eどれだけ早くリリースできたか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは数値として観測できます。\u003c/p\u003e\n\u003cp\u003e一方で、\n設計の良し悪しは、\nすぐには見えません。\u003c/p\u003e\n\u003cp\u003e設計の差が表に出るのは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e仕様変更が入ったとき\u003c/li\u003e\n\u003cli\u003eメンバーが入れ替わったとき\u003c/li\u003e\n\u003cli\u003e数か月、数年が経過したとき\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eです。つまり、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e速さは「今すぐ評価できる価値」\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e設計は「後から効いてくる価値」\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eだと言えます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"まず動くものを作るは間違いなのか\"\u003e「まず動くものを作る」は間違いなのか\u003c/h2\u003e\n\u003cp\u003eここで、一つはっきりさせておきたいことがあります。\u003c/p\u003e\n\u003cp\u003e本書は、\n\u003cstrong\u003e「まず動くものを作る」\u003c/strong\u003e こと自体を\n否定しているわけではありません。\u003c/p\u003e\n\u003cp\u003e要件が曖昧な段階で、\nいきなり完成形の設計を書くことは、\nシニアエンジニアであっても難しいと思います。\u003c/p\u003e\n\u003cp\u003eまず動くものを作ることで、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e他の実装と比較できる\u003c/li\u003e\n\u003cli\u003e問題の輪郭が見える\u003c/li\u003e\n\u003cli\u003e本当に難しい部分が浮かび上がる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eということは、確かにあります。\u003c/p\u003e\n\u003cp\u003eこの段階のコードは、 \u003cstrong\u003e思考のラフスケッチ\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003e問題は、そのラフスケッチを\n\u003cstrong\u003e完成した設計\u003c/strong\u003e だと誤認してしまうことにあります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"速く書かれたコードが抱える問題\"\u003e速く書かれたコードが抱える問題\u003c/h2\u003e\n\u003cp\u003e速く書かれたコードは、\n多くの場合、次のような特徴を持ちます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e一ヶ所修正すると、影響が爆発的に発生する\u003c/li\u003e\n\u003cli\u003e一つの部品が複数の責任を負っている\u003c/li\u003e\n\u003cli\u003e影響確認が人の注意力に委ねられている\u003c/li\u003e\n\u003cli\u003e変更時に、どこを直せばよいかわからない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは、\n「書いた人が賢いから私にはわからない」\n「書いた人がわかるなら私にもわかるはず」\nという問題ではありません。\u003c/p\u003e\n\u003cp\u003e暗黙の前提が、コードの外にある可能性があります。\u003c/p\u003e","title":"第1章：速さはなぜ価値に見えるのか"},{"content":" 判断は、どこに散らばっていくのか 判断は、いつも一か所に書かれるわけではない 条件分岐は、判断の化石である コメントが消えたとき、判断も消える 設計ドキュメントが読まれなくなる理由 判断は、人の頭の中に集約される 属人化とは、判断が共有されていない状態である 判断は、なぜ散らばるのか この章のまとめ 判断は、どこに散らばっていくのか 設計が壊れる原因は、\n判断が間違っていたからではありません。\n多くの場合、\n判断が散らばり、追えなくなったことが原因です。\nこの章では、\n判断がどのようにコードベースの中に散在し、\nやがて誰にも把握できなくなっていくのかを見ていきます。\n判断は、いつも一か所に書かれるわけではない 一つの機能を実装するとき、\n判断は一回で終わるわけではありません。\n画面の責務をどう分けるか。\nどこでデータを加工するか。\n例外はどこで握りつぶすか。\n将来増えそうな仕様を考慮するか。\nこれらは、\n実装のあちこちで、少しずつ行われます。\nしかもその多くは、\n「判断した」という自覚すらないまま下されています。\n判断は、気づかないうちに行われます。\n条件分岐は、判断の化石である コードの中で、\nもっとも分かりやすい判断の痕跡は、条件分岐です。\nif。\nwhen。\n早期 return。\nそれらはすべて、\n「どちらを選ぶか」という判断の結果です。\nなぜこの条件が存在するのか。\nなぜこの分岐は統合されていないのか。\nなぜここで例外にしているのか。\n理由が分かるうちは、\nその判断は生きています。\nしかし理由が分からなくなった瞬間、\nそれは 判断の化石 になります。\nコメントが消えたとき、判断も消える 判断を残す方法として、\nコメントを書く人も多いでしょう。\nしかしコメントは、\nとても壊れやすい存在です。\nリファクタリングで消される。\n意味が古くなる。\n「コードを見れば分かる」と判断されて削除される。\nそしてコメントが消えると、\n判断の前提も一緒に消えます。\n残るのは、\nなぜ存在するのか分からない構造です。\n設計ドキュメントが読まれなくなる理由 「判断はドキュメントに書いてある」\nというケースもあります。\nしかし多くの現場で、\n設計ドキュメントは次第に読まれなくなります。\nなぜでしょうか。\n理由は単純です。\nコードとズレるからです。\n仕様変更。\n例外対応。\n場当たり的な修正。\nそれらが積み重なると、\nドキュメントは「過去の判断」を書いたものになります。\nそして人は、\n今動いているコードを信じるようになります。\n結果として、\n判断はどこにも信頼できる形で残らなくなります。\n判断は、人の頭の中に集約される コードにも。\nコメントにも。\nドキュメントにも。\n判断が残っていないとき、\n最後に残る場所があります。\nそれは、\n特定の人の頭の中です。\n「それは〇〇さんに聞かないと分からない」\n「触る前に〇〇さんに確認して」\nこうした言葉が出始めたとき、\n判断は個人に閉じています。\nその人がいる間は、\nシステムは動き続けます。\nしかしその人がいなくなった瞬間、\n判断は失われます。\n属人化とは、判断が共有されていない状態である 属人化という言葉は、\nしばしばスキルの問題として語られます。\nしかし本質は、\nスキルではありません。\n判断が共有されていないことです。\n同じコードを書けなくてもいい。\n同じ発想ができなくてもいい。\nなぜそうしたのかを、\n追体験できれば十分です。\n判断が共有されていれば、\n設計は引き継げます。\n判断は、なぜ散らばるのか 判断が散らばる理由は、\n一つではありません。\n速さを優先した。\nとりあえず動かした。\n全体を見る余裕がなかった。\nチームが大きくなった。\nどれも、\n現場ではよくあることです。\n重要なのは、\nそれ自体を責めることではありません。\n判断は、意識しないと必ず散らばる。\nこの前提を持つことです。\nこの章のまとめ 設計が壊れるのは、\n判断が間違っていたからではありません。\n判断が、\nコードの断片に散らばり。\n理由を失い。\n追えなくなった結果です。\n次の章では、\nこの散らばった判断を、\nどのように一つの軸で扱うのかについて、\n話を進めていきます。\n","permalink":"https://design.okuda-studio.com/books/002-design-starts-with-decisions/02-where-does-judgment-fall/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AF%E3%81%A9%E3%81%93%E3%81%AB%E6%95%A3%E3%82%89%E3%81%B0%E3%81%A3%E3%81%A6%E3%81%84%E3%81%8F%E3%81%AE%E3%81%8B\"\u003e判断は、どこに散らばっていくのか\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AF%E3%81%84%E3%81%A4%E3%82%82%E4%B8%80%E3%81%8B%E6%89%80%E3%81%AB%E6%9B%B8%E3%81%8B%E3%82%8C%E3%82%8B%E3%82%8F%E3%81%91%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e判断は、いつも一か所に書かれるわけではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9D%A1%E4%BB%B6%E5%88%86%E5%B2%90%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%AE%E5%8C%96%E7%9F%B3%E3%81%A7%E3%81%82%E3%82%8B\"\u003e条件分岐は、判断の化石である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88%E3%81%8C%E6%B6%88%E3%81%88%E3%81%9F%E3%81%A8%E3%81%8D%E5%88%A4%E6%96%AD%E3%82%82%E6%B6%88%E3%81%88%E3%82%8B\"\u003eコメントが消えたとき、判断も消える\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88%E3%81%8C%E8%AA%AD%E3%81%BE%E3%82%8C%E3%81%AA%E3%81%8F%E3%81%AA%E3%82%8B%E7%90%86%E7%94%B1\"\u003e設計ドキュメントが読まれなくなる理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AF%E4%BA%BA%E3%81%AE%E9%A0%AD%E3%81%AE%E4%B8%AD%E3%81%AB%E9%9B%86%E7%B4%84%E3%81%95%E3%82%8C%E3%82%8B\"\u003e判断は、人の頭の中に集約される\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%B1%9E%E4%BA%BA%E5%8C%96%E3%81%A8%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%8C%E5%85%B1%E6%9C%89%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E7%8A%B6%E6%85%8B%E3%81%A7%E3%81%82%E3%82%8B\"\u003e属人化とは、判断が共有されていない状態である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AF%E3%81%AA%E3%81%9C%E6%95%A3%E3%82%89%E3%81%B0%E3%82%8B%E3%81%AE%E3%81%8B\"\u003e判断は、なぜ散らばるのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"判断はどこに散らばっていくのか\"\u003e判断は、どこに散らばっていくのか\u003c/h2\u003e\n\u003chr\u003e\n\u003cp\u003e設計が壊れる原因は、\u003cbr\u003e\n判断が間違っていたからではありません。\u003c/p\u003e\n\u003cp\u003e多くの場合、\u003cbr\u003e\n\u003cstrong\u003e判断が散らばり、追えなくなったこと\u003c/strong\u003eが原因です。\u003c/p\u003e\n\u003cp\u003eこの章では、\u003cbr\u003e\n判断がどのようにコードベースの中に散在し、\u003cbr\u003e\nやがて誰にも把握できなくなっていくのかを見ていきます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断はいつも一か所に書かれるわけではない\"\u003e判断は、いつも一か所に書かれるわけではない\u003c/h3\u003e\n\u003cp\u003e一つの機能を実装するとき、\u003cbr\u003e\n判断は一回で終わるわけではありません。\u003c/p\u003e\n\u003cp\u003e画面の責務をどう分けるか。\u003cbr\u003e\nどこでデータを加工するか。\u003cbr\u003e\n例外はどこで握りつぶすか。\u003cbr\u003e\n将来増えそうな仕様を考慮するか。\u003c/p\u003e\n\u003cp\u003eこれらは、\u003cbr\u003e\n実装のあちこちで、少しずつ行われます。\u003c/p\u003e\n\u003cp\u003eしかもその多くは、\u003cbr\u003e\n「判断した」という自覚すらないまま下されています。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e判断は、気づかないうちに行われます。\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"条件分岐は判断の化石である\"\u003e条件分岐は、判断の化石である\u003c/h3\u003e\n\u003cp\u003eコードの中で、\u003cbr\u003e\nもっとも分かりやすい判断の痕跡は、条件分岐です。\u003c/p\u003e\n\u003cp\u003eif。\u003cbr\u003e\nwhen。\u003cbr\u003e\n早期 return。\u003c/p\u003e\n\u003cp\u003eそれらはすべて、\u003cbr\u003e\n「どちらを選ぶか」という判断の結果です。\u003c/p\u003e\n\u003cp\u003eなぜこの条件が存在するのか。\u003cbr\u003e\nなぜこの分岐は統合されていないのか。\u003cbr\u003e\nなぜここで例外にしているのか。\u003c/p\u003e\n\u003cp\u003e理由が分かるうちは、\u003cbr\u003e\nその判断は生きています。\u003c/p\u003e\n\u003cp\u003eしかし理由が分からなくなった瞬間、\u003cbr\u003e\nそれは \u003cstrong\u003e判断の化石\u003c/strong\u003e になります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"コメントが消えたとき判断も消える\"\u003eコメントが消えたとき、判断も消える\u003c/h3\u003e\n\u003cp\u003e判断を残す方法として、\u003cbr\u003e\nコメントを書く人も多いでしょう。\u003c/p\u003e\n\u003cp\u003eしかしコメントは、\u003cbr\u003e\nとても壊れやすい存在です。\u003c/p\u003e\n\u003cp\u003eリファクタリングで消される。\u003cbr\u003e\n意味が古くなる。\u003cbr\u003e\n「コードを見れば分かる」と判断されて削除される。\u003c/p\u003e\n\u003cp\u003eそしてコメントが消えると、\u003cbr\u003e\n判断の前提も一緒に消えます。\u003c/p\u003e\n\u003cp\u003e残るのは、\u003cbr\u003e\n\u003cstrong\u003eなぜ存在するのか分からない構造\u003c/strong\u003eです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"設計ドキュメントが読まれなくなる理由\"\u003e設計ドキュメントが読まれなくなる理由\u003c/h3\u003e\n\u003cp\u003e「判断はドキュメントに書いてある」\u003cbr\u003e\nというケースもあります。\u003c/p\u003e\n\u003cp\u003eしかし多くの現場で、\u003cbr\u003e\n設計ドキュメントは次第に読まれなくなります。\u003c/p\u003e\n\u003cp\u003eなぜでしょうか。\u003c/p\u003e\n\u003cp\u003e理由は単純です。\u003cbr\u003e\n\u003cstrong\u003eコードとズレるから\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp\u003e仕様変更。\u003cbr\u003e\n例外対応。\u003cbr\u003e\n場当たり的な修正。\u003c/p\u003e","title":"第2章：判断は、どこに散らばっていくのか"},{"content":" 判断は「悪者」ではない 判断は、必ず寿命を持つ 判断が「広がる」ときに起きること 「変更が怖い」という感覚の正体 判断は、静かに増殖する 再利用が判断を壊す瞬間 判断が壊れると、構造も壊れる まとめ 第1章では、設計とは「判断」を扱う行為である、という前提を置いた。\nでは次に浮かぶ疑問は、こうだろう。\nなぜ判断は、システムを壊すのか。\n判断は必要なものだ。 それなのに、なぜ判断が増えるほど、 コードは触りづらくなっていくのか。\nこの章では、 判断そのものが悪いわけではない という事実から出発し、 それでもシステムが壊れていく理由を丁寧に掘り下げていく。\n判断は「悪者」ではない まず、はっきりさせておきたい。\n判断は、設計において避けるべきものではない。\n「判断が多いコードは悪い」 「ロジックは少ないほうがよい」\nこうした言葉は、しばしば聞かれるが、 それは半分しか正しくない。\n判断がなければ、ソフトウェアは振る舞えない。 要件を満たすこともできない。\n問題は、 判断が存在することではなく、 判断が制御されていないこと だ。\n判断は、必ず寿命を持つ すべての判断には、寿命がある。\n今は正しいが、将来は分からない この前提が崩れたら成立しない 別の文脈では通用しない それでも私たちは、 あたかもその判断が永遠に正しいかのように、 コードに埋め込んでしまう。\n設計が壊れ始めるのは、 判断の寿命が尽きた瞬間だ。\nしかし実際には、 その瞬間がはっきりと分かることは少ない。\n少しずつ前提がズレ、 少しずつ例外が増え、 気づいたときには全体が歪んでいる。\n判断が「広がる」ときに起きること 判断が一箇所に閉じ込められていれば、 その寿命が尽きても、修正は局所的で済む。\nしかし判断が広がっていると、 話はまったく変わる。\n同じ判断が、複数の場所に存在する 微妙に違う形でコピーされている どれが本体か分からない この状態では、 一つの判断を変えることが、 システム全体を揺るがす行為になる。\n結果として、 誰も判断を変えられなくなる。\n「変更が怖い」という感覚の正体 現場でよく聞く言葉がある。\n「この辺、変更すると影響範囲が分からなくて…」\nこれは、技術力不足の告白ではない。 設計上の問題だ。\n変更が怖いとは、 判断がどこにあるか分からない という状態を指している。\n触る前に全体を読む必要がある テストがあっても安心できない レビューでも確信が持てない こうしてコードは、 徐々に「触れない領域」へと変わっていく。\n判断は、静かに増殖する 判断が怖いのは、 増えていることに気づきにくい点にある。\n最初は、 「このケースだけ特別に」 という一行の if かもしれない。\nしかしその判断が閉じ込められていなければ、 同じ前提が別の場所でも必要になる。\nやがて、 似たような分岐が点在し、 少しずつズレたロジックが生まれる。\n誰も全体像を把握できなくなったとき、 システムはすでに壊れ始めている。\n再利用が判断を壊す瞬間 再利用は、善であるかのように語られることが多い。\nしかし再利用は、 判断を壊す強力なトリガーにもなり得る。\n本来、特定の文脈でのみ成立していた判断が、 別の文脈に持ち込まれる。\nその結果、\n例外対応が増える フラグやオプションが増える 呼び出し側の責務が曖昧になる 再利用が問題なのではない。\n判断のスコープを超えて使われること が問題なのだ。\n判断が壊れると、構造も壊れる 判断が歪み始めると、 それを支えている構造も耐えきれなくなる。\n責務が曖昧になる 境界が曖昧になる クラス名が実態を表さなくなる こうなると、 構造を直そうとしても、うまくいかない。\nなぜなら、 壊れているのは構造ではなく、 その中に閉じ込められているはずだった判断 だからだ。\nまとめ 判断そのものは悪ではない 判断には必ず寿命がある 判断が広がると、変更は恐怖になる 再利用は、判断を壊す引き金になり得る 構造が壊れる前に、判断はすでに壊れている 次章では、 こうした問題に対して、 判断をどのように閉じ込めるのか を、 具体的な技術として扱っていく。\n","permalink":"https://design.okuda-studio.com/books/003-design-that-locks-in-judgment/02-/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AF%E6%82%AA%E8%80%85%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e判断は「悪者」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AF%E5%BF%85%E3%81%9A%E5%AF%BF%E5%91%BD%E3%82%92%E6%8C%81%E3%81%A4\"\u003e判断は、必ず寿命を持つ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%8C%E5%BA%83%E3%81%8C%E3%82%8B%E3%81%A8%E3%81%8D%E3%81%AB%E8%B5%B7%E3%81%8D%E3%82%8B%E3%81%93%E3%81%A8\"\u003e判断が「広がる」ときに起きること\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A4%89%E6%9B%B4%E3%81%8C%E6%80%96%E3%81%84%E3%81%A8%E3%81%84%E3%81%86%E6%84%9F%E8%A6%9A%E3%81%AE%E6%AD%A3%E4%BD%93\"\u003e「変更が怖い」という感覚の正体\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AF%E9%9D%99%E3%81%8B%E3%81%AB%E5%A2%97%E6%AE%96%E3%81%99%E3%82%8B\"\u003e判断は、静かに増殖する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%86%8D%E5%88%A9%E7%94%A8%E3%81%8C%E5%88%A4%E6%96%AD%E3%82%92%E5%A3%8A%E3%81%99%E7%9E%AC%E9%96%93\"\u003e再利用が判断を壊す瞬間\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%8C%E5%A3%8A%E3%82%8C%E3%82%8B%E3%81%A8%E6%A7%8B%E9%80%A0%E3%82%82%E5%A3%8A%E3%82%8C%E3%82%8B\"\u003e判断が壊れると、構造も壊れる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003e第1章では、設計とは「判断」を扱う行為である、という前提を置いた。\u003c/p\u003e\n\u003cp\u003eでは次に浮かぶ疑問は、こうだろう。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eなぜ判断は、システムを壊すのか。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e判断は必要なものだ。\nそれなのに、なぜ判断が増えるほど、\nコードは触りづらくなっていくのか。\u003c/p\u003e\n\u003cp\u003eこの章では、\n\u003cstrong\u003e判断そのものが悪いわけではない\u003c/strong\u003e という事実から出発し、\nそれでもシステムが壊れていく理由を丁寧に掘り下げていく。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断は悪者ではない\"\u003e判断は「悪者」ではない\u003c/h3\u003e\n\u003cp\u003eまず、はっきりさせておきたい。\u003c/p\u003e\n\u003cp\u003e判断は、設計において避けるべきものではない。\u003c/p\u003e\n\u003cp\u003e「判断が多いコードは悪い」\n「ロジックは少ないほうがよい」\u003c/p\u003e\n\u003cp\u003eこうした言葉は、しばしば聞かれるが、\nそれは半分しか正しくない。\u003c/p\u003e\n\u003cp\u003e判断がなければ、ソフトウェアは振る舞えない。\n要件を満たすこともできない。\u003c/p\u003e\n\u003cp\u003e問題は、\n判断が存在することではなく、\n\u003cstrong\u003e判断が制御されていないこと\u003c/strong\u003e だ。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断は必ず寿命を持つ\"\u003e判断は、必ず寿命を持つ\u003c/h3\u003e\n\u003cp\u003eすべての判断には、寿命がある。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e今は正しいが、将来は分からない\u003c/li\u003e\n\u003cli\u003eこの前提が崩れたら成立しない\u003c/li\u003e\n\u003cli\u003e別の文脈では通用しない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eそれでも私たちは、\nあたかもその判断が永遠に正しいかのように、\nコードに埋め込んでしまう。\u003c/p\u003e\n\u003cp\u003e設計が壊れ始めるのは、\n判断の寿命が尽きた瞬間だ。\u003c/p\u003e\n\u003cp\u003eしかし実際には、\nその瞬間がはっきりと分かることは少ない。\u003c/p\u003e\n\u003cp\u003e少しずつ前提がズレ、\n少しずつ例外が増え、\n気づいたときには全体が歪んでいる。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断が広がるときに起きること\"\u003e判断が「広がる」ときに起きること\u003c/h3\u003e\n\u003cp\u003e判断が一箇所に閉じ込められていれば、\nその寿命が尽きても、修正は局所的で済む。\u003c/p\u003e\n\u003cp\u003eしかし判断が広がっていると、\n話はまったく変わる。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e同じ判断が、複数の場所に存在する\u003c/li\u003e\n\u003cli\u003e微妙に違う形でコピーされている\u003c/li\u003e\n\u003cli\u003eどれが本体か分からない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの状態では、\n一つの判断を変えることが、\nシステム全体を揺るがす行為になる。\u003c/p\u003e\n\u003cp\u003e結果として、\n誰も判断を変えられなくなる。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"変更が怖いという感覚の正体\"\u003e「変更が怖い」という感覚の正体\u003c/h3\u003e\n\u003cp\u003e現場でよく聞く言葉がある。\u003c/p\u003e\n\u003cp\u003e「この辺、変更すると影響範囲が分からなくて…」\u003c/p\u003e\n\u003cp\u003eこれは、技術力不足の告白ではない。\n設計上の問題だ。\u003c/p\u003e\n\u003cp\u003e変更が怖いとは、\n\u003cstrong\u003e判断がどこにあるか分からない\u003c/strong\u003e という状態を指している。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e触る前に全体を読む必要がある\u003c/li\u003e\n\u003cli\u003eテストがあっても安心できない\u003c/li\u003e\n\u003cli\u003eレビューでも確信が持てない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうしてコードは、\n徐々に「触れない領域」へと変わっていく。\u003c/p\u003e","title":"第2章：判断は、なぜシステムを壊すのか"},{"content":" 本書における「設計」の定義 用語についての注意 設計の本質は「責任の分割」 責任を分けただけでは、設計は完成しない 構造による保証とは何か 設計とアーキテクチャの違い 設計の8割は、構造で決まる 良い設計は、壊そうと思っても壊せない 良い設計は、変更の影響が爆発しない 良い設計は、人間の思考コストを下げる 良い設計は、属人化しない 設計に正解はないが、説明は必要 この章のまとめ 多くのエンジニアは、 「設計」という言葉を使いながら、 実は同じものを指していません。\nある人は、 クラス図やレイヤー構成のことを指します。\nある人は、 アーキテクチャやフレームワーク選定を指します。\nまたある人は、 実装前に少し考えること自体を、 設計と呼んでいるかもしれません。\n本書では、 まずこの曖昧さを取り除きます。\n本書における「設計」の定義 本書では、設計を次のように定義します。\n設計とは、\n責任を分割し、その正しさを構造によって保証すること です。\nこれを、式で表すとこうなります。\n責任の分割 ＋ 構造による保証 ＝ 設計\nこの式が、 本書全体を通しての軸になります。\n用語についての注意 本書では、 構造による保証 を表現する際に、 文脈に応じて、\n制約 制限 保証 強制 誘導 といった言葉を使います。\nしかし、指している本質は一つです。\nそれは、\nやってはいけないことを、人が判断するのではなく、 構造によって、そもそもできなくする\nという考え方です。 (これらの言葉は、あくまで、文脈によって使い分けるだけです。)\n設計の本質は「責任の分割」 まず、設計の目的から見ていきます。\n設計の本質は、責任の分割 です。\nここで言う責任とは、 わかりやすく言えば、\nクラスや関数が持つ役割\nのことです。\n何を知っているのか 何を知らなくてよいのか 何の役割を担うのか これらを明確に分けることが、 設計の出発点です。\n責任が曖昧なまま集まっている構造は、 どれだけ読みやすく書かれていても、 壊れやすい設計になります。\n責任を分けただけでは、設計は完成しない 責任を分割することは重要です。\nしかし、それだけでは不十分です。\nなぜなら、 分割された責任が、\n守られるかどうか 正しく使われるかどうか が、人の注意に委ねられてしまうからです。\nここで必要になるのが、 構造による保証 です。\n構造による保証とは何か 構造による保証とは、\nやっていいこと / いけないことを、 人が判断するのではなく、 プログラミング言語の制約によって実現すること\nです。\nたとえば、\n必ずこの順番で呼ばなければならない → そもそも順番を間違えて呼べない API にする\nnull を渡してはいけない → null を表現できない型にする\n特定の条件下でしか使えない → その条件を満たした状態でしか生成できないオブジェクトにする\nこうした工夫は、\n「ここは気をつけて使ってください」 「ドキュメントを読めばわかります」 といった、 人に依存したルールとは本質的に異なります。\n設計とアーキテクチャの違い 設計とアーキテクチャは、 別物として語られることがあります。\nしかし本質的には、\n設計とアーキテクチャの違いは、スコープの違い です。\n一つの関数やクラスの責任をどう分けるか モジュール間の責任をどう分けるか アプリ全体の責任をどう分けるか どのレベルであっても、\n責任を分割し、 それを構造によって保証する\nという問いに答えている点は同じです。\n設計の8割は、構造で決まる 設計というと、 「どう書くか」「どう実装するか」 に意識が向きがちです。\nしかし実際には、\n設計の8割は、構造で決まります。\n構造とは、\n何ができて、何ができないか どこまで知ってよいか どこから先は触れないか といった、 選択肢そのものを制限する枠組みです。\nこの枠組みが、 人の注意ではなく、 構造によって守られているかどうか。\nそこに、 設計の良し悪しが現れます。\n良い設計は、壊そうと思っても壊せない 本書が考える良い設計は、\n壊そうと思っても壊せない構造 を持っています。\nこれは、 バグが一切出ないという意味ではありません。\n間違った使い方をしようとすると書けない 書こうとすると、すぐに違和感が出る 変更すると、影響範囲が自然に限定される こうした状態は、\n正しさが、構造によって保証されている から生まれます。\n良い設計は、変更の影響が爆発しない 設計の良し悪しが最も表れるのは、 変更が入ったときです。\n責任が分割され、 構造によって保証されている設計では、\n変更理由が一つに定まり 修正箇所が自然に絞られ 他の部分を疑わなくて済む という状態になります。\nこれは、コードを修正した人が優秀だからではありません。\n構造が、変更を制御している からです。\n良い設計は、人間の思考コストを下げる 良い設計がされたコードは、 読んでいて楽です。\nそれは、 人が毎回判断しなくてよいからです。\nこれは考えなくてよい ここは迷わなくてよい これは構造が保証している 良い設計は、 人に頑張らせません。\n構造に仕事をさせます。\n良い設計は、属人化しない 属人化は、 人の問題だと思われがちです。\nしかし本書では、\n属人化は、 正しさが構造で保証されていない設計の結果 だと考えます。\n特定の人だけが正しさを知っている状態は、 責任がコードではなく、 人に乗っている状態です。\n良い設計では、\n判断は構造にあり 人はそれに従うだけでよく 後から来た人でも安全に触れる という状態になります。\n設計に正解はないが、説明は必要 設計に、 唯一の正解はありません。\nただし、\n説明できない設計は、 責任の分割や保証の意図が曖昧な可能性があります。\nなぜこの構造なのか。 なぜこの責任の分け方なのか。\nそれを言語化できる設計は、 構造として優れています。\nこの章のまとめ 設計とは、\n責任の分割 ＋ 構造による保証\nです。\n責任は、 人が意識して守るものではありません。\n構造によって、保証されるべきもの です。\n次の章では、 この「保証」が失われたとき、 コードの中で何が起きるのか。\n「判断」という切り口から、 さらに掘り下げていきます。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/02-what-is-the-design/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9C%AC%E6%9B%B8%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E8%A8%AD%E8%A8%88%E3%81%AE%E5%AE%9A%E7%BE%A9\"\u003e本書における「設計」の定義\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%94%A8%E8%AA%9E%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E3%81%AE%E6%B3%A8%E6%84%8F\"\u003e用語についての注意\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AE%E6%9C%AC%E8%B3%AA%E3%81%AF%E8%B2%AC%E4%BB%BB%E3%81%AE%E5%88%86%E5%89%B2\"\u003e設計の本質は「責任の分割」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%B2%AC%E4%BB%BB%E3%82%92%E5%88%86%E3%81%91%E3%81%9F%E3%81%A0%E3%81%91%E3%81%A7%E3%81%AF%E8%A8%AD%E8%A8%88%E3%81%AF%E5%AE%8C%E6%88%90%E3%81%97%E3%81%AA%E3%81%84\"\u003e責任を分けただけでは、設計は完成しない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%A7%8B%E9%80%A0%E3%81%AB%E3%82%88%E3%82%8B%E4%BF%9D%E8%A8%BC%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B\"\u003e構造による保証とは何か\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%A8%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3%E3%81%AE%E9%81%95%E3%81%84\"\u003e設計とアーキテクチャの違い\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AE8%E5%89%B2%E3%81%AF%E6%A7%8B%E9%80%A0%E3%81%A7%E6%B1%BA%E3%81%BE%E3%82%8B\"\u003e設計の8割は、構造で決まる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%AF%E5%A3%8A%E3%81%9D%E3%81%86%E3%81%A8%E6%80%9D%E3%81%A3%E3%81%A6%E3%82%82%E5%A3%8A%E3%81%9B%E3%81%AA%E3%81%84\"\u003e良い設計は、壊そうと思っても壊せない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%AF%E5%A4%89%E6%9B%B4%E3%81%AE%E5%BD%B1%E9%9F%BF%E3%81%8C%E7%88%86%E7%99%BA%E3%81%97%E3%81%AA%E3%81%84\"\u003e良い設計は、変更の影響が爆発しない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%AF%E4%BA%BA%E9%96%93%E3%81%AE%E6%80%9D%E8%80%83%E3%82%B3%E3%82%B9%E3%83%88%E3%82%92%E4%B8%8B%E3%81%92%E3%82%8B\"\u003e良い設計は、人間の思考コストを下げる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%AF%E5%B1%9E%E4%BA%BA%E5%8C%96%E3%81%97%E3%81%AA%E3%81%84\"\u003e良い設計は、属人化しない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AB%E6%AD%A3%E8%A7%A3%E3%81%AF%E3%81%AA%E3%81%84%E3%81%8C%E8%AA%AC%E6%98%8E%E3%81%AF%E5%BF%85%E8%A6%81\"\u003e設計に正解はないが、説明は必要\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e多くのエンジニアは、\n「設計」という言葉を使いながら、\n実は同じものを指していません。\u003c/p\u003e\n\u003cp\u003eある人は、\nクラス図やレイヤー構成のことを指します。\u003c/p\u003e\n\u003cp\u003eある人は、\nアーキテクチャやフレームワーク選定を指します。\u003c/p\u003e\n\u003cp\u003eまたある人は、\n実装前に少し考えること自体を、\n設計と呼んでいるかもしれません。\u003c/p\u003e\n\u003cp\u003e本書では、\nまずこの曖昧さを取り除きます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"本書における設計の定義\"\u003e本書における「設計」の定義\u003c/h2\u003e\n\u003cp\u003e本書では、設計を次のように定義します。\u003c/p\u003e\n\u003cp\u003e設計とは、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e責任を分割し、その正しさを構造によって保証すること\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003eこれを、式で表すとこうなります。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e責任の分割 ＋ 構造による保証 ＝ 設計\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eこの式が、\n本書全体を通しての軸になります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"用語についての注意\"\u003e用語についての注意\u003c/h2\u003e\n\u003cp\u003e本書では、 \u003cstrong\u003e構造による保証\u003c/strong\u003e を表現する際に、\n文脈に応じて、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e制約\u003c/li\u003e\n\u003cli\u003e制限\u003c/li\u003e\n\u003cli\u003e保証\u003c/li\u003e\n\u003cli\u003e強制\u003c/li\u003e\n\u003cli\u003e誘導\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった言葉を使います。\u003c/p\u003e\n\u003cp\u003eしかし、指している本質は一つです。\u003c/p\u003e\n\u003cp\u003eそれは、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eやってはいけないことを、人が判断するのではなく、\n構造によって、そもそもできなくする\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eという考え方です。\n(これらの言葉は、あくまで、文脈によって使い分けるだけです。)\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"設計の本質は責任の分割\"\u003e設計の本質は「責任の分割」\u003c/h2\u003e\n\u003cp\u003eまず、設計の目的から見ていきます。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e設計の本質は、責任の分割\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003eここで言う責任とは、\nわかりやすく言えば、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eクラスや関数が持つ役割\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eのことです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e何を知っているのか\u003c/li\u003e\n\u003cli\u003e何を知らなくてよいのか\u003c/li\u003e\n\u003cli\u003e何の役割を担うのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらを明確に分けることが、\n設計の出発点です。\u003c/p\u003e\n\u003cp\u003e責任が曖昧なまま集まっている構造は、\nどれだけ読みやすく書かれていても、\n壊れやすい設計になります。\u003c/p\u003e","title":"第2章：設計とは何か"},{"content":" 判断とは何か 判断が構造として表現されていない場合、何が起こるか 「レビューで防ぐ」は、設計ではない 良い設計は、判断を構造で表現する 判断が構造で表現されると、何が変わるか 判断が構造で表現されていないコードの特徴 判断が構造で表現されると、コードは強くなる この章のまとめ 設計が壊れ始めるとき、 コードの中では、 ある現象が必ず起きています。\nそれは、\n判断が、コードのあちこちに散らばっている\nという状態です。\n判断とは何か 本書で言う「判断」とは、 if 文や条件分岐そのもののことではありません。\nこれは今やってよいのか この順番で呼んでよいのか この値を渡してよいのか この状態で変更してよいのか といった、 「やってよい／いけない」を決める責任 そのものを指します。\nこの判断が、 どこで行われているか。\nそれが、 設計の壊れやすさを決めます。\n判断が構造として表現されていない場合、何が起こるか 判断が構造として表現されていない場合、 それは次の場所に押し出されていきます。\n呼び出し元のコード コメントやドキュメント コードレビュー テスト そして最終的には、人の記憶 この状態では、\n正しく使えるかどうかは人次第 知っている人がいないと触れない うっかりミスが即バグになる という構造になります。\nこれは、 判断がコードの外に漏れ出している 状態です。\n「レビューで防ぐ」は、設計ではない よくある会話があります。\nこれはレビューで気づけますよね テストを書けば大丈夫ですよね\n一見、正しそうに聞こえます。\nしかしこれは、 設計でやるべき判断を、 後工程に押し出している だけです。\n書いてはいけないコードが書けてしまう 実行してはいけない状態が表現できてしまう 呼んではいけない順番で呼べてしまう この時点で、 構造はすでに負けています。\nレビューやテストは、 設計の代わりにはなりません。\n良い設計は、判断を構造で表現する 良い設計では、 判断は 構造の中 にあります。\n正しい順番でしか呼べない 不正な状態を表現できない 間違った依存関係を書けない こうした制約は、\n人が判断して守るもの ではなく 構造が勝手に守るもの です。\n判断が構造で表現されると、何が変わるか 判断が構造に埋め込まれると、 コードの性質が変わります。\n書いていて迷わない 正しい使い方が自然にわかる 間違った方向に進もうとすると止められる このとき開発者は、\n毎回考える人 ではなく 構造に従う人 になります。\nこれは、 スキルが低いという意味ではありません。\n思考を より価値の高い場所に使える という意味です。\n判断が構造で表現されていないコードの特徴 判断が構造で表現されていないコードには、 共通した兆候があります。\n「ここは注意してください」というコメントが多い 正しい呼び出し方が暗黙知になっている 同じような if が何度も出てくる テストでしか仕様がわからない これらはすべて、\n判断を構造として表現できていない サインです。\n判断が構造で表現されると、コードは強くなる 判断が構造で表現されたコードは、 驚くほど壊れにくくなります。\nそれは、\n人が賢くなったから ではなく 構造が判断を引き受けたから です。\n設計の仕事は、 人を信用しないことではありません。\n人が間違えても大丈夫な構造を作ること です。\nこの章のまとめ 判断は、必ずどこかに存在する 構造で表現されない判断は、人に押し付けられる 良い設計は、判断を構造で表現する 判断が構造で表現されれば、コードは壊れにくくなる 次の章では、この「判断」を、\n状態 依存関係 ライフサイクル といった、 より具体的な構造の中で、 どう扱うかを見ていきます。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/03-where-the-judge-placed/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B\"\u003e判断とは何か\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%8C%E6%A7%8B%E9%80%A0%E3%81%A8%E3%81%97%E3%81%A6%E8%A1%A8%E7%8F%BE%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E4%BD%95%E3%81%8C%E8%B5%B7%E3%81%93%E3%82%8B%E3%81%8B\"\u003e判断が構造として表現されていない場合、何が起こるか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC%E3%81%A7%E9%98%B2%E3%81%90%E3%81%AF%E8%A8%AD%E8%A8%88%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e「レビューで防ぐ」は、設計ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%AF%E5%88%A4%E6%96%AD%E3%82%92%E6%A7%8B%E9%80%A0%E3%81%A7%E8%A1%A8%E7%8F%BE%E3%81%99%E3%82%8B\"\u003e良い設計は、判断を構造で表現する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%8C%E6%A7%8B%E9%80%A0%E3%81%A7%E8%A1%A8%E7%8F%BE%E3%81%95%E3%82%8C%E3%82%8B%E3%81%A8%E4%BD%95%E3%81%8C%E5%A4%89%E3%82%8F%E3%82%8B%E3%81%8B\"\u003e判断が構造で表現されると、何が変わるか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%8C%E6%A7%8B%E9%80%A0%E3%81%A7%E8%A1%A8%E7%8F%BE%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E7%89%B9%E5%BE%B4\"\u003e判断が構造で表現されていないコードの特徴\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%8C%E6%A7%8B%E9%80%A0%E3%81%A7%E8%A1%A8%E7%8F%BE%E3%81%95%E3%82%8C%E3%82%8B%E3%81%A8%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AF%E5%BC%B7%E3%81%8F%E3%81%AA%E3%82%8B\"\u003e判断が構造で表現されると、コードは強くなる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e設計が壊れ始めるとき、\nコードの中では、\nある現象が必ず起きています。\u003c/p\u003e\n\u003cp\u003eそれは、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e判断が、コードのあちこちに散らばっている\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eという状態です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"判断とは何か\"\u003e判断とは何か\u003c/h2\u003e\n\u003cp\u003e本書で言う「判断」とは、\nif 文や条件分岐そのもののことではありません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこれは今やってよいのか\u003c/li\u003e\n\u003cli\u003eこの順番で呼んでよいのか\u003c/li\u003e\n\u003cli\u003eこの値を渡してよいのか\u003c/li\u003e\n\u003cli\u003eこの状態で変更してよいのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった、\n\u003cstrong\u003e「やってよい／いけない」を決める責任\u003c/strong\u003e\nそのものを指します。\u003c/p\u003e\n\u003cp\u003eこの判断が、\nどこで行われているか。\u003c/p\u003e\n\u003cp\u003eそれが、\n設計の壊れやすさを決めます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"判断が構造として表現されていない場合何が起こるか\"\u003e判断が構造として表現されていない場合、何が起こるか\u003c/h2\u003e\n\u003cp\u003e判断が構造として表現されていない場合、\nそれは次の場所に押し出されていきます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e呼び出し元のコード\u003c/li\u003e\n\u003cli\u003eコメントやドキュメント\u003c/li\u003e\n\u003cli\u003eコードレビュー\u003c/li\u003e\n\u003cli\u003eテスト\u003c/li\u003e\n\u003cli\u003eそして最終的には、人の記憶\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの状態では、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e正しく使えるかどうかは人次第\u003c/li\u003e\n\u003cli\u003e知っている人がいないと触れない\u003c/li\u003e\n\u003cli\u003eうっかりミスが即バグになる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという構造になります。\u003c/p\u003e\n\u003cp\u003eこれは、\n\u003cstrong\u003e判断がコードの外に漏れ出している\u003c/strong\u003e\n状態です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"レビューで防ぐは設計ではない\"\u003e「レビューで防ぐ」は、設計ではない\u003c/h2\u003e\n\u003cp\u003eよくある会話があります。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eこれはレビューで気づけますよね\nテストを書けば大丈夫ですよね\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e一見、正しそうに聞こえます。\u003c/p\u003e\n\u003cp\u003eしかしこれは、\n\u003cstrong\u003e設計でやるべき判断を、\n後工程に押し出している\u003c/strong\u003e だけです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e書いてはいけないコードが書けてしまう\u003c/li\u003e\n\u003cli\u003e実行してはいけない状態が表現できてしまう\u003c/li\u003e\n\u003cli\u003e呼んではいけない順番で呼べてしまう\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの時点で、\n構造はすでに負けています。\u003c/p\u003e\n\u003cp\u003eレビューやテストは、\n設計の代わりにはなりません。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"良い設計は判断を構造で表現する\"\u003e良い設計は、判断を構造で表現する\u003c/h2\u003e\n\u003cp\u003e良い設計では、\n判断は \u003cstrong\u003e構造の中\u003c/strong\u003e にあります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e正しい順番でしか呼べない\u003c/li\u003e\n\u003cli\u003e不正な状態を表現できない\u003c/li\u003e\n\u003cli\u003e間違った依存関係を書けない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうした制約は、\u003c/p\u003e","title":"第3章：判断は、どこに置かれるべきか"},{"content":" 「閉じ込める」とは、どういうことか 強く閉じる、弱く閉じる 境界は、判断のために存在する 型は、判断を固定する道具である 抽象化は、判断を動かす余地を残す 共通化は「閉じ込め」ではない 判断を閉じ込められている状態とは まとめ 第2章では、 判断がどのようにシステムを壊していくのかを見てきた。\nこの章では、いよいよ本題に入る。\nでは、判断をどのように扱えばよいのか。\n答えはシンプルだ。 判断を、閉じ込める。\nただしこれは、 単にロジックを隠すという話ではない。 設計として意味のある「閉じ込め方」には、 いくつかの技術と考え方がある。\n「閉じ込める」とは、どういうことか 判断を閉じ込めるとは、 その判断に責任を持つ場所を決めることだ。\nこの判断は、どこで行うのか どこから触ってよいのか どこからは触ってはいけないのか これを曖昧にしたまま設計すると、 判断は必ず広がる。\n逆に言えば、 閉じ込めるとは 判断の影響範囲を限定する行為 に他ならない。\n強く閉じる、弱く閉じる すべての判断を、 同じ強さで閉じ込める必要はない。\n判断には、それぞれ性質がある。\n外れたら致命的な判断 外れてもすぐに直せる判断 プロダクト全体に影響する判断 画面単位で完結する判断 重要なのは、 判断の重さに応じて、閉じ込め方を変えること だ。\n強く閉じるとは、 型や境界によって、 簡単には触れないようにすること。\n弱く閉じるとは、 変更を前提に、 差し替えやすい形で置いておくこと。\n設計とは、 この強弱を意識的に選び続ける行為だ。\n境界は、判断のために存在する レイヤやモジュールの境界は、 整理のためにあるのではない。\nそこには必ず、\n「この判断は、ここまで」\nという線が引かれている。\n境界をまたいで判断が漏れ出すと、 設計は一気に脆くなる。\n上位レイヤが下位の事情を知りすぎる 本来関係のない変更が波及する 境界を守る意味が失われる 境界とは、 判断を隔離するための装置 だと捉えたほうがよい。\n型は、判断を固定する道具である 型は、 安全性のためだけに存在するのではない。\n型は、\n「この判断は、こういう形でしか存在しない」\nと宣言するための道具でもある。\n型を使うことで、\n許される状態 許されない状態 を設計者が先に決めることができる。\nこれは、 判断をコード全体ににじませないための、 非常に強力な手段だ。\n抽象化は、判断を動かす余地を残す 抽象化は、 判断を消す行為ではない。\n判断を あとから差し替えられる場所に押し込める 行為だ。\n良い抽象化は、\n何が変わりうるか 何は変わらないか を、はっきり分けている。\n逆に言えば、 何が変わるか分かっていない状態での抽象化は、 判断を拡散させる原因になる。\n共通化は「閉じ込め」ではない 共通化は、 しばしば閉じ込める行為だと誤解される。\nしかし実際には、 共通化は 判断を集める行為 だ。\n同じように見える処理 今は似ている振る舞い これらを一箇所にまとめることで、 判断のスコープは広がる。\nだからこそ、 共通化は慎重に扱わなければならない。\n閉じ込める前に共通化すると、 判断は逃げ場を失い、 システム全体を縛り始める。\n判断を閉じ込められている状態とは 判断がうまく閉じ込められているとき、 コードには次のような特徴が現れる。\n変更点が、ほぼ一箇所に収まる 修正理由を説明できる 壊すときに、壊す場所が分かる これは、 設計が「うまくいっている」サインだ。\n完璧である必要はない。\n判断の置き場所を、自覚できているかどうか が、 設計者としての分かれ目になる。\nまとめ 閉じ込めるとは、判断の影響範囲を限定すること 判断の重さによって、閉じ込め方を変える 境界・型・抽象は、すべて判断のための道具 共通化は、閉じ込めではなく拡張である 次章では、 これらの考え方を使って、 間違える前提で設計する とはどういうことかを掘り下げていく。\n","permalink":"https://design.okuda-studio.com/books/003-design-that-locks-in-judgment/03-/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E9%96%89%E3%81%98%E8%BE%BC%E3%82%81%E3%82%8B%E3%81%A8%E3%81%AF%E3%81%A9%E3%81%86%E3%81%84%E3%81%86%E3%81%93%E3%81%A8%E3%81%8B\"\u003e「閉じ込める」とは、どういうことか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%BC%B7%E3%81%8F%E9%96%89%E3%81%98%E3%82%8B%E5%BC%B1%E3%81%8F%E9%96%89%E3%81%98%E3%82%8B\"\u003e強く閉じる、弱く閉じる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A2%83%E7%95%8C%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B\"\u003e境界は、判断のために存在する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%9E%8B%E3%81%AF%E5%88%A4%E6%96%AD%E3%82%92%E5%9B%BA%E5%AE%9A%E3%81%99%E3%82%8B%E9%81%93%E5%85%B7%E3%81%A7%E3%81%82%E3%82%8B\"\u003e型は、判断を固定する道具である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%8A%BD%E8%B1%A1%E5%8C%96%E3%81%AF%E5%88%A4%E6%96%AD%E3%82%92%E5%8B%95%E3%81%8B%E3%81%99%E4%BD%99%E5%9C%B0%E3%82%92%E6%AE%8B%E3%81%99\"\u003e抽象化は、判断を動かす余地を残す\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%85%B1%E9%80%9A%E5%8C%96%E3%81%AF%E9%96%89%E3%81%98%E8%BE%BC%E3%82%81%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e共通化は「閉じ込め」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%82%92%E9%96%89%E3%81%98%E8%BE%BC%E3%82%81%E3%82%89%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E7%8A%B6%E6%85%8B%E3%81%A8%E3%81%AF\"\u003e判断を閉じ込められている状態とは\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003e第2章では、\n判断がどのようにシステムを壊していくのかを見てきた。\u003c/p\u003e\n\u003cp\u003eこの章では、いよいよ本題に入る。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eでは、判断をどのように扱えばよいのか。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e答えはシンプルだ。\n\u003cstrong\u003e判断を、閉じ込める。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eただしこれは、\n単にロジックを隠すという話ではない。\n設計として意味のある「閉じ込め方」には、\nいくつかの技術と考え方がある。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"閉じ込めるとはどういうことか\"\u003e「閉じ込める」とは、どういうことか\u003c/h3\u003e\n\u003cp\u003e判断を閉じ込めるとは、\nその判断に責任を持つ場所を決めることだ。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこの判断は、どこで行うのか\u003c/li\u003e\n\u003cli\u003eどこから触ってよいのか\u003c/li\u003e\n\u003cli\u003eどこからは触ってはいけないのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれを曖昧にしたまま設計すると、\n判断は必ず広がる。\u003c/p\u003e\n\u003cp\u003e逆に言えば、\n閉じ込めるとは \u003cstrong\u003e判断の影響範囲を限定する行為\u003c/strong\u003e に他ならない。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"強く閉じる弱く閉じる\"\u003e強く閉じる、弱く閉じる\u003c/h3\u003e\n\u003cp\u003eすべての判断を、\n同じ強さで閉じ込める必要はない。\u003c/p\u003e\n\u003cp\u003e判断には、それぞれ性質がある。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e外れたら致命的な判断\u003c/li\u003e\n\u003cli\u003e外れてもすぐに直せる判断\u003c/li\u003e\n\u003cli\u003eプロダクト全体に影響する判断\u003c/li\u003e\n\u003cli\u003e画面単位で完結する判断\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e重要なのは、\n\u003cstrong\u003e判断の重さに応じて、閉じ込め方を変えること\u003c/strong\u003e だ。\u003c/p\u003e\n\u003cp\u003e強く閉じるとは、\n型や境界によって、\n簡単には触れないようにすること。\u003c/p\u003e\n\u003cp\u003e弱く閉じるとは、\n変更を前提に、\n差し替えやすい形で置いておくこと。\u003c/p\u003e\n\u003cp\u003e設計とは、\nこの強弱を意識的に選び続ける行為だ。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"境界は判断のために存在する\"\u003e境界は、判断のために存在する\u003c/h3\u003e\n\u003cp\u003eレイヤやモジュールの境界は、\n整理のためにあるのではない。\u003c/p\u003e\n\u003cp\u003eそこには必ず、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e「この判断は、ここまで」\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eという線が引かれている。\u003c/p\u003e\n\u003cp\u003e境界をまたいで判断が漏れ出すと、\n設計は一気に脆くなる。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e上位レイヤが下位の事情を知りすぎる\u003c/li\u003e\n\u003cli\u003e本来関係のない変更が波及する\u003c/li\u003e\n\u003cli\u003e境界を守る意味が失われる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e境界とは、\n\u003cstrong\u003e判断を隔離するための装置\u003c/strong\u003e だと捉えたほうがよい。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"型は判断を固定する道具である\"\u003e型は、判断を固定する道具である\u003c/h3\u003e\n\u003cp\u003e型は、\n安全性のためだけに存在するのではない。\u003c/p\u003e\n\u003cp\u003e型は、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e「この判断は、こういう形でしか存在しない」\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eと宣言するための道具でもある。\u003c/p\u003e\n\u003cp\u003e型を使うことで、\u003c/p\u003e","title":"第3章：判断を閉じ込めるという技術"},{"content":" 設計とは、判断の軸を一本通すこと 判断が強い設計には「一本の軸」がある 軸がない設計は、すべて場当たりになる 設計の仕事は「選択肢を減らす」こと 軸とは「何を守るか」の宣言である 軸があれば、判断は再利用できる 構造は、軸の副産物である この章のまとめ 設計とは、判断の軸を一本通すこと 設計の話になると、\nよくこんな言葉が出てきます。\n責務を分離する。\n関心事を分ける。\n疎結合にする。\nこれらはすべて、\n設計において重要な考え方です。\nしかし本書では、\nそれらを個別のテクニックとしては扱いません。\nなぜなら、\nそれらはすべて 結果として現れるもの だからです。\n判断が強い設計には「一本の軸」がある 良い設計を眺めると、\nある共通点があります。\nそれは、\n判断の軸が一貫している ことです。\nどの責務を分けるか。\nどこにロジックを置くか。\nどこで例外を吸収するか。\nそれらの判断が、\n同じ方向を向いています。\n一方で、\n設計が崩れているコードでは、\n判断の基準が場所ごとに違います。\nある場所では変更頻度を重視し、\n別の場所では実装の楽さを優先し、\nさらに別の場所では将来拡張を想定する。\n軸が複数あると、設計は必ず歪みます。\n軸がない設計は、すべて場当たりになる 判断の軸が明示されていない場合、\n設計はどうなるでしょうか。\n答えは単純です。\nその場で一番納得しやすい判断が選ばれます。\n今すぐ直せるか。\n影響が少なそうか。\n説明しやすいか。\nこれらは、\n判断基準として間違ってはいません。\nしかしそれが積み重なると、\n判断同士が噛み合わなくなります。\n結果として、\n「なぜこうなっているのか分からない構造」 が生まれます。\n設計の仕事は「選択肢を減らす」こと 設計というと、\n選択肢を増やす行為だと思われがちです。\n将来に備える。\n拡張ポイントを作る。\n何でもできる構造にする。\nしかし実際には、\n良い設計ほど、選択肢を減らします。\nこの変更は、ここに影響する。\nこの責務は、ここにしか書かない。\nこの種類の判断は、ここでまとめて行う。\n判断の置き場所を固定すること。\nそれが、設計の重要な役割です。\n軸とは「何を守るか」の宣言である 判断の軸とは、\n言い換えると「何を守るか」です。\n変更のしやすさを守るのか。\n理解のしやすさを守るのか。\n失敗しにくさを守るのか。\nすべてを同時に守ることはできません。\nだから設計では、\n何を優先し、\n何を犠牲にするかを決めます。\n設計とは、価値観の選択です。\n軸があれば、判断は再利用できる 判断の軸が明確であれば、\nすべての細かい判断を覚えておく必要はありません。\n迷ったときは、\n軸に照らして考えればよいからです。\nこの変更は、 守りたい価値に沿っているか。\nこの実装は、 判断の置き場所を壊していないか。\nこうして、\n判断は再現可能になります。\n再現可能なのは、\nテクニックではありません。\n判断の基準です。\n構造は、軸の副産物である 責務分離。\nレイヤードアーキテクチャ。\nモジュール分割。\nこれらはすべて、\n判断の軸に従った結果として現れます。\n軸が違えば、\n同じ問題に対して、\nまったく違う構造が選ばれることもあります。\nそれで構いません。\n重要なのは、\nなぜその構造なのかを説明できることです。\nこの章のまとめ 設計とは、\n判断を増やす行為ではありません。\n判断を、\n一つの軸に集約する行為です。\n軸があれば、\n判断は再現できます。\n軸がなければ、\n設計は場当たりになります。\n次の章では、\nこの「判断の軸」を、\nどのように言語化し、共有するのかについて、\n具体的に掘り下げていきます。\n","permalink":"https://design.okuda-studio.com/books/002-design-starts-with-decisions/03-make-decisions-based-on-a-single-axis/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%A8%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%AE%E8%BB%B8%E3%82%92%E4%B8%80%E6%9C%AC%E9%80%9A%E3%81%99%E3%81%93%E3%81%A8\"\u003e設計とは、判断の軸を一本通すこと\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%8C%E5%BC%B7%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%AB%E3%81%AF%E4%B8%80%E6%9C%AC%E3%81%AE%E8%BB%B8%E3%81%8C%E3%81%82%E3%82%8B\"\u003e判断が強い設計には「一本の軸」がある\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%BB%B8%E3%81%8C%E3%81%AA%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%AF%E3%81%99%E3%81%B9%E3%81%A6%E5%A0%B4%E5%BD%93%E3%81%9F%E3%82%8A%E3%81%AB%E3%81%AA%E3%82%8B\"\u003e軸がない設計は、すべて場当たりになる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AE%E4%BB%95%E4%BA%8B%E3%81%AF%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E6%B8%9B%E3%82%89%E3%81%99%E3%81%93%E3%81%A8\"\u003e設計の仕事は「選択肢を減らす」こと\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%BB%B8%E3%81%A8%E3%81%AF%E4%BD%95%E3%82%92%E5%AE%88%E3%82%8B%E3%81%8B%E3%81%AE%E5%AE%A3%E8%A8%80%E3%81%A7%E3%81%82%E3%82%8B\"\u003e軸とは「何を守るか」の宣言である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%BB%B8%E3%81%8C%E3%81%82%E3%82%8C%E3%81%B0%E5%88%A4%E6%96%AD%E3%81%AF%E5%86%8D%E5%88%A9%E7%94%A8%E3%81%A7%E3%81%8D%E3%82%8B\"\u003e軸があれば、判断は再利用できる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%A7%8B%E9%80%A0%E3%81%AF%E8%BB%B8%E3%81%AE%E5%89%AF%E7%94%A3%E7%89%A9%E3%81%A7%E3%81%82%E3%82%8B\"\u003e構造は、軸の副産物である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"設計とは判断の軸を一本通すこと\"\u003e設計とは、判断の軸を一本通すこと\u003c/h2\u003e\n\u003chr\u003e\n\u003cp\u003e設計の話になると、\u003cbr\u003e\nよくこんな言葉が出てきます。\u003c/p\u003e\n\u003cp\u003e責務を分離する。\u003cbr\u003e\n関心事を分ける。\u003cbr\u003e\n疎結合にする。\u003c/p\u003e\n\u003cp\u003eこれらはすべて、\u003cbr\u003e\n設計において重要な考え方です。\u003c/p\u003e\n\u003cp\u003eしかし本書では、\u003cbr\u003e\nそれらを個別のテクニックとしては扱いません。\u003c/p\u003e\n\u003cp\u003eなぜなら、\u003cbr\u003e\nそれらはすべて \u003cstrong\u003e結果として現れるもの\u003c/strong\u003e だからです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断が強い設計には一本の軸がある\"\u003e判断が強い設計には「一本の軸」がある\u003c/h3\u003e\n\u003cp\u003e良い設計を眺めると、\u003cbr\u003e\nある共通点があります。\u003c/p\u003e\n\u003cp\u003eそれは、\u003cbr\u003e\n\u003cstrong\u003e判断の軸が一貫している\u003c/strong\u003e ことです。\u003c/p\u003e\n\u003cp\u003eどの責務を分けるか。\u003cbr\u003e\nどこにロジックを置くか。\u003cbr\u003e\nどこで例外を吸収するか。\u003c/p\u003e\n\u003cp\u003eそれらの判断が、\u003cbr\u003e\n同じ方向を向いています。\u003c/p\u003e\n\u003cp\u003e一方で、\u003cbr\u003e\n設計が崩れているコードでは、\u003cbr\u003e\n判断の基準が場所ごとに違います。\u003c/p\u003e\n\u003cp\u003eある場所では変更頻度を重視し、\u003cbr\u003e\n別の場所では実装の楽さを優先し、\u003cbr\u003e\nさらに別の場所では将来拡張を想定する。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e軸が複数あると、設計は必ず歪みます。\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"軸がない設計はすべて場当たりになる\"\u003e軸がない設計は、すべて場当たりになる\u003c/h3\u003e\n\u003cp\u003e判断の軸が明示されていない場合、\u003cbr\u003e\n設計はどうなるでしょうか。\u003c/p\u003e\n\u003cp\u003e答えは単純です。\u003cbr\u003e\nその場で一番納得しやすい判断が選ばれます。\u003c/p\u003e\n\u003cp\u003e今すぐ直せるか。\u003cbr\u003e\n影響が少なそうか。\u003cbr\u003e\n説明しやすいか。\u003c/p\u003e\n\u003cp\u003eこれらは、\u003cbr\u003e\n判断基準として間違ってはいません。\u003c/p\u003e\n\u003cp\u003eしかしそれが積み重なると、\u003cbr\u003e\n判断同士が噛み合わなくなります。\u003c/p\u003e\n\u003cp\u003e結果として、\u003cbr\u003e\n「なぜこうなっているのか分からない構造」\nが生まれます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"設計の仕事は選択肢を減らすこと\"\u003e設計の仕事は「選択肢を減らす」こと\u003c/h3\u003e\n\u003cp\u003e設計というと、\u003cbr\u003e\n選択肢を増やす行為だと思われがちです。\u003c/p\u003e\n\u003cp\u003e将来に備える。\u003cbr\u003e\n拡張ポイントを作る。\u003cbr\u003e\n何でもできる構造にする。\u003c/p\u003e\n\u003cp\u003eしかし実際には、\u003cbr\u003e\n良い設計ほど、選択肢を減らします。\u003c/p\u003e\n\u003cp\u003eこの変更は、ここに影響する。\u003cbr\u003e\nこの責務は、ここにしか書かない。\u003cbr\u003e\nこの種類の判断は、ここでまとめて行う。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e判断の置き場所を固定すること\u003c/strong\u003e。\u003cbr\u003e\nそれが、設計の重要な役割です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"軸とは何を守るかの宣言である\"\u003e軸とは「何を守るか」の宣言である\u003c/h3\u003e\n\u003cp\u003e判断の軸とは、\u003cbr\u003e\n言い換えると「何を守るか」です。\u003c/p\u003e","title":"第3章：設計とは、判断の軸を一本通すこと"},{"content":" 判断の軸を、コードの外に逃がさない 軸が失われる一番の理由 判断は「読む人が必ず通る場所」に置く 命名は、判断を閉じ込める最初の手段 層を作ることは、判断の担当を決めること コメントを書くなら「なぜ」だけを書く テストは、判断を固定する最後の砦 判断を書かない設計は、必ず口頭説明に戻る この章のまとめ 判断の軸を、コードの外に逃がさない 判断の軸が重要だ、\nという話までは、\n多くのエンジニアが同意します。\n問題は、その次です。\n判断の軸は、\nどこに置けばよいのでしょうか。\n頭の中でしょうか。\n設計ドキュメントでしょうか。\nコードでしょうか。\nこの章では、\n判断の軸を「消えにくい形」で残す方法を考えます。\n軸が失われる一番の理由 判断の軸が失われる理由は、\n実はとても単純です。\n軸が、コードの外にあるからです。\nドキュメント Wiki 設計資料 それらは悪ではありません。\nしかし、\nコードと更新タイミングがズレた瞬間、\n信頼されなくなります。\n結果として、\n人はコードだけを見るようになります。\nそしてコードの中に、\n判断の理由が見つからなくなります。\n判断は「読む人が必ず通る場所」に置く 判断の軸を残すための原則は、\n一つだけです。\n読む人が、必ず通る場所に置くこと。\n誰も読まないドキュメントに、\n重要な判断を書いても意味はありません。\n一方で、\n必ず読まれる場所があります。\nそれは、\nコードです。\n正確には、\nコードを理解するために、\n必ず目に入る構造です。\n命名は、判断を閉じ込める最初の手段 もっとも軽く、\nもっとも効果的な方法は、\n命名です。\nなぜこのクラスが存在するのか。\nなぜこの責務が切り出されているのか。\nそれが名前に現れていれば、\n読む人は自然に軸を追えます。\n逆に、\n無難で抽象的な名前は、\n判断を隠します。\nManager Helper Util これらは、\n判断を先送りにした結果です。\n命名は、判断を固定する行為です。\n層を作ることは、判断の担当を決めること レイヤー分割も、\n判断を残すための手段です。\nどこで判断するのか。\nどこでは判断しないのか。\nそれを、\n構造として固定します。\nUI は判断しない。\nUseCase が判断する。\nRepository は選択肢を提供する。\nこう決めることで、\n判断は散らばりにくくなります。\n層とは、判断の責任範囲です。\nコメントを書くなら「なぜ」だけを書く コメントを書く場合、\n注意点があります。\nやっていることを書く必要はありません。\nコードを読めば分かるからです。\n書くべきなのは、\nなぜ、そうしているのか です。\nなぜこの条件があるのか。\nなぜこの分岐はここにあるのか。\nなぜ別の選択をしなかったのか。\nコメントは、\n判断の補助線として使います。\nテストは、判断を固定する最後の砦 テストもまた、\n判断を残す場所です。\n何を保証しているのか。\n何を保証しないのか。\nそれが、\nテストケースとして表れます。\n特に、\n境界条件や例外系は、\n強い判断の塊です。\nなぜこのケースを落とすのか。\nなぜここは通してよいのか。\nテストは、判断を軽く書き換えられないようにする仕組みです。\n判断を書かない設計は、必ず口頭説明に戻る 判断がコードに残っていない場合、\nどうなるでしょうか。\n必ず、\n口頭説明に戻ります。\n「それは暗黙の了解で」\n「前からそうなっていて」\n「触るときは気をつけて」\nこうした言葉が増えたら、\n判断は失われています。\n設計が属人化しているのではありません。\n判断が、構造に閉じていないだけです。\nこの章のまとめ 判断の軸は、\n意識しないと必ず消えます。\nだからこそ、\n消えにくい場所に置く必要があります。\n命名 構造 コメント テスト これらはすべて、\n判断を固定するための手段です。\n次の章では、\n既に判断が失われたコードに対して、\nどうやって軸を見つけ直すのか を扱います。\nつまり、\nモノリスや負債のある現場で、\n最初に何を見るべきか、です。\n","permalink":"https://design.okuda-studio.com/books/002-design-starts-with-decisions/04-leave-the-decisions-in-the-code/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AE%E8%BB%B8%E3%82%92%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E5%A4%96%E3%81%AB%E9%80%83%E3%81%8C%E3%81%95%E3%81%AA%E3%81%84\"\u003e判断の軸を、コードの外に逃がさない\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E8%BB%B8%E3%81%8C%E5%A4%B1%E3%82%8F%E3%82%8C%E3%82%8B%E4%B8%80%E7%95%AA%E3%81%AE%E7%90%86%E7%94%B1\"\u003e軸が失われる一番の理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AF%E8%AA%AD%E3%82%80%E4%BA%BA%E3%81%8C%E5%BF%85%E3%81%9A%E9%80%9A%E3%82%8B%E5%A0%B4%E6%89%80%E3%81%AB%E7%BD%AE%E3%81%8F\"\u003e判断は「読む人が必ず通る場所」に置く\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%91%BD%E5%90%8D%E3%81%AF%E5%88%A4%E6%96%AD%E3%82%92%E9%96%89%E3%81%98%E8%BE%BC%E3%82%81%E3%82%8B%E6%9C%80%E5%88%9D%E3%81%AE%E6%89%8B%E6%AE%B5\"\u003e命名は、判断を閉じ込める最初の手段\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%B1%A4%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%AE%E6%8B%85%E5%BD%93%E3%82%92%E6%B1%BA%E3%82%81%E3%82%8B%E3%81%93%E3%81%A8\"\u003e層を作ることは、判断の担当を決めること\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88%E3%82%92%E6%9B%B8%E3%81%8F%E3%81%AA%E3%82%89%E3%81%AA%E3%81%9C%E3%81%A0%E3%81%91%E3%82%92%E6%9B%B8%E3%81%8F\"\u003eコメントを書くなら「なぜ」だけを書く\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%86%E3%82%B9%E3%83%88%E3%81%AF%E5%88%A4%E6%96%AD%E3%82%92%E5%9B%BA%E5%AE%9A%E3%81%99%E3%82%8B%E6%9C%80%E5%BE%8C%E3%81%AE%E7%A0%A6\"\u003eテストは、判断を固定する最後の砦\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%82%92%E6%9B%B8%E3%81%8B%E3%81%AA%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%AF%E5%BF%85%E3%81%9A%E5%8F%A3%E9%A0%AD%E8%AA%AC%E6%98%8E%E3%81%AB%E6%88%BB%E3%82%8B\"\u003e判断を書かない設計は、必ず口頭説明に戻る\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"判断の軸をコードの外に逃がさない\"\u003e判断の軸を、コードの外に逃がさない\u003c/h2\u003e\n\u003chr\u003e\n\u003cp\u003e判断の軸が重要だ、\u003cbr\u003e\nという話までは、\u003cbr\u003e\n多くのエンジニアが同意します。\u003c/p\u003e\n\u003cp\u003e問題は、その次です。\u003c/p\u003e\n\u003cp\u003e判断の軸は、\u003cbr\u003e\nどこに置けばよいのでしょうか。\u003c/p\u003e\n\u003cp\u003e頭の中でしょうか。\u003cbr\u003e\n設計ドキュメントでしょうか。\u003cbr\u003e\nコードでしょうか。\u003c/p\u003e\n\u003cp\u003eこの章では、\u003cbr\u003e\n判断の軸を「消えにくい形」で残す方法を考えます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"軸が失われる一番の理由\"\u003e軸が失われる一番の理由\u003c/h3\u003e\n\u003cp\u003e判断の軸が失われる理由は、\u003cbr\u003e\n実はとても単純です。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e軸が、コードの外にあるからです。\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eドキュメント\u003c/li\u003e\n\u003cli\u003eWiki\u003c/li\u003e\n\u003cli\u003e設計資料\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eそれらは悪ではありません。\u003c/p\u003e\n\u003cp\u003eしかし、\u003cbr\u003e\nコードと更新タイミングがズレた瞬間、\u003cbr\u003e\n信頼されなくなります。\u003c/p\u003e\n\u003cp\u003e結果として、\u003cbr\u003e\n人はコードだけを見るようになります。\u003c/p\u003e\n\u003cp\u003eそしてコードの中に、\u003cbr\u003e\n判断の理由が見つからなくなります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断は読む人が必ず通る場所に置く\"\u003e判断は「読む人が必ず通る場所」に置く\u003c/h3\u003e\n\u003cp\u003e判断の軸を残すための原則は、\u003cbr\u003e\n一つだけです。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e読む人が、必ず通る場所に置くこと。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e誰も読まないドキュメントに、\u003cbr\u003e\n重要な判断を書いても意味はありません。\u003c/p\u003e\n\u003cp\u003e一方で、\u003cbr\u003e\n必ず読まれる場所があります。\u003c/p\u003e\n\u003cp\u003eそれは、\u003cbr\u003e\nコードです。\u003c/p\u003e\n\u003cp\u003e正確には、\u003cbr\u003e\nコードを理解するために、\u003cbr\u003e\n必ず目に入る構造です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"命名は判断を閉じ込める最初の手段\"\u003e命名は、判断を閉じ込める最初の手段\u003c/h3\u003e\n\u003cp\u003eもっとも軽く、\u003cbr\u003e\nもっとも効果的な方法は、\u003cbr\u003e\n命名です。\u003c/p\u003e\n\u003cp\u003eなぜこのクラスが存在するのか。\u003cbr\u003e\nなぜこの責務が切り出されているのか。\u003c/p\u003e\n\u003cp\u003eそれが名前に現れていれば、\u003cbr\u003e\n読む人は自然に軸を追えます。\u003c/p\u003e\n\u003cp\u003e逆に、\u003cbr\u003e\n無難で抽象的な名前は、\u003cbr\u003e\n判断を隠します。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eManager\u003c/li\u003e\n\u003cli\u003eHelper\u003c/li\u003e\n\u003cli\u003eUtil\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは、\u003cbr\u003e\n判断を先送りにした結果です。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e命名は、判断を固定する行為です。\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"層を作ることは判断の担当を決めること\"\u003e層を作ることは、判断の担当を決めること\u003c/h3\u003e\n\u003cp\u003eレイヤー分割も、\u003cbr\u003e\n判断を残すための手段です。\u003c/p\u003e\n\u003cp\u003eどこで判断するのか。\u003cbr\u003e\nどこでは判断しないのか。\u003c/p\u003e","title":"第4章：判断の軸を、コードの外に逃がさない"},{"content":" この章で伝えたいこと 構造は「結果」であり「目的」ではない 判断が失われると、構造は硬直する 良い設計は「線を引く」行為である 判断をコードに残すという発想 まとめ この章で伝えたいこと 第2章・第3章では、構造を共通化しすぎた結果として起きる歪みや、モノリスが生まれる過程を見てきました。 本章では一段視点を上げ、「良い構造」を直接目指すのではなく、良い判断が積み重なった結果として構造が決まる という考え方を扱います。\n設計が破綻する現場では、多くの場合「判断」がコードの外に散らばり、後から追えなくなっています。 その結果、なぜこの構造になっているのか、どこまで壊してよいのかが分からなくなります。\n本章のゴールは、\n構造よりも判断に目を向ける 判断をコードに閉じ込める 将来の変更に耐えられる思考の軸を持つ この3点を理解することです。\n構造は「結果」であり「目的」ではない 設計の話になると、\nレイヤードにするか モジュールをどう切るか どこを共通化するか といった 構造そのもの に議論が集中しがちです。\nしかし実際には、構造はその時点での判断の積み重ねの結果にすぎません。\nなぜこの責務をここに置いたのか なぜこのクラスに依存させたのか なぜこの抽象を導入したのか これらの判断が変われば、同じ要件でも構造はまったく別の形になります。\n構造だけを真似しても、判断の前提が共有されていなければ、すぐに歪みが生まれます。\n判断が失われると、構造は硬直する モノリス化したコードベースでよく見られるのが、\nこのクラスを触っていいのか分からない どこまで変更してよいのか判断できない とりあえず既存の流れに合わせる という状態です。\nこれは「構造が悪い」以前に、 なぜその構造になったのかという判断が失われている ことが原因です。\n判断の背景が見えない構造は、\n壊すのが怖い 変更が最小限になる 例外処理が積み重なる 結果として、さらに判断不能な構造へと進化していきます。\n良い設計は「線を引く」行為である 設計とは、突き詰めると 線を引く行為 です。\nどこからどこまでがこの責務か ここから先は別の判断に委ねる このユースケースでは扱わない 線を引くということは、同時に「やらないこと」を決めることでもあります。\n線が引かれていない設計では、\n責務が広がり続ける 境界を越えた依存が増える 修正の影響範囲が読めなくなる という問題が必ず起きます。\n判断をコードに残すという発想 判断は、ドキュメントや頭の中に置いておくと必ず失われます。\nそこで重要になるのが、 判断をコードの形で残す という考え方です。\n型で制約する sealed class で分岐を限定する インターフェースで責務を分ける これらはすべて、 「こういう使われ方は想定していない」という判断をコードに刻む行為です。\n判断がコードに残っていれば、\n間違った使い方はコンパイル時に弾かれる 新しい要件が来たときに、線を引き直す場所が分かる 構造は自然と壊れにくくなります。\nまとめ 構造は設計の目的ではなく、判断の結果である 判断が失われると、構造は硬直し、モノリス化する 設計とは線を引き、責務と境界を明確にする行為である 判断はコードに残して初めて、将来に耐えられる 次章では、こうした「判断」をどのように分解し、チームで共有していくかを扱います。\n","permalink":"https://design.okuda-studio.com/books/003-design-that-locks-in-judgment/04-/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%A7%E4%BC%9D%E3%81%88%E3%81%9F%E3%81%84%E3%81%93%E3%81%A8\"\u003eこの章で伝えたいこと\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%A7%8B%E9%80%A0%E3%81%AF%E7%B5%90%E6%9E%9C%E3%81%A7%E3%81%82%E3%82%8A%E7%9B%AE%E7%9A%84%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e構造は「結果」であり「目的」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%8C%E5%A4%B1%E3%82%8F%E3%82%8C%E3%82%8B%E3%81%A8%E6%A7%8B%E9%80%A0%E3%81%AF%E7%A1%AC%E7%9B%B4%E3%81%99%E3%82%8B\"\u003e判断が失われると、構造は硬直する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%AF%E7%B7%9A%E3%82%92%E5%BC%95%E3%81%8F%E8%A1%8C%E7%82%BA%E3%81%A7%E3%81%82%E3%82%8B\"\u003e良い設計は「線を引く」行為である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%82%92%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AB%E6%AE%8B%E3%81%99%E3%81%A8%E3%81%84%E3%81%86%E7%99%BA%E6%83%B3\"\u003e判断をコードに残すという発想\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"この章で伝えたいこと\"\u003eこの章で伝えたいこと\u003c/h3\u003e\n\u003cp\u003e第2章・第3章では、構造を共通化しすぎた結果として起きる歪みや、モノリスが生まれる過程を見てきました。\n本章では一段視点を上げ、「良い構造」を直接目指すのではなく、\u003cstrong\u003e良い判断が積み重なった結果として構造が決まる\u003c/strong\u003e という考え方を扱います。\u003c/p\u003e\n\u003cp\u003e設計が破綻する現場では、多くの場合「判断」がコードの外に散らばり、後から追えなくなっています。\nその結果、なぜこの構造になっているのか、どこまで壊してよいのかが分からなくなります。\u003c/p\u003e\n\u003cp\u003e本章のゴールは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e構造よりも判断に目を向ける\u003c/li\u003e\n\u003cli\u003e判断をコードに閉じ込める\u003c/li\u003e\n\u003cli\u003e将来の変更に耐えられる思考の軸を持つ\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの3点を理解することです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"構造は結果であり目的ではない\"\u003e構造は「結果」であり「目的」ではない\u003c/h3\u003e\n\u003cp\u003e設計の話になると、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eレイヤードにするか\u003c/li\u003e\n\u003cli\u003eモジュールをどう切るか\u003c/li\u003e\n\u003cli\u003eどこを共通化するか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった \u003cstrong\u003e構造そのもの\u003c/strong\u003e に議論が集中しがちです。\u003c/p\u003e\n\u003cp\u003eしかし実際には、構造はその時点での判断の積み重ねの結果にすぎません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eなぜこの責務をここに置いたのか\u003c/li\u003e\n\u003cli\u003eなぜこのクラスに依存させたのか\u003c/li\u003e\n\u003cli\u003eなぜこの抽象を導入したのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらの判断が変われば、同じ要件でも構造はまったく別の形になります。\u003c/p\u003e\n\u003cp\u003e構造だけを真似しても、判断の前提が共有されていなければ、すぐに歪みが生まれます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断が失われると構造は硬直する\"\u003e判断が失われると、構造は硬直する\u003c/h3\u003e\n\u003cp\u003eモノリス化したコードベースでよく見られるのが、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこのクラスを触っていいのか分からない\u003c/li\u003e\n\u003cli\u003eどこまで変更してよいのか判断できない\u003c/li\u003e\n\u003cli\u003eとりあえず既存の流れに合わせる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという状態です。\u003c/p\u003e\n\u003cp\u003eこれは「構造が悪い」以前に、\n\u003cstrong\u003eなぜその構造になったのかという判断が失われている\u003c/strong\u003e ことが原因です。\u003c/p\u003e\n\u003cp\u003e判断の背景が見えない構造は、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e壊すのが怖い\u003c/li\u003e\n\u003cli\u003e変更が最小限になる\u003c/li\u003e\n\u003cli\u003e例外処理が積み重なる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e結果として、さらに判断不能な構造へと進化していきます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"良い設計は線を引く行為である\"\u003e良い設計は「線を引く」行為である\u003c/h3\u003e\n\u003cp\u003e設計とは、突き詰めると \u003cstrong\u003e線を引く行為\u003c/strong\u003e です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどこからどこまでがこの責務か\u003c/li\u003e\n\u003cli\u003eここから先は別の判断に委ねる\u003c/li\u003e\n\u003cli\u003eこのユースケースでは扱わない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e線を引くということは、同時に「やらないこと」を決めることでもあります。\u003c/p\u003e\n\u003cp\u003e線が引かれていない設計では、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e責務が広がり続ける\u003c/li\u003e\n\u003cli\u003e境界を越えた依存が増える\u003c/li\u003e\n\u003cli\u003e修正の影響範囲が読めなくなる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという問題が必ず起きます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断をコードに残すという発想\"\u003e判断をコードに残すという発想\u003c/h3\u003e\n\u003cp\u003e判断は、ドキュメントや頭の中に置いておくと必ず失われます。\u003c/p\u003e\n\u003cp\u003eそこで重要になるのが、\n\u003cstrong\u003e判断をコードの形で残す\u003c/strong\u003e という考え方です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e型で制約する\u003c/li\u003e\n\u003cli\u003esealed class で分岐を限定する\u003c/li\u003e\n\u003cli\u003eインターフェースで責務を分ける\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらはすべて、\n「こういう使われ方は想定していない」という判断をコードに刻む行為です。\u003c/p\u003e","title":"第4章：構造ではなく「判断」を設計する"},{"content":" 状態とは、「今、何が許されているか」である 判断は、必ず状態に依存する 状態が曖昧だと、判断が漏れ出す 良い状態設計は、「ありえない状況」を消す 状態を構造で表現する、ということ 状態を構造で表現できていないコードの兆候 状態設計は、設計の中核である この章のまとめ 第3章では、 判断を人に持たせるのではなく、 構造で表現する ことが設計だと述べました。\nでは、その判断は、 構造の中で どんな形 を取るのでしょうか。\nその答えが、 状態 です。\n状態とは、「今、何が許されているか」である 本書で言う状態とは、\n変数の値 フラグの on / off データの有無 といった、 表面的な話ではありません。\n状態とは、\n「今、このコードは何をしてよくて、何をしてはいけないか」 を表すものです。\nたとえば、\n今はまだ送信してはいけない もう変更してはいけない ここから先は読み取り専用である この操作は一度しか許されない こうした判断が、 暗黙の了解ではなく、 コードとして表現されているかどうか\nそれが、 状態設計の良し悪しを分けます。\n判断は、必ず状態に依存する 第3章で扱った判断は、 必ず何かに依存していました。\nこの順番で呼んでよいのか 今、この処理をしてよいのか この値を変更してよいのか これらはすべて、\n「今がどんな状態か」 によって決まります。\nつまり、\n判断を構造で表現する 状態を構造で表現する この二つは、 実は 同じ話を違う角度から見ている だけです。\n状態が曖昧だと、判断が漏れ出す 状態がはっきり定義されていないコードでは、 判断が漏れ出します。\nnull かもしれない 呼ばれる順番は暗黙 途中の状態が存在するかどうかわからない このときコードは、\nif を増やして守る コメントで注意書きをする テストで網を張る という方向に進みます。\nしかしそれは、\n状態を構造で表現できていない という問題の結果にすぎません。\n良い状態設計は、「ありえない状況」を消す 良い状態設計の目的は、 状態を増やすことではありません。\nありえない状態を、表現できなくすること です。\nまだ準備できていないのに実行できる 完了しているのに再実行できる 必須の値がないのに処理が進められる こうした状況を、\nif で防ぐ のではなく 構造として存在しない ようにします。\nその結果、 判断は自然と減っていきます。\n状態を構造で表現する、ということ 状態を構造で表現するとは、\n状態ごとにできる操作を限定する 状態が変わるタイミングを限定する 状態の組み合わせを制限する ということです。\nこれは、\n「ちゃんと使えば大丈夫」 ではなく 「間違って使えない」 という設計を意味します。\n状態が構造に落ちていれば、 判断はそこから外に出てきません。\n状態を構造で表現できていないコードの兆候 次のようなコードは、 状態設計が弱い可能性があります。\nBoolean フラグが増え続ける null チェックがあちこちにある 「この場合だけ特別」が多い 呼び出し順をコメントで説明している これらはすべて、\n状態を、人が握っている サインです。\n状態設計は、設計の中核である 判断を構造で表現する。 その最も強力な手段が、 状態設計です。\n判断が減り if が減り 読むときに考えることが減る それは、 コードが単純になったからではありません。\n判断を、状態として引き受けたから です。\nこの章のまとめ 判断は、必ず状態に依存する 状態が曖昧だと、判断がコードの外に漏れ出す 良い設計は、状態を構造で表現する 状態設計は、判断を減らすための設計である 次の章では、 この「状態」を、\n型 API オブジェクト ライフサイクル といった、 具体的な構造 に どう落とし込んでいくかを見ていきます。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/04-what-is-the-state/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E3%81%A8%E3%81%AF%E4%BB%8A%E4%BD%95%E3%81%8C%E8%A8%B1%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E3%81%8B%E3%81%A7%E3%81%82%E3%82%8B\"\u003e状態とは、「今、何が許されているか」である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AF%E5%BF%85%E3%81%9A%E7%8A%B6%E6%85%8B%E3%81%AB%E4%BE%9D%E5%AD%98%E3%81%99%E3%82%8B\"\u003e判断は、必ず状態に依存する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E3%81%8C%E6%9B%96%E6%98%A7%E3%81%A0%E3%81%A8%E5%88%A4%E6%96%AD%E3%81%8C%E6%BC%8F%E3%82%8C%E5%87%BA%E3%81%99\"\u003e状態が曖昧だと、判断が漏れ出す\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E7%8A%B6%E6%85%8B%E8%A8%AD%E8%A8%88%E3%81%AF%E3%81%82%E3%82%8A%E3%81%88%E3%81%AA%E3%81%84%E7%8A%B6%E6%B3%81%E3%82%92%E6%B6%88%E3%81%99\"\u003e良い状態設計は、「ありえない状況」を消す\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E3%82%92%E6%A7%8B%E9%80%A0%E3%81%A7%E8%A1%A8%E7%8F%BE%E3%81%99%E3%82%8B%E3%81%A8%E3%81%84%E3%81%86%E3%81%93%E3%81%A8\"\u003e状態を構造で表現する、ということ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E3%82%92%E6%A7%8B%E9%80%A0%E3%81%A7%E8%A1%A8%E7%8F%BE%E3%81%A7%E3%81%8D%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E5%85%86%E5%80%99\"\u003e状態を構造で表現できていないコードの兆候\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E8%A8%AD%E8%A8%88%E3%81%AF%E8%A8%AD%E8%A8%88%E3%81%AE%E4%B8%AD%E6%A0%B8%E3%81%A7%E3%81%82%E3%82%8B\"\u003e状態設計は、設計の中核である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e第3章では、\n判断を人に持たせるのではなく、\n\u003cstrong\u003e構造で表現する\u003c/strong\u003e ことが設計だと述べました。\u003c/p\u003e\n\u003cp\u003eでは、その判断は、\n構造の中で \u003cstrong\u003eどんな形\u003c/strong\u003e を取るのでしょうか。\u003c/p\u003e\n\u003cp\u003eその答えが、 \u003cstrong\u003e状態\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"状態とは今何が許されているかである\"\u003e状態とは、「今、何が許されているか」である\u003c/h2\u003e\n\u003cp\u003e本書で言う状態とは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e変数の値\u003c/li\u003e\n\u003cli\u003eフラグの on / off\u003c/li\u003e\n\u003cli\u003eデータの有無\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった、\n表面的な話ではありません。\u003c/p\u003e\n\u003cp\u003e状態とは、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e「今、このコードは何をしてよくて、何をしてはいけないか」\u003c/strong\u003e\nを表すものです。\u003c/p\u003e\n\u003cp\u003eたとえば、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e今はまだ送信してはいけない\u003c/li\u003e\n\u003cli\u003eもう変更してはいけない\u003c/li\u003e\n\u003cli\u003eここから先は読み取り専用である\u003c/li\u003e\n\u003cli\u003eこの操作は一度しか許されない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうした判断が、\n暗黙の了解ではなく、\n\u003cstrong\u003eコードとして表現されているかどうか\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eそれが、\n状態設計の良し悪しを分けます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"判断は必ず状態に依存する\"\u003e判断は、必ず状態に依存する\u003c/h2\u003e\n\u003cp\u003e第3章で扱った判断は、\n必ず何かに依存していました。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこの順番で呼んでよいのか\u003c/li\u003e\n\u003cli\u003e今、この処理をしてよいのか\u003c/li\u003e\n\u003cli\u003eこの値を変更してよいのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらはすべて、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e「今がどんな状態か」\u003c/strong\u003e\nによって決まります。\u003c/p\u003e\n\u003cp\u003eつまり、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e判断を構造で表現する\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e状態を構造で表現する\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの二つは、\n実は \u003cstrong\u003e同じ話を違う角度から見ている\u003c/strong\u003e だけです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"状態が曖昧だと判断が漏れ出す\"\u003e状態が曖昧だと、判断が漏れ出す\u003c/h2\u003e\n\u003cp\u003e状態がはっきり定義されていないコードでは、\n判断が漏れ出します。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003enull かもしれない\u003c/li\u003e\n\u003cli\u003e呼ばれる順番は暗黙\u003c/li\u003e\n\u003cli\u003e途中の状態が存在するかどうかわからない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこのときコードは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eif を増やして守る\u003c/li\u003e\n\u003cli\u003eコメントで注意書きをする\u003c/li\u003e\n\u003cli\u003eテストで網を張る\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという方向に進みます。\u003c/p\u003e","title":"第4章：状態とは何か"},{"content":" 壊れやすさは、構造ではなく判断の偏りから生まれる 典型的な三つの偏り 「今きれいであること」を優先しすぎる 「将来どうせ変わる」を理由に判断を放棄する 「自分が分かっている」前提で判断を外に漏らす 健全な設計は、偏りを自覚して選び直すことから始まる 壊れやすさに気づける設計者になる ここまでの章で、設計とは「判断をどこに閉じ込めるか」であり、 そして判断は必ず変わる、という前提に立つ必要があることを見てきました。\nでは、次の問いに進みます。\nなぜ、現場では壊れやすい設計が繰り返し生まれてしまうのでしょうか。\nこの章では、技術力不足や経験不足といった分かりやすい理由ではなく、 設計者が無意識に選んでしまう判断の置き方 に注目します。\nこれは誰かを責める章ではありません。 むしろ、自分自身が何度も陥ってきたパターンを言語化する章です。\n壊れやすさは、構造ではなく判断の偏りから生まれる 壊れやすい設計を見ると、つい構造に目が向きがちです。\nクラスが大きすぎる 責務が多すぎる 共通化しすぎている しかし、これらはすべて「結果」にすぎません。\nその前段には必ず、\nどの判断を重要だと見なしたか どの判断を軽視したか どの判断を将来に押し付けたか という偏りがあります。\n壊れやすい設計とは、 一部の判断だけを過度に優先した設計 だと言い換えることができます。\n典型的な三つの偏り 壊れやすい設計に共通する判断の偏りは、いくつかの型に分けられます。 ここでは特に遭遇頻度の高い三つを取り上げます。\n「今きれいであること」を優先しすぎる 最もよくあるのが、この偏りです。\n重複は悪だ 抽象化は善だ 共通化すれば美しい こうした価値観自体は間違っていません。 問題は、将来の判断の変化よりも、現在の見た目の整合性を優先してしまう ことです。\n結果として、\nまだ揃っていないものを無理に揃える 違いが見えていない段階で共通化する 変更理由の異なる処理を一箇所に集める といった構造が生まれます。\nこれは「きれいに設計したつもり」で壊れやすくする、典型例です。\n「将来どうせ変わる」を理由に判断を放棄する 逆方向の偏りも存在します。\nどうせ仕様は変わる 先のことは分からない 今はとりあえず動けばいい この考え方が行き過ぎると、 判断そのものを行わない設計 になります。\n境界を引かない 責務を定義しない 型や制約を置かない 結果として、 変更が起きた瞬間に「全部を考え直す」必要が出てきます。\n「将来に備えない」のではなく、 将来に備えるための最小限の判断すら閉じ込めていない 状態です。\n「自分が分かっている」前提で判断を外に漏らす 三つ目は、設計者本人には気づきにくい偏りです。\nこれは普通こうだよね このクラスはそういう前提だから 使う側が気をつければいい こうした前提は、コードの外に存在します。\nつまり、\n型で表現されない 境界として切り出されない 名前にも表れない 判断です。\nこの状態では、 設計は設計者の頭の中にしか存在しません。\n人が変わった瞬間、 あるいは時間が経った瞬間に、 設計は事実上失われます。\n健全な設計は、偏りを自覚して選び直すことから始まる ここまで挙げた三つの偏りは、 どれか一つが絶対に悪いというものではありません。\n今を優先する判断が必要な場面もある 将来を見ない決断が合理的なこともある 暗黙知で進めた方が速い局面もある 問題は、 その偏りを自覚しないまま固定化してしまうこと です。\n設計とは、 毎回バランスを取り直す行為です。\n今と将来 明示と暗黙 柔軟性と制約 これらの間で、 「今回はどこに判断を置くか」を選び続けることが設計です。\n壊れやすさに気づける設計者になる 壊れやすい設計を完全に避けることはできません。\nしかし、\nなぜ今この設計が壊れやすいのか どの判断が偏っているのか 次に変わるとしたらどこか を説明できる設計者になることはできます。\nその時点で、 設計は「失敗」ではなく「途中経過」になります。\n次の章では、 こうした壊れやすさとどう付き合い、 どう回収していくかについて掘り下げていきます。\nここから先は、 設計を壊す話 です。\n","permalink":"https://design.okuda-studio.com/books/003-design-that-locks-in-judgment/05-/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A3%8A%E3%82%8C%E3%82%84%E3%81%99%E3%81%95%E3%81%AF%E6%A7%8B%E9%80%A0%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%E5%88%A4%E6%96%AD%E3%81%AE%E5%81%8F%E3%82%8A%E3%81%8B%E3%82%89%E7%94%9F%E3%81%BE%E3%82%8C%E3%82%8B\"\u003e壊れやすさは、構造ではなく判断の偏りから生まれる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%85%B8%E5%9E%8B%E7%9A%84%E3%81%AA%E4%B8%89%E3%81%A4%E3%81%AE%E5%81%8F%E3%82%8A\"\u003e典型的な三つの偏り\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BB%8A%E3%81%8D%E3%82%8C%E3%81%84%E3%81%A7%E3%81%82%E3%82%8B%E3%81%93%E3%81%A8%E3%82%92%E5%84%AA%E5%85%88%E3%81%97%E3%81%99%E3%81%8E%E3%82%8B\"\u003e「今きれいであること」を優先しすぎる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%B0%86%E6%9D%A5%E3%81%A9%E3%81%86%E3%81%9B%E5%A4%89%E3%82%8F%E3%82%8B%E3%82%92%E7%90%86%E7%94%B1%E3%81%AB%E5%88%A4%E6%96%AD%E3%82%92%E6%94%BE%E6%A3%84%E3%81%99%E3%82%8B\"\u003e「将来どうせ変わる」を理由に判断を放棄する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%87%AA%E5%88%86%E3%81%8C%E5%88%86%E3%81%8B%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E5%89%8D%E6%8F%90%E3%81%A7%E5%88%A4%E6%96%AD%E3%82%92%E5%A4%96%E3%81%AB%E6%BC%8F%E3%82%89%E3%81%99\"\u003e「自分が分かっている」前提で判断を外に漏らす\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%81%A5%E5%85%A8%E3%81%AA%E8%A8%AD%E8%A8%88%E3%81%AF%E5%81%8F%E3%82%8A%E3%82%92%E8%87%AA%E8%A6%9A%E3%81%97%E3%81%A6%E9%81%B8%E3%81%B3%E7%9B%B4%E3%81%99%E3%81%93%E3%81%A8%E3%81%8B%E3%82%89%E5%A7%8B%E3%81%BE%E3%82%8B\"\u003e健全な設計は、偏りを自覚して選び直すことから始まる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A3%8A%E3%82%8C%E3%82%84%E3%81%99%E3%81%95%E3%81%AB%E6%B0%97%E3%81%A5%E3%81%91%E3%82%8B%E8%A8%AD%E8%A8%88%E8%80%85%E3%81%AB%E3%81%AA%E3%82%8B\"\u003e壊れやすさに気づける設計者になる\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eここまでの章で、設計とは「判断をどこに閉じ込めるか」であり、\nそして判断は必ず変わる、という前提に立つ必要があることを見てきました。\u003c/p\u003e\n\u003cp\u003eでは、次の問いに進みます。\u003c/p\u003e\n\u003cp\u003eなぜ、現場では壊れやすい設計が繰り返し生まれてしまうのでしょうか。\u003c/p\u003e\n\u003cp\u003eこの章では、技術力不足や経験不足といった分かりやすい理由ではなく、\n\u003cstrong\u003e設計者が無意識に選んでしまう判断の置き方\u003c/strong\u003e に注目します。\u003c/p\u003e\n\u003cp\u003eこれは誰かを責める章ではありません。\nむしろ、自分自身が何度も陥ってきたパターンを言語化する章です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"壊れやすさは構造ではなく判断の偏りから生まれる\"\u003e壊れやすさは、構造ではなく判断の偏りから生まれる\u003c/h3\u003e\n\u003cp\u003e壊れやすい設計を見ると、つい構造に目が向きがちです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eクラスが大きすぎる\u003c/li\u003e\n\u003cli\u003e責務が多すぎる\u003c/li\u003e\n\u003cli\u003e共通化しすぎている\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eしかし、これらはすべて「結果」にすぎません。\u003c/p\u003e\n\u003cp\u003eその前段には必ず、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどの判断を重要だと見なしたか\u003c/li\u003e\n\u003cli\u003eどの判断を軽視したか\u003c/li\u003e\n\u003cli\u003eどの判断を将来に押し付けたか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという偏りがあります。\u003c/p\u003e\n\u003cp\u003e壊れやすい設計とは、\n\u003cstrong\u003e一部の判断だけを過度に優先した設計\u003c/strong\u003e だと言い換えることができます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"典型的な三つの偏り\"\u003e典型的な三つの偏り\u003c/h3\u003e\n\u003cp\u003e壊れやすい設計に共通する判断の偏りは、いくつかの型に分けられます。\nここでは特に遭遇頻度の高い三つを取り上げます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"今きれいであることを優先しすぎる\"\u003e「今きれいであること」を優先しすぎる\u003c/h3\u003e\n\u003cp\u003e最もよくあるのが、この偏りです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e重複は悪だ\u003c/li\u003e\n\u003cli\u003e抽象化は善だ\u003c/li\u003e\n\u003cli\u003e共通化すれば美しい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうした価値観自体は間違っていません。\n問題は、\u003cstrong\u003e将来の判断の変化よりも、現在の見た目の整合性を優先してしまう\u003c/strong\u003e ことです。\u003c/p\u003e\n\u003cp\u003e結果として、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eまだ揃っていないものを無理に揃える\u003c/li\u003e\n\u003cli\u003e違いが見えていない段階で共通化する\u003c/li\u003e\n\u003cli\u003e変更理由の異なる処理を一箇所に集める\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった構造が生まれます。\u003c/p\u003e\n\u003cp\u003eこれは「きれいに設計したつもり」で壊れやすくする、典型例です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"将来どうせ変わるを理由に判断を放棄する\"\u003e「将来どうせ変わる」を理由に判断を放棄する\u003c/h3\u003e\n\u003cp\u003e逆方向の偏りも存在します。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどうせ仕様は変わる\u003c/li\u003e\n\u003cli\u003e先のことは分からない\u003c/li\u003e\n\u003cli\u003e今はとりあえず動けばいい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの考え方が行き過ぎると、\n\u003cstrong\u003e判断そのものを行わない設計\u003c/strong\u003e になります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e境界を引かない\u003c/li\u003e\n\u003cli\u003e責務を定義しない\u003c/li\u003e\n\u003cli\u003e型や制約を置かない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e結果として、\n変更が起きた瞬間に「全部を考え直す」必要が出てきます。\u003c/p\u003e\n\u003cp\u003e「将来に備えない」のではなく、\n\u003cstrong\u003e将来に備えるための最小限の判断すら閉じ込めていない\u003c/strong\u003e 状態です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"自分が分かっている前提で判断を外に漏らす\"\u003e「自分が分かっている」前提で判断を外に漏らす\u003c/h3\u003e\n\u003cp\u003e三つ目は、設計者本人には気づきにくい偏りです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこれは普通こうだよね\u003c/li\u003e\n\u003cli\u003eこのクラスはそういう前提だから\u003c/li\u003e\n\u003cli\u003e使う側が気をつければいい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうした前提は、コードの外に存在します。\u003c/p\u003e\n\u003cp\u003eつまり、\u003c/p\u003e","title":"第5章：壊れやすい設計は、なぜ生まれるのか"},{"content":" 失われた判断を、既存コードから読み解く 最初にやってはいけないこと コードは、判断の痕跡でできている 「変えにくい場所」から見る 不自然な一貫性を探す 変更履歴は、判断の化石層である 軸は「正解」ではなく「現実」から見つける この章のまとめ 失われた判断を、既存コードから読み解く 設計の話をすると、\nしばしばこう言われます、\n「それは新規開発だからできた話ですよね」、\n既にコードがあり、\n既にモノリスになっていて、\n既に判断が失われている場合、\nどうすればよいのでしょうか、\nこの章では、\n今あるコードを出発点として、 判断の軸を見つけ直す方法を扱います、\n最初にやってはいけないこと 既存コードを前にしたとき、\n多くのエンジニアが最初にやりがちなことがあります、\nそれは、\n「理想的な構造」を思い描くことです、\nレイヤーを引き直す、\n責務を整理する、\nきれいなアーキテクチャに作り替える、\n気持ちはよく分かります、\nしかし、このアプローチはほぼ確実に失敗します、\nなぜなら、\n現状の判断を理解しないまま、 別の判断を上書きしようとするからです、\nコードは、判断の痕跡でできている どれだけ荒れて見えるコードでも、\nそこには必ず判断の痕跡があります、\n意味の分からない条件分岐、\n不自然な責務の集まり、\nやたらと慎重なガード、\nそれらは偶然ではありません、\n誰かが、\n何かを恐れ、\n何かを避け、\n何かを守ろうとした結果です、\nコードは、過去の判断の集合体です、\n「変えにくい場所」から見る 判断の軸を探すとき、\nまず注目すべき場所があります、\nそれは、\n誰も触りたがらない場所です、\n変更すると壊れそう、\n影響範囲が読めない、\nテストがなくて怖い、\nこうした場所には、\n強い判断が眠っています、\nなぜここは、\nこんなにも慎重に扱われているのか、\nその理由を考えることが、\n軸を見つける第一歩です、\n不自然な一貫性を探す もう一つ、\n有効な手がかりがあります、\nそれは、\n不自然なほど一貫している部分です、\n毎回同じチェックをしている、\n似たような変換が何度も出てくる、\n例外処理の方針が妙に揃っている、\nそれは、\n偶然ではありません、\n誰かが、\n「ここだけは揺らがせない」と 決めた可能性があります、\n軸は、繰り返しの中に現れます、\n変更履歴は、判断の化石層である もし可能であれば、\n変更履歴も確認してください、\nどんな修正が、\nどこに集中しているか、\n何度も直されている場所は、\n判断が揺れている場所です、\n逆に、\nほとんど触られていない場所は、\n長く守られてきた判断を含んでいます、\n履歴は、判断の地層です、\n軸は「正解」ではなく「現実」から見つける ここで重要なことがあります、\n見つけようとしているのは、\n理想の判断軸ではありません、\nこのコードベースが、 実際に選んできた判断です、\nそれが未熟に見えても、\n歪んでいても、\n今の現実です、\n設計とは、\n現実を否定することではありません、\n現実を理解した上で、\n次の判断を重ねることです、\nこの章のまとめ 既存コードに、\n判断が「ない」ことはありません、\n見えなくなっているだけです、\n変えにくい場所、\n不自然な一貫性、\n長く守られてきた構造、\nそこには、\n必ず判断の軸があります、\n次の章では、\nこの見つけ出した軸を使って、\nどうやって最初の一手を打つのかを 具体的に扱います、\nつまり、 「どこから直し始めるのか」です、\n","permalink":"https://design.okuda-studio.com/books/002-design-starts-with-decisions/05-deciphering-lost-decisions/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A4%B1%E3%82%8F%E3%82%8C%E3%81%9F%E5%88%A4%E6%96%AD%E3%82%92%E6%97%A2%E5%AD%98%E3%82%B3%E3%83%BC%E3%83%89%E3%81%8B%E3%82%89%E8%AA%AD%E3%81%BF%E8%A7%A3%E3%81%8F\"\u003e失われた判断を、既存コードから読み解く\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9C%80%E5%88%9D%E3%81%AB%E3%82%84%E3%81%A3%E3%81%A6%E3%81%AF%E3%81%84%E3%81%91%E3%81%AA%E3%81%84%E3%81%93%E3%81%A8\"\u003e最初にやってはいけないこと\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%AE%E7%97%95%E8%B7%A1%E3%81%A7%E3%81%A7%E3%81%8D%E3%81%A6%E3%81%84%E3%82%8B\"\u003eコードは、判断の痕跡でできている\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A4%89%E3%81%88%E3%81%AB%E3%81%8F%E3%81%84%E5%A0%B4%E6%89%80%E3%81%8B%E3%82%89%E8%A6%8B%E3%82%8B\"\u003e「変えにくい場所」から見る\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%B8%8D%E8%87%AA%E7%84%B6%E3%81%AA%E4%B8%80%E8%B2%AB%E6%80%A7%E3%82%92%E6%8E%A2%E3%81%99\"\u003e不自然な一貫性を探す\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A4%89%E6%9B%B4%E5%B1%A5%E6%AD%B4%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%AE%E5%8C%96%E7%9F%B3%E5%B1%A4%E3%81%A7%E3%81%82%E3%82%8B\"\u003e変更履歴は、判断の化石層である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%BB%B8%E3%81%AF%E6%AD%A3%E8%A7%A3%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%E7%8F%BE%E5%AE%9F%E3%81%8B%E3%82%89%E8%A6%8B%E3%81%A4%E3%81%91%E3%82%8B\"\u003e軸は「正解」ではなく「現実」から見つける\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"失われた判断を既存コードから読み解く\"\u003e失われた判断を、既存コードから読み解く\u003c/h2\u003e\n\u003chr\u003e\n\u003cp\u003e設計の話をすると、\u003cbr\u003e\nしばしばこう言われます、\u003cbr\u003e\n「それは新規開発だからできた話ですよね」、\u003c/p\u003e\n\u003cp\u003e既にコードがあり、\u003cbr\u003e\n既にモノリスになっていて、\u003cbr\u003e\n既に判断が失われている場合、\u003cbr\u003e\nどうすればよいのでしょうか、\u003c/p\u003e\n\u003cp\u003eこの章では、\u003cbr\u003e\n\u003cstrong\u003e今あるコードを出発点として、\n判断の軸を見つけ直す方法\u003c/strong\u003eを扱います、\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"最初にやってはいけないこと\"\u003e最初にやってはいけないこと\u003c/h3\u003e\n\u003cp\u003e既存コードを前にしたとき、\u003cbr\u003e\n多くのエンジニアが最初にやりがちなことがあります、\u003c/p\u003e\n\u003cp\u003eそれは、\u003cbr\u003e\n「理想的な構造」を思い描くことです、\u003c/p\u003e\n\u003cp\u003eレイヤーを引き直す、\u003cbr\u003e\n責務を整理する、\u003cbr\u003e\nきれいなアーキテクチャに作り替える、\u003c/p\u003e\n\u003cp\u003e気持ちはよく分かります、\u003cbr\u003e\nしかし、このアプローチはほぼ確実に失敗します、\u003c/p\u003e\n\u003cp\u003eなぜなら、\u003cbr\u003e\n\u003cstrong\u003e現状の判断を理解しないまま、\n別の判断を上書きしようとするから\u003c/strong\u003eです、\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"コードは判断の痕跡でできている\"\u003eコードは、判断の痕跡でできている\u003c/h3\u003e\n\u003cp\u003eどれだけ荒れて見えるコードでも、\u003cbr\u003e\nそこには必ず判断の痕跡があります、\u003c/p\u003e\n\u003cp\u003e意味の分からない条件分岐、\u003cbr\u003e\n不自然な責務の集まり、\u003cbr\u003e\nやたらと慎重なガード、\u003c/p\u003e\n\u003cp\u003eそれらは偶然ではありません、\u003c/p\u003e\n\u003cp\u003e誰かが、\u003cbr\u003e\n何かを恐れ、\u003cbr\u003e\n何かを避け、\u003cbr\u003e\n何かを守ろうとした結果です、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eコードは、過去の判断の集合体です、\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"変えにくい場所から見る\"\u003e「変えにくい場所」から見る\u003c/h3\u003e\n\u003cp\u003e判断の軸を探すとき、\u003cbr\u003e\nまず注目すべき場所があります、\u003c/p\u003e\n\u003cp\u003eそれは、\u003cbr\u003e\n\u003cstrong\u003e誰も触りたがらない場所\u003c/strong\u003eです、\u003c/p\u003e\n\u003cp\u003e変更すると壊れそう、\u003cbr\u003e\n影響範囲が読めない、\u003cbr\u003e\nテストがなくて怖い、\u003c/p\u003e\n\u003cp\u003eこうした場所には、\u003cbr\u003e\n強い判断が眠っています、\u003c/p\u003e\n\u003cp\u003eなぜここは、\u003cbr\u003e\nこんなにも慎重に扱われているのか、\u003c/p\u003e\n\u003cp\u003eその理由を考えることが、\u003cbr\u003e\n軸を見つける第一歩です、\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"不自然な一貫性を探す\"\u003e不自然な一貫性を探す\u003c/h3\u003e\n\u003cp\u003eもう一つ、\u003cbr\u003e\n有効な手がかりがあります、\u003c/p\u003e\n\u003cp\u003eそれは、\u003cbr\u003e\n\u003cstrong\u003e不自然なほど一貫している部分\u003c/strong\u003eです、\u003c/p\u003e\n\u003cp\u003e毎回同じチェックをしている、\u003cbr\u003e\n似たような変換が何度も出てくる、\u003cbr\u003e\n例外処理の方針が妙に揃っている、\u003c/p\u003e\n\u003cp\u003eそれは、\u003cbr\u003e\n偶然ではありません、\u003c/p\u003e\n\u003cp\u003e誰かが、\u003cbr\u003e\n「ここだけは揺らがせない」と\n決めた可能性があります、\u003c/p\u003e","title":"第5章：失われた判断を、既存コードから読み解く"},{"content":" 振る舞いは「判断の結果」であり、書くものではない 振る舞いは「考える」ものではない 良い設計では、振る舞いは「選ばれている」 振る舞いを制御するのは「構造」 「書けない振る舞い」を作る 振る舞いが増えたら、設計を疑う この章のまとめ 振る舞いは「判断の結果」であり、書くものではない ここまでで、 判断は 人がその場で行うもの ではなく、 構造として先に固定されるべきもの だ、という話をしてきました。\nでは、構造に固定された判断は、 最終的にどこへ行き着くのでしょうか。\nそれが 振る舞い（behavior） です。\n振る舞いは「考える」ものではない 設計が弱いコードでは、 振る舞いは次のように書かれます。\nif / when で分岐する 状態を見て都度判断する 条件が増えるたびに分岐が増える このとき、プログラムは常に 「今、どう動くべきか？」 を 実行時に考え続けている 状態になります。\nこれは一見、自然に見えます。 しかし設計として見ると、これは負けています。\nなぜなら、\n振る舞いの正しさが 毎回の判断に依存している からです。\n良い設計では、振る舞いは「選ばれている」 設計されたコードでは、 振る舞いは 書かれるもの ではありません。\nすでに選ばれている のです。\nある状態になった時点で どの振る舞いが可能かは決まっている それ以外の振る舞いは、そもそも存在しない つまり、\n「どう動くか」を考える必要がない\n状態が確定した瞬間に、 実行できる振る舞いも一意に確定する これが設計された状態です。\n振る舞いを制御するのは「構造」 ここで重要なのは、 振る舞いを縛っているのが、\nif 文 フラグ コメント 運用ルール ではない、という点です。\n縛っているのは 構造 です。\n型によって呼べる関数が決まる 状態オブジェクトによって持てる操作が決まる API によって渡せる情報が制限される このとき、 振る舞いは構造の結果として現れるだけ になります。\n「書けない振る舞い」を作る 設計のゴールは、 正しい振る舞いを書くことではありません。\n間違った振る舞いを書けなくすること です。\nそのメソッドは呼べない その状態ではその操作は存在しない その値は生成できない こうした制約が積み重なると、 実装者は「正しいコードしか書けない」状態になります。\nここに至って初めて、\n気をつける レビューで弾く テストで守る といった 人の判断 が、脇役になります。\n振る舞いが増えたら、設計を疑う もし振る舞いが増え続けているなら、 それは仕様が複雑なのではなく、\n判断が構造に押し込まれていない 可能性が高いです。\n状態が曖昧 責務が混ざっている 境界が引かれていない その結果、 振る舞いがコード上で増殖します。\n振る舞いが増えたら、 「どう実装するか」ではなく、 どの判断が構造化されていないか を見直すべきです。\nこの章のまとめ 振る舞いは、判断の結果である 判断は、実行時に行うものではない 判断は構造に固定される 構造が、可能な振る舞いを決める 良い設計とは、間違った振る舞いを書けない状態である 次の章では、 この「構造による制約」が 境界設計・責務分離とどう結びつくか を扱います。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/05-how-to-decide-the-behavior/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E6%8C%AF%E3%82%8B%E8%88%9E%E3%81%84%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%AE%E7%B5%90%E6%9E%9C%E3%81%A7%E3%81%82%E3%82%8A%E6%9B%B8%E3%81%8F%E3%82%82%E3%81%AE%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e振る舞いは「判断の結果」であり、書くものではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%8C%AF%E3%82%8B%E8%88%9E%E3%81%84%E3%81%AF%E8%80%83%E3%81%88%E3%82%8B%E3%82%82%E3%81%AE%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e振る舞いは「考える」ものではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%A7%E3%81%AF%E6%8C%AF%E3%82%8B%E8%88%9E%E3%81%84%E3%81%AF%E9%81%B8%E3%81%B0%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B\"\u003e良い設計では、振る舞いは「選ばれている」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%8C%AF%E3%82%8B%E8%88%9E%E3%81%84%E3%82%92%E5%88%B6%E5%BE%A1%E3%81%99%E3%82%8B%E3%81%AE%E3%81%AF%E6%A7%8B%E9%80%A0\"\u003e振る舞いを制御するのは「構造」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9B%B8%E3%81%91%E3%81%AA%E3%81%84%E6%8C%AF%E3%82%8B%E8%88%9E%E3%81%84%E3%82%92%E4%BD%9C%E3%82%8B\"\u003e「書けない振る舞い」を作る\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%8C%AF%E3%82%8B%E8%88%9E%E3%81%84%E3%81%8C%E5%A2%97%E3%81%88%E3%81%9F%E3%82%89%E8%A8%AD%E8%A8%88%E3%82%92%E7%96%91%E3%81%86\"\u003e振る舞いが増えたら、設計を疑う\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"振る舞いは判断の結果であり書くものではない\"\u003e振る舞いは「判断の結果」であり、書くものではない\u003c/h2\u003e\n\u003cp\u003eここまでで、\n判断は \u003cstrong\u003e人がその場で行うもの\u003c/strong\u003e ではなく、\n\u003cstrong\u003e構造として先に固定されるべきもの\u003c/strong\u003e だ、という話をしてきました。\u003c/p\u003e\n\u003cp\u003eでは、構造に固定された判断は、\n最終的にどこへ行き着くのでしょうか。\u003c/p\u003e\n\u003cp\u003eそれが \u003cstrong\u003e振る舞い（behavior）\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"振る舞いは考えるものではない\"\u003e振る舞いは「考える」ものではない\u003c/h2\u003e\n\u003cp\u003e設計が弱いコードでは、\n振る舞いは次のように書かれます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eif / when で分岐する\u003c/li\u003e\n\u003cli\u003e状態を見て都度判断する\u003c/li\u003e\n\u003cli\u003e条件が増えるたびに分岐が増える\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこのとき、プログラムは常に\n「今、どう動くべきか？」\nを \u003cstrong\u003e実行時に考え続けている\u003c/strong\u003e 状態になります。\u003c/p\u003e\n\u003cp\u003eこれは一見、自然に見えます。\nしかし設計として見ると、これは負けています。\u003c/p\u003e\n\u003cp\u003eなぜなら、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e振る舞いの正しさが\u003c/li\u003e\n\u003cli\u003e毎回の判断に依存している\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eからです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"良い設計では振る舞いは選ばれている\"\u003e良い設計では、振る舞いは「選ばれている」\u003c/h2\u003e\n\u003cp\u003e設計されたコードでは、\n振る舞いは \u003cstrong\u003e書かれるもの\u003c/strong\u003e ではありません。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eすでに選ばれている\u003c/strong\u003e のです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eある状態になった時点で\u003c/li\u003e\n\u003cli\u003eどの振る舞いが可能かは決まっている\u003c/li\u003e\n\u003cli\u003eそれ以外の振る舞いは、そもそも存在しない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eつまり、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e「どう動くか」を考える必要がない\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003e状態が確定した瞬間に、\n実行できる振る舞いも一意に確定する\u003c/strong\u003e\nこれが設計された状態です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"振る舞いを制御するのは構造\"\u003e振る舞いを制御するのは「構造」\u003c/h2\u003e\n\u003cp\u003eここで重要なのは、\n振る舞いを縛っているのが、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eif 文\u003c/li\u003e\n\u003cli\u003eフラグ\u003c/li\u003e\n\u003cli\u003eコメント\u003c/li\u003e\n\u003cli\u003e運用ルール\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eではない、という点です。\u003c/p\u003e\n\u003cp\u003e縛っているのは \u003cstrong\u003e構造\u003c/strong\u003e です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e型によって呼べる関数が決まる\u003c/li\u003e\n\u003cli\u003e状態オブジェクトによって持てる操作が決まる\u003c/li\u003e\n\u003cli\u003eAPI によって渡せる情報が制限される\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこのとき、\n\u003cstrong\u003e振る舞いは構造の結果として現れるだけ\u003c/strong\u003e になります。\u003c/p\u003e","title":"第5章：構造として表現された判断が、どう振る舞いを決定するか"},{"content":" 判断が散らばると、コードは壊れ始める 境界の役割は「判断を一箇所に押し込む」こと Android / Compose における「境界」 悪い例：UI が判断している 良い例：境界の内側で判断が完結している ViewModel は「判断を閉じ込める箱」 境界が曖昧だと、判断は漏れ出す この章のまとめ 設計において「境界」という言葉は、 しばしば次のように説明されます。\n責務の境界 レイヤーの境界 モジュールの境界 しかし本書では、境界をもう一段深く捉えます。\n境界とは、判断を閉じ込めるための構造 です。\n判断が散らばると、コードは壊れ始める 設計されていないコードでは、 同じ判断がいろいろなところに散らばります。\n例えば、ボタンの有効 / 無効を判断する処理が、 UI 内と ViewModel 内にそれぞれ存在するとします。\n判断方法の仕様が変更になった際に、 UI 側の判断は仕様通りに変更したが、 ViewModel 側の変更を忘れた。\nというような 構造的な破綻 が起き始めます。\n境界の役割は「判断を一箇所に押し込む」こと 良い設計では、 判断は 境界の内側に閉じ込められます。\n境界の外では、判断しない 境界の内側で、判断が完結する 境界を越えた時点で、前提が保証される つまり、\n境界を越えたら、もう迷わない\nという状態を作るのが、設計です。\nAndroid / Compose における「境界」 Android / Jetpack Compose では、 典型的に次のような境界が現れます。\nComposable と ViewModel の境界 ViewModel と UseCase の境界 UseCase と Repository の境界 重要なのは、 どこに判断を閉じ込めるかを意識しているか です。\n悪い例：UI が判断している @Composable fun SubmitButton( isLoading: Boolean, isValid: Boolean, onClick: () -\u0026gt; Unit ) { Button( enabled = !isLoading \u0026amp;\u0026amp; isValid, onClick = onClick ) { Text(\u0026#34;Submit\u0026#34;) } } 一見、普通のコードです。 しかしここでは UI が次の判断をしています。\n今、押していいか？ この状態は有効か？ この判断が UI にある限り、\n別の画面でも同じ判断を書く 状態が増えるたびに UI が複雑になる ViewModel との責務が曖昧になる という問題が避けられません。\n良い例：境界の内側で判断が完結している sealed interface SubmitUiState { data object Idle : SubmitUiState data object Loading : SubmitUiState data object Ready : SubmitUiState } @Composable fun SubmitButton( state: SubmitUiState, onClick: () -\u0026gt; Unit ) { Button( enabled = state is SubmitUiState.Ready, onClick = onClick ) { Text(\u0026#34;Submit\u0026#34;) } } この場合、 isLoading と isValid を見て、 「ボタンの状態を決定する」という 判断が境界の内側（ViewModel）で既に完結 しています。\nこの例では、あまり恩恵を感じませんが、 それは、ボタンの状態を決定する要因が二つだけあるためです。\nもし、要因が五つくらいあったらどうでしょうか？ UI で判断するのが、厳しくなると想像できるでしょう。\nViewModel は「判断を閉じ込める箱」 sealed interface FormState { data class Editing( val name: String, val isValid: Boolean ) : FormState data class Ready( val name: String ) : FormState object Submitting : FormState } class SubmitViewModel : ViewModel() { val uiState: StateFlow\u0026lt;SubmitUiState\u0026gt; = ... fun onInputChanged(input: Input) { // ここで判断を完結させる // ( input を判定して、 UI 状態を更新する) } fun onSubmit(ready: FormState.Ready) { // Ready 以外では呼ばれない前提が保証される } } ここで重要なのは、\nUI から不正な状態で呼ばれない 呼ばれた時点で前提が成立している という 保証が構造として成立 していることです。\nこの保証こそが、 境界が存在する意味です。\n境界が曖昧だと、判断は漏れ出す 判断が漏れ出すと、\nif が増える フラグが増える コメントが増える レビューでの指摘が増える これは実装の問題ではなく、 境界設計の失敗 です。\nこの章のまとめ 境界とは、判断を閉じ込める構造である 境界の外では判断しない 境界の内側で判断を完結させる Compose UI は、判断を「表現する側」に徹する 次の章では、 この「境界」が 状態・イベント・責務分割とどう結びつくか ――つまり、 設計として破綻しない全体構造 について扱えます。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/06-devider-closes-the-judgement/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%8C%E6%95%A3%E3%82%89%E3%81%B0%E3%82%8B%E3%81%A8%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AF%E5%A3%8A%E3%82%8C%E5%A7%8B%E3%82%81%E3%82%8B\"\u003e判断が散らばると、コードは壊れ始める\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A2%83%E7%95%8C%E3%81%AE%E5%BD%B9%E5%89%B2%E3%81%AF%E5%88%A4%E6%96%AD%E3%82%92%E4%B8%80%E7%AE%87%E6%89%80%E3%81%AB%E6%8A%BC%E3%81%97%E8%BE%BC%E3%82%80%E3%81%93%E3%81%A8\"\u003e境界の役割は「判断を一箇所に押し込む」こと\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#android--compose-%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E5%A2%83%E7%95%8C\"\u003eAndroid / Compose における「境界」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%82%AA%E3%81%84%E4%BE%8Bui-%E3%81%8C%E5%88%A4%E6%96%AD%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B\"\u003e悪い例：UI が判断している\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E4%BE%8B%E5%A2%83%E7%95%8C%E3%81%AE%E5%86%85%E5%81%B4%E3%81%A7%E5%88%A4%E6%96%AD%E3%81%8C%E5%AE%8C%E7%B5%90%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B\"\u003e良い例：境界の内側で判断が完結している\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#viewmodel-%E3%81%AF%E5%88%A4%E6%96%AD%E3%82%92%E9%96%89%E3%81%98%E8%BE%BC%E3%82%81%E3%82%8B%E7%AE%B1\"\u003eViewModel は「判断を閉じ込める箱」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A2%83%E7%95%8C%E3%81%8C%E6%9B%96%E6%98%A7%E3%81%A0%E3%81%A8%E5%88%A4%E6%96%AD%E3%81%AF%E6%BC%8F%E3%82%8C%E5%87%BA%E3%81%99\"\u003e境界が曖昧だと、判断は漏れ出す\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e設計において「境界」という言葉は、\nしばしば次のように説明されます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e責務の境界\u003c/li\u003e\n\u003cli\u003eレイヤーの境界\u003c/li\u003e\n\u003cli\u003eモジュールの境界\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eしかし本書では、境界をもう一段深く捉えます。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e境界とは、判断を閉じ込めるための構造\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"判断が散らばるとコードは壊れ始める\"\u003e判断が散らばると、コードは壊れ始める\u003c/h2\u003e\n\u003cp\u003e設計されていないコードでは、\n同じ判断がいろいろなところに散らばります。\u003c/p\u003e\n\u003cp\u003e例えば、ボタンの有効 / 無効を判断する処理が、\nUI 内と ViewModel 内にそれぞれ存在するとします。\u003c/p\u003e\n\u003cp\u003e判断方法の仕様が変更になった際に、\nUI 側の判断は仕様通りに変更したが、\nViewModel 側の変更を忘れた。\u003c/p\u003e\n\u003cp\u003eというような \u003cstrong\u003e構造的な破綻\u003c/strong\u003e が起き始めます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"境界の役割は判断を一箇所に押し込むこと\"\u003e境界の役割は「判断を一箇所に押し込む」こと\u003c/h2\u003e\n\u003cp\u003e良い設計では、\n判断は \u003cstrong\u003e境界の内側に閉じ込められます\u003c/strong\u003e。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e境界の外では、判断しない\u003c/li\u003e\n\u003cli\u003e境界の内側で、判断が完結する\u003c/li\u003e\n\u003cli\u003e境界を越えた時点で、前提が保証される\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eつまり、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e境界を越えたら、もう迷わない\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eという状態を作るのが、設計です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"android--compose-における境界\"\u003eAndroid / Compose における「境界」\u003c/h2\u003e\n\u003cp\u003eAndroid / Jetpack Compose では、\n典型的に次のような境界が現れます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eComposable と ViewModel の境界\u003c/li\u003e\n\u003cli\u003eViewModel と UseCase の境界\u003c/li\u003e\n\u003cli\u003eUseCase と Repository の境界\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e重要なのは、\n\u003cstrong\u003eどこに判断を閉じ込めるかを意識しているか\u003c/strong\u003e です。\u003c/p\u003e","title":"第6章：境界は判断を閉じ込める装置である"},{"content":" 壊れない設計を目指すと、判断は過剰に固められる 壊れる設計と、壊してよい設計は違う 「直しやすさ」は、後から付け足せない 壊れやすい場所は、あらかじめ弱くしておく 判断の強度を揃えないという選択 設計は、未来の自分への引き継ぎである 壊すことを恐れなくなると、設計は楽になる ここまでの章では、\n設計とは判断を閉じ込める行為であること 判断は必ず変わること 壊れやすい設計は、判断の偏りから生まれること を見てきました。\nここで、設計に対する前提を一段階更新します。\n設計は、壊れないようにする行為ではありません。 壊れることを前提に、回収できる形にしておく行為です。\nこの章では、 「壊れる前提」を受け入れたときに初めて見えてくる設計の姿を掘り下げます。\n壊れない設計を目指すと、判断は過剰に固められる 壊れない設計を目指すと、 設計者は無意識に、判断を強く閉じ込めようとします。\n将来の変更を想定しすぎる 例外ケースをすべて先取りしようとする 型や抽象で厳重に縛る 一見すると堅牢そうに見えますが、 ここには大きな落とし穴があります。\nそれは、 想定が外れた瞬間に、全体が一気に硬直する ということです。\n壊れないように固めた設計ほど、 壊れたときの修復コストは高くなります。\n壊れる設計と、壊してよい設計は違う 「壊れる前提」と言うと、 雑に作ってよい、という意味に受け取られることがあります。\nしかし、それは違います。\n無秩序 無境界 無責任 な設計は、単に放棄です。\nここで言うのは、 壊れる場所が分かっている設計 です。\nどこが変わりやすいか どこは変わりにくいか 壊れるとしたら、どこからか これが説明できる状態を作ることが目的です。\n「直しやすさ」は、後から付け足せない よく、次のような言葉を耳にします。\nまずは作って、あとで直せばいい 動くものを早く出そう これはスピードが求められる場面では正しい判断です。\nただし、 直しやすさを設計せずに作ったものは、後から直しにくい という事実もあります。\n直しやすさとは、\n境界があること 責務が分かれていること 判断が局所化されていること の積み重ねです。\n直すという行為は、何かを後から付け加えることではありません。 すでに存在するコードを修正し、置き換え、削る行為です。 そのため、どんなに小さな変更であっても、既存の判断や構造に多かれ少なかれ影響を与えます。\n壊れやすい場所は、あらかじめ弱くしておく 壊れやすい場所を、 あえて「弱く」設計するという考え方があります。\n差し替えやすい 捨てやすい 影響範囲が小さい こうした性質を持たせることで、 壊れたときに迷わず手を入れられます。\nこれは、\n抽象を増やすこと レイヤを増やすこと とは限りません。\nむしろ、 壊れる前提の場所ほど、構造はシンプルな方がよい 場合も多くあります。\n判断の強度を揃えないという選択 すべての判断を、 同じ強度で閉じ込める必要はありません。\n型で完全に縛る判断 境界として分ける判断 コメントやドキュメントに留める判断 これらはすべて、 判断をどの強さで残すか の違いです。\n壊れる前提で設計するとは、 判断ごとに強度を変えることだとも言えます。\n設計は、未来の自分への引き継ぎである 壊れたときにコードを触るのは、 未来の自分か、別の誰かです。\nその人が、\nどこを疑えばいいか どこを壊していいか どこは触らない方がいいか を判断できるようにすること。\nそれが、 壊れる前提で設計するということです。\n設計は、 未来への説明責任 でもあります。\n壊すことを恐れなくなると、設計は楽になる 壊れることを前提にすると、 設計は少し楽になります。\n完璧を目指さなくてよくなる 想定外を過剰に恐れなくてよくなる 判断を置く場所に集中できる 設計は、 当てるゲームではありません。\n選び直せる状態を作るゲームです。\n次の章では、 判断を「コードとして残す」具体的な方法、 つまり名前・型・境界の話に進みます。\nここから先は、 設計が目に見える形になる章 です。\n","permalink":"https://design.okuda-studio.com/books/003-design-that-locks-in-judgment/06-/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A3%8A%E3%82%8C%E3%81%AA%E3%81%84%E8%A8%AD%E8%A8%88%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E3%81%A8%E5%88%A4%E6%96%AD%E3%81%AF%E9%81%8E%E5%89%B0%E3%81%AB%E5%9B%BA%E3%82%81%E3%82%89%E3%82%8C%E3%82%8B\"\u003e壊れない設計を目指すと、判断は過剰に固められる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A3%8A%E3%82%8C%E3%82%8B%E8%A8%AD%E8%A8%88%E3%81%A8%E5%A3%8A%E3%81%97%E3%81%A6%E3%82%88%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%AF%E9%81%95%E3%81%86\"\u003e壊れる設計と、壊してよい設計は違う\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%9B%B4%E3%81%97%E3%82%84%E3%81%99%E3%81%95%E3%81%AF%E5%BE%8C%E3%81%8B%E3%82%89%E4%BB%98%E3%81%91%E8%B6%B3%E3%81%9B%E3%81%AA%E3%81%84\"\u003e「直しやすさ」は、後から付け足せない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A3%8A%E3%82%8C%E3%82%84%E3%81%99%E3%81%84%E5%A0%B4%E6%89%80%E3%81%AF%E3%81%82%E3%82%89%E3%81%8B%E3%81%98%E3%82%81%E5%BC%B1%E3%81%8F%E3%81%97%E3%81%A6%E3%81%8A%E3%81%8F\"\u003e壊れやすい場所は、あらかじめ弱くしておく\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AE%E5%BC%B7%E5%BA%A6%E3%82%92%E6%8F%83%E3%81%88%E3%81%AA%E3%81%84%E3%81%A8%E3%81%84%E3%81%86%E9%81%B8%E6%8A%9E\"\u003e判断の強度を揃えないという選択\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AF%E6%9C%AA%E6%9D%A5%E3%81%AE%E8%87%AA%E5%88%86%E3%81%B8%E3%81%AE%E5%BC%95%E3%81%8D%E7%B6%99%E3%81%8E%E3%81%A7%E3%81%82%E3%82%8B\"\u003e設計は、未来の自分への引き継ぎである\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A3%8A%E3%81%99%E3%81%93%E3%81%A8%E3%82%92%E6%81%90%E3%82%8C%E3%81%AA%E3%81%8F%E3%81%AA%E3%82%8B%E3%81%A8%E8%A8%AD%E8%A8%88%E3%81%AF%E6%A5%BD%E3%81%AB%E3%81%AA%E3%82%8B\"\u003e壊すことを恐れなくなると、設計は楽になる\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eここまでの章では、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e設計とは判断を閉じ込める行為であること\u003c/li\u003e\n\u003cli\u003e判断は必ず変わること\u003c/li\u003e\n\u003cli\u003e壊れやすい設計は、判断の偏りから生まれること\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを見てきました。\u003c/p\u003e\n\u003cp\u003eここで、設計に対する前提を一段階更新します。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e設計は、壊れないようにする行為ではありません。\u003c/strong\u003e\n\u003cstrong\u003e壊れることを前提に、回収できる形にしておく行為です。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eこの章では、\n「壊れる前提」を受け入れたときに初めて見えてくる設計の姿を掘り下げます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"壊れない設計を目指すと判断は過剰に固められる\"\u003e壊れない設計を目指すと、判断は過剰に固められる\u003c/h3\u003e\n\u003cp\u003e壊れない設計を目指すと、\n設計者は無意識に、判断を強く閉じ込めようとします。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e将来の変更を想定しすぎる\u003c/li\u003e\n\u003cli\u003e例外ケースをすべて先取りしようとする\u003c/li\u003e\n\u003cli\u003e型や抽象で厳重に縛る\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e一見すると堅牢そうに見えますが、\nここには大きな落とし穴があります。\u003c/p\u003e\n\u003cp\u003eそれは、\n\u003cstrong\u003e想定が外れた瞬間に、全体が一気に硬直する\u003c/strong\u003e ということです。\u003c/p\u003e\n\u003cp\u003e壊れないように固めた設計ほど、\n壊れたときの修復コストは高くなります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"壊れる設計と壊してよい設計は違う\"\u003e壊れる設計と、壊してよい設計は違う\u003c/h3\u003e\n\u003cp\u003e「壊れる前提」と言うと、\n雑に作ってよい、という意味に受け取られることがあります。\u003c/p\u003e\n\u003cp\u003eしかし、それは違います。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e無秩序\u003c/li\u003e\n\u003cli\u003e無境界\u003c/li\u003e\n\u003cli\u003e無責任\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eな設計は、単に放棄です。\u003c/p\u003e\n\u003cp\u003eここで言うのは、\n\u003cstrong\u003e壊れる場所が分かっている設計\u003c/strong\u003e です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどこが変わりやすいか\u003c/li\u003e\n\u003cli\u003eどこは変わりにくいか\u003c/li\u003e\n\u003cli\u003e壊れるとしたら、どこからか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれが説明できる状態を作ることが目的です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"直しやすさは後から付け足せない\"\u003e「直しやすさ」は、後から付け足せない\u003c/h3\u003e\n\u003cp\u003eよく、次のような言葉を耳にします。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eまずは作って、あとで直せばいい\u003c/li\u003e\n\u003cli\u003e動くものを早く出そう\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれはスピードが求められる場面では正しい判断です。\u003c/p\u003e\n\u003cp\u003eただし、\n\u003cstrong\u003e直しやすさを設計せずに作ったものは、後から直しにくい\u003c/strong\u003e\nという事実もあります。\u003c/p\u003e\n\u003cp\u003e直しやすさとは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e境界があること\u003c/li\u003e\n\u003cli\u003e責務が分かれていること\u003c/li\u003e\n\u003cli\u003e判断が局所化されていること\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eの積み重ねです。\u003c/p\u003e\n\u003cp\u003e直すという行為は、何かを後から付け加えることではありません。\nすでに存在するコードを修正し、置き換え、削る行為です。\nそのため、どんなに小さな変更であっても、既存の判断や構造に多かれ少なかれ影響を与えます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"壊れやすい場所はあらかじめ弱くしておく\"\u003e壊れやすい場所は、あらかじめ弱くしておく\u003c/h3\u003e\n\u003cp\u003e壊れやすい場所を、\nあえて「弱く」設計するという考え方があります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e差し替えやすい\u003c/li\u003e\n\u003cli\u003e捨てやすい\u003c/li\u003e\n\u003cli\u003e影響範囲が小さい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうした性質を持たせることで、\n壊れたときに迷わず手を入れられます。\u003c/p\u003e\n\u003cp\u003eこれは、\u003c/p\u003e","title":"第6章：壊れることを前提に設計する"},{"content":" 最初の一手は、「判断の置き場所」に打つ なぜ「小さいところから」は失敗しやすいのか 最初の一手が変えるべきもの 「守られている判断」を一つ選ぶ 切り出すのは「処理」ではない 判断は、まだ if 文の中にある 切り出すべきなのは「条件」ではない 改善例：判断に名前と置き場所を与える 何が変わったのか canApplySpecialDiscount の場合に起きていること isEligible の場合に起きていること 「置き場所が決まる」と何が変わるのか もう一つ大事な違い 設計とは、if を減らすことではない 成功する最初の一手の形 最初の一手は、小さくていい この章のまとめ 最初の一手は、「判断の置き場所」に打つ 既存のモノリスを前にして、\n次に必ず出てくる問いがあります。\n「で、どこから直せばいいんですか。」\nこの問いに対して、\n多くの現場ではこう答えがちです。\n影響範囲が小さいところから テストがあるところから 簡単そうなところから これらは、\n間違いではありません。\nしかし、\n十分でもありません。\nなぜ「小さいところから」は失敗しやすいのか 影響範囲の小さい修正は、\n安全に見えます。\nしかし、\nそれは多くの場合、 判断に触れていない修正 です。\nロジックを少し整理した クラスを分割した 命名を直した コードはきれいになります。\nですが、\n設計はほとんど変わりません。\nなぜなら、\n判断がそのままだからです。\n最初の一手が変えるべきもの 最初の一手で変えるべきなのは、\n構造ではなく、\n判断です。\nもっと正確に言うと、\n「この判断は、ここに置く」という\n配置の仕方です。\nつまり、\n判断の所在地を動かすこと が\n効果的な最初の一手になります。\n「守られている判断」を一つ選ぶ 第5章で見つけた、\n判断の軸を思い出してください。\nその中から、\n次の条件を満たすものを\n一つだけ選びます。\n長く守られてきた 壊れると致命的 多くの場所から参照されている これは、\n今のモノリスの中心判断 です。\n最初の一手は、\n必ずここに打ちます。\n切り出すのは「処理」ではない ここで、\nよくある誤解があります。\nそれは、\n「ロジックを別クラスに切り出すことが設計だ」\nと思ってしまうことです。\nたとえば、\n次のような if 文を見たとします。\nif (user.isPremium \u0026amp;\u0026amp; order.total \u0026gt;= 1000 \u0026amp;\u0026amp; !order.isCampaign) { applySpecialDiscount(order) } 条件が長く、\n意味も一目では分かりません。\nそのため、\n多くの現場では次のような改善が行われます。\nif (canApplySpecialDiscount(user, order)) { applySpecialDiscount(order) } 一見すると、\n読みやすくなりました。\nしかし、\n設計としては、ほとんど前進していません。\n判断は、まだ if 文の中にある この時点でも、\n次の問いには答えられていません。\nなぜプレミアムユーザーなのか。 なぜ 1000 円以上なのか。 なぜキャンペーン中は除外されるのか。 つまり、\n「いつ特別扱いしてよいのか」という判断は、\n依然としてコードの外にあります。\n関数名が付いただけで、\n判断そのものは、\nその場しのぎで書かれたままです。\n切り出すべきなのは「条件」ではない ここで切り出すべきなのは、\n条件式でも、\n処理の塊でもありません。\n切り出すべきなのは、\nその分岐が存在する理由 です。\nつまり、\n「どんな状態のときに、特別割引が許されるのか」\nという判断そのものです。\n改善例：判断に名前と置き場所を与える この判断を、\n明示的な存在として表現すると、\n次のようになります。\nclass SpecialDiscountPolicy { fun isEligible(user: User, order: Order): Boolean { return user.isPremium \u0026amp;\u0026amp; order.total \u0026gt;= MINIMUM_AMOUNT \u0026amp;\u0026amp; !order.isCampaign } } 重要なのは、\nこのクラスが「割引ロジック」を表しているわけではない、\nという点です。\nこれは、\n「特別割引が許される条件とは何か」\nという判断を表現したものです。\n何が変わったのか この形にすると、\n設計上の意味がはっきり変わります。\n「判断の置き場所が 偶然 決まっているか、\nそれとも 意図して固定 されているか」\nが変わります。\nこの変更により、\n判断が一箇所に集まる 変更理由を説明できる 条件の妥当性を議論できる 状態になります。\ncanApplySpecialDiscount の場合に起きていること if (canApplySpecialDiscount(user, order)) { applySpecialDiscount(order) } この形では、\n判断は「ある」 しかし どこに属する判断なのかが決まっていない という状態です。\ncanApplySpecialDiscount は、\nutil 関数かもしれない ViewModel に置かれているかもしれない 別のファイルに散らばるかもしれない つまり、\n「とりあえず今ここにある判断」\nでしかありません。\nこの判断は、\n他でも使われるかもしれない 別の文脈で書き直されるかもしれない 微妙に条件がズレた別バージョンが生まれるかもしれない という、 漂流状態 にあります。\nisEligible の場合に起きていること class SpecialDiscountPolicy { fun isEligible(user: User, order: Order): Boolean { ... } } こちらでは、\n判断が SpecialDiscountPolicy という概念に所属している 「この判断はここにある」と明示されている という状態です。\nこれは単なるリファクタリングではなく、\n「この判断は、特別割引というルールの一部だ」 という設計上の宣言 です。\nその結果、\n似た判断はここに集まる 変更理由をここに集約できる 仕様の会話がコードと一致する ようになります。\n「置き場所が決まる」と何が変わるのか 重要なのは、\n置き場所が決まると 責任が決まる という点です。\ncanApplySpecialDiscount → 「誰の判断か分からない」 isEligible → 「特別割引 ( SpecialDiscountPolicy ) の判断」 この差は、\nテストを書くとき 仕様変更が入ったとき 説明責任を果たすとき に、はっきり効いてきます。\nもう一つ大事な違い もう一つだけ補足します。\ncanApplySpecialDiscount は、\n「今、この条件を通していいか」\nという 局所的な判断 です。\n一方、isEligible は、\n「特別割引とは、どういう状態か」\nという ドメイン定義上の判断 です。\n実行可否 と 概念の定義 。\nここが、決定的に違います。\n設計とは、if を減らすことではない if 文が悪いわけではありません。\n問題なのは、\n本来は言葉で説明されるべき判断を、\nif 文の中に閉じ込めてしまうことです。\n設計とは、\n構文を整理することではありません。\n判断が、\nどこに置かれているのかを\n自分の言葉で説明できる状態にすることです。\n成功する最初の一手の形 成功する最初の一手には、\n共通した特徴があります。\n呼び出し側が楽になる 責務の説明が一文で言える そして何より、\n「ああ、そういう判断だったのか」\nと周囲が納得する。\nこの納得感が、\n次の一手を呼び込みます。\n最初の一手は、小さくていい ここまで読むと、\n大きな変更が必要だと\n感じるかもしれません。\nですが、\n最初の一手は小さくて構いません。\n重要なのは、\n変更量ではなく、\n方向性 です。\n判断の置き場所が、\n一つでも明確になれば、\n設計は動き始めます。\nこの章のまとめ 最初の一手は、\n安全な場所に打つものではありません。\n意味のある場所に打つものです。\n構造を直す前に、\n判断を動かす。\nその一手が、\nモノリスを\n「理解可能な塊」へと\n変えていきます。\n次の章では、\nこの一手を\nどうやって連鎖させるのか。\nつまり、\n改善を止めないための考え方を\n扱います。\n","permalink":"https://design.okuda-studio.com/books/002-design-starts-with-decisions/06-first-move/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9C%80%E5%88%9D%E3%81%AE%E4%B8%80%E6%89%8B%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%AE%E7%BD%AE%E3%81%8D%E5%A0%B4%E6%89%80%E3%81%AB%E6%89%93%E3%81%A4\"\u003e最初の一手は、「判断の置き場所」に打つ\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E5%B0%8F%E3%81%95%E3%81%84%E3%81%A8%E3%81%93%E3%82%8D%E3%81%8B%E3%82%89%E3%81%AF%E5%A4%B1%E6%95%97%E3%81%97%E3%82%84%E3%81%99%E3%81%84%E3%81%AE%E3%81%8B\"\u003eなぜ「小さいところから」は失敗しやすいのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9C%80%E5%88%9D%E3%81%AE%E4%B8%80%E6%89%8B%E3%81%8C%E5%A4%89%E3%81%88%E3%82%8B%E3%81%B9%E3%81%8D%E3%82%82%E3%81%AE\"\u003e最初の一手が変えるべきもの\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%AE%88%E3%82%89%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E5%88%A4%E6%96%AD%E3%82%92%E4%B8%80%E3%81%A4%E9%81%B8%E3%81%B6\"\u003e「守られている判断」を一つ選ぶ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%87%E3%82%8A%E5%87%BA%E3%81%99%E3%81%AE%E3%81%AF%E5%87%A6%E7%90%86%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e切り出すのは「処理」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AF%E3%81%BE%E3%81%A0-if-%E6%96%87%E3%81%AE%E4%B8%AD%E3%81%AB%E3%81%82%E3%82%8B\"\u003e判断は、まだ if 文の中にある\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%87%E3%82%8A%E5%87%BA%E3%81%99%E3%81%B9%E3%81%8D%E3%81%AA%E3%81%AE%E3%81%AF%E6%9D%A1%E4%BB%B6%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e切り出すべきなのは「条件」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%94%B9%E5%96%84%E4%BE%8B%E5%88%A4%E6%96%AD%E3%81%AB%E5%90%8D%E5%89%8D%E3%81%A8%E7%BD%AE%E3%81%8D%E5%A0%B4%E6%89%80%E3%82%92%E4%B8%8E%E3%81%88%E3%82%8B\"\u003e改善例：判断に名前と置き場所を与える\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BD%95%E3%81%8C%E5%A4%89%E3%82%8F%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%8B\"\u003e何が変わったのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#canapplyspecialdiscount-%E3%81%AE%E5%A0%B4%E5%90%88%E3%81%AB%E8%B5%B7%E3%81%8D%E3%81%A6%E3%81%84%E3%82%8B%E3%81%93%E3%81%A8\"\u003ecanApplySpecialDiscount の場合に起きていること\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#iseligible-%E3%81%AE%E5%A0%B4%E5%90%88%E3%81%AB%E8%B5%B7%E3%81%8D%E3%81%A6%E3%81%84%E3%82%8B%E3%81%93%E3%81%A8\"\u003eisEligible の場合に起きていること\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%BD%AE%E3%81%8D%E5%A0%B4%E6%89%80%E3%81%8C%E6%B1%BA%E3%81%BE%E3%82%8B%E3%81%A8%E4%BD%95%E3%81%8C%E5%A4%89%E3%82%8F%E3%82%8B%E3%81%AE%E3%81%8B\"\u003e「置き場所が決まる」と何が変わるのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%82%E3%81%86%E4%B8%80%E3%81%A4%E5%A4%A7%E4%BA%8B%E3%81%AA%E9%81%95%E3%81%84\"\u003eもう一つ大事な違い\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%A8%E3%81%AFif-%E3%82%92%E6%B8%9B%E3%82%89%E3%81%99%E3%81%93%E3%81%A8%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e設計とは、if を減らすことではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%88%90%E5%8A%9F%E3%81%99%E3%82%8B%E6%9C%80%E5%88%9D%E3%81%AE%E4%B8%80%E6%89%8B%E3%81%AE%E5%BD%A2\"\u003e成功する最初の一手の形\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9C%80%E5%88%9D%E3%81%AE%E4%B8%80%E6%89%8B%E3%81%AF%E5%B0%8F%E3%81%95%E3%81%8F%E3%81%A6%E3%81%84%E3%81%84\"\u003e最初の一手は、小さくていい\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"最初の一手は判断の置き場所に打つ\"\u003e最初の一手は、「判断の置き場所」に打つ\u003c/h2\u003e\n\u003chr\u003e\n\u003cp\u003e既存のモノリスを前にして、\u003cbr\u003e\n次に必ず出てくる問いがあります。\u003c/p\u003e\n\u003cp\u003e「で、どこから直せばいいんですか。」\u003c/p\u003e\n\u003cp\u003eこの問いに対して、\u003cbr\u003e\n多くの現場ではこう答えがちです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e影響範囲が小さいところから\u003c/li\u003e\n\u003cli\u003eテストがあるところから\u003c/li\u003e\n\u003cli\u003e簡単そうなところから\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは、\u003cbr\u003e\n\u003cstrong\u003e間違いではありません。\u003c/strong\u003e\u003cbr\u003e\nしかし、\u003cbr\u003e\n\u003cstrong\u003e十分でもありません。\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"なぜ小さいところからは失敗しやすいのか\"\u003eなぜ「小さいところから」は失敗しやすいのか\u003c/h3\u003e\n\u003cp\u003e影響範囲の小さい修正は、\u003cbr\u003e\n安全に見えます。\u003c/p\u003e\n\u003cp\u003eしかし、\u003cbr\u003e\nそれは多くの場合、\n\u003cstrong\u003e判断に触れていない修正\u003c/strong\u003e です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eロジックを少し整理した\u003c/li\u003e\n\u003cli\u003eクラスを分割した\u003c/li\u003e\n\u003cli\u003e命名を直した\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eコードはきれいになります。\u003cbr\u003e\nですが、\u003cbr\u003e\n設計はほとんど変わりません。\u003c/p\u003e\n\u003cp\u003eなぜなら、\u003cbr\u003e\n判断がそのままだからです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"最初の一手が変えるべきもの\"\u003e最初の一手が変えるべきもの\u003c/h3\u003e\n\u003cp\u003e最初の一手で変えるべきなのは、\u003cbr\u003e\n構造ではなく、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e判断です。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eもっと正確に言うと、\u003cbr\u003e\n「この判断は、ここに置く」という\u003cbr\u003e\n配置の仕方です。\u003c/p\u003e\n\u003cp\u003eつまり、\u003cbr\u003e\n\u003cstrong\u003e判断の所在地を動かすこと\u003c/strong\u003e が\u003cbr\u003e\n効果的な最初の一手になります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"守られている判断を一つ選ぶ\"\u003e「守られている判断」を一つ選ぶ\u003c/h3\u003e\n\u003cp\u003e第5章で見つけた、\u003cbr\u003e\n判断の軸を思い出してください。\u003c/p\u003e\n\u003cp\u003eその中から、\u003cbr\u003e\n次の条件を満たすものを\u003cbr\u003e\n一つだけ選びます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e長く守られてきた\u003c/li\u003e\n\u003cli\u003e壊れると致命的\u003c/li\u003e\n\u003cli\u003e多くの場所から参照されている\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれは、\u003cbr\u003e\n\u003cstrong\u003e今のモノリスの中心判断\u003c/strong\u003e です。\u003c/p\u003e","title":"第6章：最初の一手は、「判断の置き場所」に打つ"},{"content":" 判断は「意図」ではなく「制約」として残す 名前は、最も軽い制約である 型は、判断を強制する 境界は、判断の置き場所を固定する 判断を残しすぎないという判断 制約の「強さ」を意識して設計する 設計とは、判断の履歴を残すこと まとめ ここまでの章で、設計とは判断を閉じ込める行為であり、 その判断は必ず変わり、壊れ、直されるものであることを見てきました。\nでは、次の問いに進みます。\nその判断を、どこに、どうやって残すのか。\nこの章では、設計の議論をいよいよコードの中に降ろします。 抽象論ではなく、日々書いているコードの中で 判断をどう扱えばよいのかを整理していきます。\n判断は「意図」ではなく「制約」として残す 設計の意図は、しばしばコメントやドキュメントに書かれます。\nこのクラスは◯◯のために存在する ここは将来変更される想定 これ自体は悪いことではありません。 しかし、意図だけが残り、制約が残らない設計には限界があります。\nコードに残すべきなのは、 「こう使ってほしい」ではなく「こう使うことはできない」 という判断です。\n制約として残された判断は、\n誤った使い方を防ぐ 設計者の不在時にも効力を持つ 時間が経っても意味を失いにくい という性質を持ちます。\n名前は、最も軽い制約である 判断を残す最初の手段は、名前です。\nクラス名 関数名 変数名 名前は、 「これは何か」「これは何ではないか」 を同時に伝えます。\nたとえば、\nManager Helper Util といった名前は、判断をほとんど閉じ込めていません。\n逆に、\n何の責務を持つのか どこまでを扱うのか が読み取れる名前は、 それだけで利用範囲を制限します。\n名前は弱い制約ですが、 弱いからこそ、最初に置く価値があります。\n型は、判断を強制する 名前だけでは防げない誤用は、必ず出てきます。\nそこで次に使うのが、型です。\nプリミティブ型をそのまま使わない 意味のある値オブジェクトを作る null を許可しない型にする 型は、 守らなければならない判断 をコードとして強制します。\n型として残された判断は、\nコンパイル時に検証される 利用側に説明を要求しない という強い効力を持ちます。\n境界は、判断の置き場所を固定する 名前と型だけでは、 判断の影響範囲を限定しきれないことがあります。\nそこで登場するのが、境界です。\nモジュール レイヤ インターフェース 境界の役割は、 この判断は、ここに閉じ込める と明示することです。\n境界があることで、\n変更点が集約される 影響範囲が見積もれる 壊してよい場所が分かる ようになります。\n判断を残しすぎないという判断 判断をコードに残すことは重要ですが、 すべてを強い制約にすればよいわけではありません。\n名前で十分な判断 型で縛るべき判断 境界を切るほどでもない判断 これらを見極めること自体が、設計です。\n判断を残しすぎると、\n変更がしにくくなる 本来変えてよい部分まで固定される という問題が起きます。\nここでも、 判断の強度を選ぶ という第6章の話が生きてきます。\n制約の「強さ」を意識して設計する 設計における制約には、強さの違いがあります。\nコメントやドキュメントは、意図を伝えるが守られる保証はない 命名は、読み手の判断をある程度縛るが、解釈の余地が残る 境界は、構造として責務や依存方向を示す 型は、コンパイル時に破られることを許さない この中で、 最も強い制約は型 です。 型は人の理解や注意力に依存せず、機械的に誤りを排除します。\nしかし、強い制約ほど万能というわけではありません。 型は局所的には非常に強力ですが、システム全体の構造までは表現できません。\nそこで重要になるのが、 境界 です。\n境界は、\nどこまでがこの責務か どの方向に依存してよいか といった設計判断を、構造として表現する制約です。\n境界で構造を縛り、その上で型によって振る舞いを縛る。 設計とは、制約を一気に強くすることではなく、 適切な制約を付与する行為 です。\n設計とは、判断の履歴を残すこと 時間が経ったコードベースには、 必ず複数の判断が折り重なっています。\nそのとき重要なのは、\nこの判断はどこに残っているか どの判断が、どの制約として現れているか を追えることです。\n良い設計とは、 判断の履歴をコードから読み取れる設計 だと言えます。\nまとめ 判断は意図ではなく、制約としてコードに残す 名前・型・境界は、判断の強度の違いである 強い制約ほど、置く場所と範囲を慎重に選ぶ 設計とは、判断を選び、履歴として残す行為である 次章では、 こうした判断をチームでどう共有し、 設計を属人化させないかを扱います。\n","permalink":"https://design.okuda-studio.com/books/003-design-that-locks-in-judgment/07-/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AF%E6%84%8F%E5%9B%B3%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%E5%88%B6%E7%B4%84%E3%81%A8%E3%81%97%E3%81%A6%E6%AE%8B%E3%81%99\"\u003e判断は「意図」ではなく「制約」として残す\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%90%8D%E5%89%8D%E3%81%AF%E6%9C%80%E3%82%82%E8%BB%BD%E3%81%84%E5%88%B6%E7%B4%84%E3%81%A7%E3%81%82%E3%82%8B\"\u003e名前は、最も軽い制約である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%9E%8B%E3%81%AF%E5%88%A4%E6%96%AD%E3%82%92%E5%BC%B7%E5%88%B6%E3%81%99%E3%82%8B\"\u003e型は、判断を強制する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A2%83%E7%95%8C%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%AE%E7%BD%AE%E3%81%8D%E5%A0%B4%E6%89%80%E3%82%92%E5%9B%BA%E5%AE%9A%E3%81%99%E3%82%8B\"\u003e境界は、判断の置き場所を固定する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%82%92%E6%AE%8B%E3%81%97%E3%81%99%E3%81%8E%E3%81%AA%E3%81%84%E3%81%A8%E3%81%84%E3%81%86%E5%88%A4%E6%96%AD\"\u003e判断を残しすぎないという判断\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%B6%E7%B4%84%E3%81%AE%E5%BC%B7%E3%81%95%E3%82%92%E6%84%8F%E8%AD%98%E3%81%97%E3%81%A6%E8%A8%AD%E8%A8%88%E3%81%99%E3%82%8B\"\u003e制約の「強さ」を意識して設計する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%A8%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%AE%E5%B1%A5%E6%AD%B4%E3%82%92%E6%AE%8B%E3%81%99%E3%81%93%E3%81%A8\"\u003e設計とは、判断の履歴を残すこと\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eここまでの章で、設計とは判断を閉じ込める行為であり、\nその判断は必ず変わり、壊れ、直されるものであることを見てきました。\u003c/p\u003e\n\u003cp\u003eでは、次の問いに進みます。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eその判断を、どこに、どうやって残すのか。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eこの章では、設計の議論をいよいよコードの中に降ろします。\n抽象論ではなく、日々書いているコードの中で\n判断をどう扱えばよいのかを整理していきます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断は意図ではなく制約として残す\"\u003e判断は「意図」ではなく「制約」として残す\u003c/h3\u003e\n\u003cp\u003e設計の意図は、しばしばコメントやドキュメントに書かれます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこのクラスは◯◯のために存在する\u003c/li\u003e\n\u003cli\u003eここは将来変更される想定\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれ自体は悪いことではありません。\nしかし、意図だけが残り、制約が残らない設計には限界があります。\u003c/p\u003e\n\u003cp\u003eコードに残すべきなのは、\n\u003cstrong\u003e「こう使ってほしい」ではなく「こう使うことはできない」\u003c/strong\u003e\nという判断です。\u003c/p\u003e\n\u003cp\u003e制約として残された判断は、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e誤った使い方を防ぐ\u003c/li\u003e\n\u003cli\u003e設計者の不在時にも効力を持つ\u003c/li\u003e\n\u003cli\u003e時間が経っても意味を失いにくい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという性質を持ちます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"名前は最も軽い制約である\"\u003e名前は、最も軽い制約である\u003c/h3\u003e\n\u003cp\u003e判断を残す最初の手段は、名前です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eクラス名\u003c/li\u003e\n\u003cli\u003e関数名\u003c/li\u003e\n\u003cli\u003e変数名\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e名前は、\n\u003cstrong\u003e「これは何か」「これは何ではないか」\u003c/strong\u003e を同時に伝えます。\u003c/p\u003e\n\u003cp\u003eたとえば、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eManager\u003c/li\u003e\n\u003cli\u003eHelper\u003c/li\u003e\n\u003cli\u003eUtil\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった名前は、判断をほとんど閉じ込めていません。\u003c/p\u003e\n\u003cp\u003e逆に、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e何の責務を持つのか\u003c/li\u003e\n\u003cli\u003eどこまでを扱うのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eが読み取れる名前は、\nそれだけで利用範囲を制限します。\u003c/p\u003e\n\u003cp\u003e名前は弱い制約ですが、\n弱いからこそ、最初に置く価値があります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"型は判断を強制する\"\u003e型は、判断を強制する\u003c/h3\u003e\n\u003cp\u003e名前だけでは防げない誤用は、必ず出てきます。\u003c/p\u003e\n\u003cp\u003eそこで次に使うのが、型です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eプリミティブ型をそのまま使わない\u003c/li\u003e\n\u003cli\u003e意味のある値オブジェクトを作る\u003c/li\u003e\n\u003cli\u003enull を許可しない型にする\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e型は、\n\u003cstrong\u003e守らなければならない判断\u003c/strong\u003e をコードとして強制します。\u003c/p\u003e\n\u003cp\u003e型として残された判断は、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eコンパイル時に検証される\u003c/li\u003e\n\u003cli\u003e利用側に説明を要求しない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという強い効力を持ちます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"境界は判断の置き場所を固定する\"\u003e境界は、判断の置き場所を固定する\u003c/h3\u003e\n\u003cp\u003e名前と型だけでは、\n判断の影響範囲を限定しきれないことがあります。\u003c/p\u003e\n\u003cp\u003eそこで登場するのが、境界です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eモジュール\u003c/li\u003e\n\u003cli\u003eレイヤ\u003c/li\u003e\n\u003cli\u003eインターフェース\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e境界の役割は、\n\u003cstrong\u003eこの判断は、ここに閉じ込める\u003c/strong\u003e と明示することです。\u003c/p\u003e","title":"第7章：判断をコードに残す"},{"content":" 改善を止めないために必要なもの 連鎖が途切れる典型的な瞬間 なぜ一気に触ると、連鎖が止まるのか 判断を一つだけ動かした場合 変更が重なると、因果が見えなくなる 「追えない」とは、どういう状態か 連鎖が続く条件は「因果が見えること」 チームでは、さらに問題が大きくなる 改善を止めないためのルール この章のまとめ 改善を止めないために必要なもの 第6章で見たように、\n最初の一手は「判断を動かす」ことから始まります。\nこの一手がうまくいくと、\n現場では次に、こんな感覚が生まれます。\n「もう少し、ここも直せそうだ」\n「次は、あの判断も整理できそうだ」\n設計改善が、\n連鎖し始める瞬間 です。\nしかし、この連鎖は、\n意外と簡単に途切れます。\n連鎖が途切れる典型的な瞬間 連鎖が止まるのは、\n多くの場合、次の判断をしたときです。\n「今の流れで、\nまとめて構造も整理してしまおう」\n判断を一つ動かせた成功体験があると、\nつい、こうしたくなります。\nクラス構成を整理する パッケージを切り直す 似た責務をまとめる 命名を一気に整える 結果として、\nコードはきれいになります。\nしかし、\nここで一気に構造を触ると、\n改善の連鎖は途切れます。\nなぜ一気に触ると、連鎖が止まるのか 理由は単純です。\n判断の変化が、追えなくなるからです。\n判断を一つだけ動かした場合 たとえば、\n第6章で扱ったように、\n散らばっていた if の判断を SpecialDiscountPolicy に集めた この変更は、\nとても説明しやすい状態です。\n「特別割引という判断を、\nこのクラスに置きました」\n何が変わったのか なぜ変えたのか どの判断を動かしたのか が、\n一文で説明できます。\n変わった判断が、ひとつだけ\nだからです。\n変更が重なると、因果が見えなくなる 一方で、\n次のような変更を同時に行った場合を考えてみてください。\n判断を切り出した クラスを分割した パッケージを整理した util を削除した コードの見た目は、\n確実に良くなっています。\nですが、\nここでこう聞かれると、どうでしょうか。\n「なぜ、この構造になったんですか？」\n多くの場合、\n答えがこうなります。\n「判断を整理した結果で……\nついでに構造も見直して……\n全体的にきれいにしました」\nこれは、\n説明できているようで、できていません。\n「追えない」とは、どういう状態か ここで言っている\n「判断の変化が追えない」とは、\nどの判断が起点だったのか分からない この構造が、どの判断に対応しているのか説明できない diff を見ても、意図が読み取れない という状態です。\n設計の変更が、\n「なぜそうなったか」ではなく 「そうなっている」という結果 だけを残してしまいます。\nこれはつまり、\n判断の履歴が、消えてしまった状態\nだと言えます。\n連鎖が続く条件は「因果が見えること」 改善が連鎖するためには、\n次の対応関係が、常に見えている必要があります。\nこの変更で この判断が ここに置かれた この 1 対 1 の因果が、\n誰の目にも明らかであること。\n一気に構造を触ると、\nどの判断が前進を生んだのか 次は、何を基準に直せばいいのか が分からなくなります。\nその結果、\n次の一手が選べなくなる。\nこれが、\n「連鎖が途切れる」という現象の正体です。\nチームでは、さらに問題が大きくなる この問題は、\nチーム開発では、より深刻になります。\nレビューで意図が共有できない 「とりあえずきれいにした変更」に見える 次に触る人が、元の if を復活させる つまり、\n判断が再び漂流し始める のです。\n「良くなったはずなのに、戻ってしまう」\n多くの現場で起きているこの現象は、\n技術力の問題ではありません。\n判断の因果が、\nコードに残っていないだけ です。\n改善を止めないためのルール 改善を連鎖させたいなら、\n守るべきルールは、実はとてもシンプルです。\n1 回の変更で 動かす判断は 1 つ 説明は 1 文でできる この状態を保てていれば、\n設計改善は自然に続いていきます。\nこの章のまとめ 改善が止まるのは、\n難しいことをしているからではありません。\n何を変えたのかが、\n分からなくなるからです。\n判断を一つ動かす。\nその因果を、コードに残す。\nこの積み重ねが、\nモノリスを少しずつ、\nしかし確実に変えていきます。\n次の章では、\nこの判断の連鎖を\n個人の感覚ではなく、チームの共通理解にする方法\nについて扱います。\n","permalink":"https://design.okuda-studio.com/books/002-design-starts-with-decisions/07-to-keep-improving/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E6%94%B9%E5%96%84%E3%82%92%E6%AD%A2%E3%82%81%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E3%82%82%E3%81%AE\"\u003e改善を止めないために必要なもの\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E9%80%A3%E9%8E%96%E3%81%8C%E9%80%94%E5%88%87%E3%82%8C%E3%82%8B%E5%85%B8%E5%9E%8B%E7%9A%84%E3%81%AA%E7%9E%AC%E9%96%93\"\u003e連鎖が途切れる典型的な瞬間\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E4%B8%80%E6%B0%97%E3%81%AB%E8%A7%A6%E3%82%8B%E3%81%A8%E9%80%A3%E9%8E%96%E3%81%8C%E6%AD%A2%E3%81%BE%E3%82%8B%E3%81%AE%E3%81%8B\"\u003eなぜ一気に触ると、連鎖が止まるのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%82%92%E4%B8%80%E3%81%A4%E3%81%A0%E3%81%91%E5%8B%95%E3%81%8B%E3%81%97%E3%81%9F%E5%A0%B4%E5%90%88\"\u003e判断を一つだけ動かした場合\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A4%89%E6%9B%B4%E3%81%8C%E9%87%8D%E3%81%AA%E3%82%8B%E3%81%A8%E5%9B%A0%E6%9E%9C%E3%81%8C%E8%A6%8B%E3%81%88%E3%81%AA%E3%81%8F%E3%81%AA%E3%82%8B\"\u003e変更が重なると、因果が見えなくなる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%BF%BD%E3%81%88%E3%81%AA%E3%81%84%E3%81%A8%E3%81%AF%E3%81%A9%E3%81%86%E3%81%84%E3%81%86%E7%8A%B6%E6%85%8B%E3%81%8B\"\u003e「追えない」とは、どういう状態か\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%80%A3%E9%8E%96%E3%81%8C%E7%B6%9A%E3%81%8F%E6%9D%A1%E4%BB%B6%E3%81%AF%E5%9B%A0%E6%9E%9C%E3%81%8C%E8%A6%8B%E3%81%88%E3%82%8B%E3%81%93%E3%81%A8\"\u003e連鎖が続く条件は「因果が見えること」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%81%E3%83%BC%E3%83%A0%E3%81%A7%E3%81%AF%E3%81%95%E3%82%89%E3%81%AB%E5%95%8F%E9%A1%8C%E3%81%8C%E5%A4%A7%E3%81%8D%E3%81%8F%E3%81%AA%E3%82%8B\"\u003eチームでは、さらに問題が大きくなる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%94%B9%E5%96%84%E3%82%92%E6%AD%A2%E3%82%81%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%AB\"\u003e改善を止めないためのルール\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"改善を止めないために必要なもの\"\u003e改善を止めないために必要なもの\u003c/h2\u003e\n\u003cp\u003e第6章で見たように、\u003cbr\u003e\n最初の一手は「判断を動かす」ことから始まります。\u003c/p\u003e\n\u003cp\u003eこの一手がうまくいくと、\u003cbr\u003e\n現場では次に、こんな感覚が生まれます。\u003c/p\u003e\n\u003cp\u003e「もう少し、ここも直せそうだ」\u003cbr\u003e\n「次は、あの判断も整理できそうだ」\u003c/p\u003e\n\u003cp\u003e設計改善が、\u003cbr\u003e\n\u003cstrong\u003e連鎖し始める瞬間\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003eしかし、この連鎖は、\u003cbr\u003e\n意外と簡単に途切れます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"連鎖が途切れる典型的な瞬間\"\u003e連鎖が途切れる典型的な瞬間\u003c/h3\u003e\n\u003cp\u003e連鎖が止まるのは、\u003cbr\u003e\n多くの場合、次の判断をしたときです。\u003c/p\u003e\n\u003cp\u003e「今の流れで、\u003cbr\u003e\n　まとめて構造も整理してしまおう」\u003c/p\u003e\n\u003cp\u003e判断を一つ動かせた成功体験があると、\u003cbr\u003e\nつい、こうしたくなります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eクラス構成を整理する\u003c/li\u003e\n\u003cli\u003eパッケージを切り直す\u003c/li\u003e\n\u003cli\u003e似た責務をまとめる\u003c/li\u003e\n\u003cli\u003e命名を一気に整える\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e結果として、\u003cbr\u003e\nコードはきれいになります。\u003c/p\u003e\n\u003cp\u003eしかし、\u003cbr\u003e\nここで一気に構造を触ると、\u003cbr\u003e\n改善の連鎖は途切れます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"なぜ一気に触ると連鎖が止まるのか\"\u003eなぜ一気に触ると、連鎖が止まるのか\u003c/h3\u003e\n\u003cp\u003e理由は単純です。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e判断の変化が、追えなくなるからです。\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断を一つだけ動かした場合\"\u003e判断を一つだけ動かした場合\u003c/h3\u003e\n\u003cp\u003eたとえば、\u003cbr\u003e\n第6章で扱ったように、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e散らばっていた if の判断を\u003c/li\u003e\n\u003cli\u003eSpecialDiscountPolicy に集めた\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの変更は、\u003cbr\u003e\nとても説明しやすい状態です。\u003c/p\u003e\n\u003cp\u003e「特別割引という判断を、\u003cbr\u003e\n　このクラスに置きました」\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e何が変わったのか\u003c/li\u003e\n\u003cli\u003eなぜ変えたのか\u003c/li\u003e\n\u003cli\u003eどの判断を動かしたのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eが、\u003cbr\u003e\n一文で説明できます。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e変わった判断が、ひとつだけ\u003c/strong\u003e\u003cbr\u003e\nだからです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"変更が重なると因果が見えなくなる\"\u003e変更が重なると、因果が見えなくなる\u003c/h3\u003e\n\u003cp\u003e一方で、\u003cbr\u003e\n次のような変更を同時に行った場合を考えてみてください。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e判断を切り出した\u003c/li\u003e\n\u003cli\u003eクラスを分割した\u003c/li\u003e\n\u003cli\u003eパッケージを整理した\u003c/li\u003e\n\u003cli\u003eutil を削除した\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eコードの見た目は、\u003cbr\u003e\n確実に良くなっています。\u003c/p\u003e","title":"第7章：改善を止めないために必要なもの"},{"content":" 状態とは何か 状態は、判断を繰り返させないための装置 状態が嘘をつくと、設計は壊れる 「ありえない状態」を表現できてはいけない 状態は、判断が終わった世界を表す この章のまとめ 設計の話をしていると、 「状態」という言葉が、 とても曖昧に使われがちです。\n画面の表示状態 一時的な入力値 データベースの中身 これらはすべて「状態」と呼ばれます。\nしかし本書では、 もう一段、踏み込んで定義します。\n状態とは何か 本書における状態とは、\n判断の結果を、構造として保持したもの\nです。\n言い換えると、\n状態は、判断そのものではない 状態は、判断が終わった「あと」の姿 です。\n「今、何ができるのか」 「次に何をしてよいのか」\nそれらはすべて、 状態が表現しています。\n状態は、判断を繰り返させないための装置 判断が構造で表現されていない設計では、\n毎回 if で確認する 毎回 null チェックをする 毎回条件を思い出す ということが起きます。\nこれは、 同じ判断を何度も繰り返している 状態です。\n良い設計では、\n一度判断したら その結果を状態として持ち 以降は状態を見るだけ になります。\n状態とは、 判断を 保存するための構造 です。\n状態が嘘をつくと、設計は壊れる 状態が正しく設計されていないと、 次のようなコードが生まれます。\n本当は使えないのに、使えてしまう 本当は準備中なのに、完了に見える 条件次第で意味が変わるフラグ これはすべて、\n状態が、判断結果を正しく表現できていない 状態です。\n状態が嘘をつくと、 判断が再び人に戻ってきます。\n「ありえない状態」を表現できてはいけない 良い状態設計では、\nありえない組み合わせ 矛盾した状態 中途半端な段階 を、そもそも表現できません。\nたとえば、\nLoading と Ready が同時に true 取得エラーなのにデータが存在する 未初期化なのに操作できる こうした状態を、 型や構造で排除します。\nこれは、 「注意する」話ではありません。\n表現 (実装) できないようにする という設計の話です。\n状態は、判断が終わった世界を表す 第6章で、 境界の話をしました。\n状態は、 その境界の 内側 にあります。\nつまり、\n状態を見るコードは もう判断をしなくてよい 世界です。\n状態が正しく設計されていれば、\n「この状態なら、これをしてよい」 「この状態なら、迷わなくてよい」 という前提が、 構造として保証されます。\nこの章のまとめ 状態とは、判断の結果である 状態は、判断を繰り返させないための構造である 状態が嘘をつくと、判断が人に戻る 良い設計では、ありえない状態を表現できない 次の章では、 この「判断」が いつ起きるのか。\nつまり、 判断が発生する「瞬間」について、 イベントという切り口から見ていきます。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/07-state-has-result-of-judgement/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B\"\u003e状態とは何か\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E3%81%AF%E5%88%A4%E6%96%AD%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%95%E3%81%9B%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%81%AE%E8%A3%85%E7%BD%AE\"\u003e状態は、判断を繰り返させないための装置\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E3%81%8C%E5%98%98%E3%82%92%E3%81%A4%E3%81%8F%E3%81%A8%E8%A8%AD%E8%A8%88%E3%81%AF%E5%A3%8A%E3%82%8C%E3%82%8B\"\u003e状態が嘘をつくと、設計は壊れる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%82%E3%82%8A%E3%81%88%E3%81%AA%E3%81%84%E7%8A%B6%E6%85%8B%E3%82%92%E8%A1%A8%E7%8F%BE%E3%81%A7%E3%81%8D%E3%81%A6%E3%81%AF%E3%81%84%E3%81%91%E3%81%AA%E3%81%84\"\u003e「ありえない状態」を表現できてはいけない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%8C%E7%B5%82%E3%82%8F%E3%81%A3%E3%81%9F%E4%B8%96%E7%95%8C%E3%82%92%E8%A1%A8%E3%81%99\"\u003e状態は、判断が終わった世界を表す\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e設計の話をしていると、\n「状態」という言葉が、\nとても曖昧に使われがちです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e画面の表示状態\u003c/li\u003e\n\u003cli\u003e一時的な入力値\u003c/li\u003e\n\u003cli\u003eデータベースの中身\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらはすべて「状態」と呼ばれます。\u003c/p\u003e\n\u003cp\u003eしかし本書では、\nもう一段、踏み込んで定義します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"状態とは何か\"\u003e状態とは何か\u003c/h2\u003e\n\u003cp\u003e本書における状態とは、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e判断の結果を、構造として保持したもの\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003cp\u003e言い換えると、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e状態は、判断そのものではない\u003c/li\u003e\n\u003cli\u003e状態は、判断が終わった「あと」の姿\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003cp\u003e「今、何ができるのか」\n「次に何をしてよいのか」\u003c/p\u003e\n\u003cp\u003eそれらはすべて、\n状態が表現しています。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"状態は判断を繰り返させないための装置\"\u003e状態は、判断を繰り返させないための装置\u003c/h2\u003e\n\u003cp\u003e判断が構造で表現されていない設計では、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e毎回 if で確認する\u003c/li\u003e\n\u003cli\u003e毎回 null チェックをする\u003c/li\u003e\n\u003cli\u003e毎回条件を思い出す\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eということが起きます。\u003c/p\u003e\n\u003cp\u003eこれは、\n\u003cstrong\u003e同じ判断を何度も繰り返している\u003c/strong\u003e\n状態です。\u003c/p\u003e\n\u003cp\u003e良い設計では、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e一度判断したら\u003c/li\u003e\n\u003cli\u003eその結果を状態として持ち\u003c/li\u003e\n\u003cli\u003e以降は状態を見るだけ\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eになります。\u003c/p\u003e\n\u003cp\u003e状態とは、\n判断を \u003cstrong\u003e保存するための構造\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"状態が嘘をつくと設計は壊れる\"\u003e状態が嘘をつくと、設計は壊れる\u003c/h2\u003e\n\u003cp\u003e状態が正しく設計されていないと、\n次のようなコードが生まれます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e本当は使えないのに、使えてしまう\u003c/li\u003e\n\u003cli\u003e本当は準備中なのに、完了に見える\u003c/li\u003e\n\u003cli\u003e条件次第で意味が変わるフラグ\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれはすべて、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e状態が、判断結果を正しく表現できていない\u003c/strong\u003e\n状態です。\u003c/p\u003e\n\u003cp\u003e状態が嘘をつくと、\n判断が再び人に戻ってきます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"ありえない状態を表現できてはいけない\"\u003e「ありえない状態」を表現できてはいけない\u003c/h2\u003e\n\u003cp\u003e良い状態設計では、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eありえない組み合わせ\u003c/li\u003e\n\u003cli\u003e矛盾した状態\u003c/li\u003e\n\u003cli\u003e中途半端な段階\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを、\u003cstrong\u003eそもそも表現できません。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eたとえば、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eLoading と Ready が同時に true\u003c/li\u003e\n\u003cli\u003e取得エラーなのにデータが存在する\u003c/li\u003e\n\u003cli\u003e未初期化なのに操作できる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうした状態を、\n型や構造で排除します。\u003c/p\u003e","title":"第7章：状態は判断の結果を保持する"},{"content":" 本書における「イベント」とは何か イベントは「判断の起点」ではない イベントは「判断が終わったこと」を表す なぜ、イベントが明確だと境界を越えたと分かるのか イベントは、境界を越えたことの通知である 判断が終わっていないものは、イベントではない この章のまとめ 本書における「イベント」とは何か 一般に、 イベントというと、\nonClick onTextChanged onResume のような、 UI やフレームワークが発火する通知 を思い浮かべるかもしれません。\nしかし、 本書で扱う「イベント」は、 それらとは少し意味が違います。\n本書におけるイベントとは、\n判断が完了したことを、 構造として外部に表現するもの\nです。\nイベントは「判断の起点」ではない よくある誤解として、\nイベントが来たから判断する イベントを受けて状態をチェックする という考え方があります。\nしかしこの考え方では、 判断はイベントの 後工程 に残ります。\nその結果、\nif が増える 状態チェックが散らばる 「このイベントは安全か？」を毎回考える という構造になります。\nこれは、 イベントが判断を内包していない 状態です。\nイベントは「判断が終わったこと」を表す 本書でのイベントは、 次の役割を持ちます。\n判断がすでに完了している 前提条件はすべて満たされている 境界を越えてよい状態になった つまりイベントは、\n「ここまでの判断はすべて終わりました」 という合図\nです。\nイベントは、 これ以上判断を進めるための材料ではありません。\n判断を 終わらせた結果 です。\nなぜ、イベントが明確だと境界を越えたと分かるのか イベントが明確であるとは、\n判断済みの値しか持たない 未検証・未確定な情報を含まない そのイベントが存在するだけで前提が成立している という状態です。\nこのようなイベントは、\n境界の内側でしか生成できず 境界の外側では、前提を疑う必要がありません そのため、\nそのイベントを受け取った瞬間に、 「判断はすでに終わっている」と分かる\nのです。\nイベントは、境界を越えたことの通知である 境界とは、\n判断を行う世界 前提を確認する世界 と、\n判断を信じてよい世界 前提を疑わなくてよい世界 を分ける線でした。\nイベントは、\nその境界を越えたことを知らせる唯一の手段 です。\nだからこそ、\n境界の外では if が消え 状態チェックが不要になり 処理は単純になる のです。\n判断が終わっていないものは、イベントではない もしイベントが、\n曖昧な名前 未検証の値 「まだ判断が必要そうな情報」 を含んでいる場合、\nそのイベントを受け取った側は、\n本当に安全か？ この状態で呼んでいいのか？ と、 再び判断を始めてしまいます。\nこれは、\nイベントが境界を越えていない 状態です。\nこの章のまとめ 本書におけるイベントは、UI 通知ではない イベントは「判断が起きる瞬間」を表す それは「判断が完了した」という合図である 明確なイベントは、境界を越えたことを示す イベントが曖昧だと、判断は終わらない ","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/08-event-represents-completion-of-judgement/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9C%AC%E6%9B%B8%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B\"\u003e本書における「イベント」とは何か\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%AE%E8%B5%B7%E7%82%B9%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003eイベントは「判断の起点」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%8C%E7%B5%82%E3%82%8F%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8%E3%82%92%E8%A1%A8%E3%81%99\"\u003eイベントは「判断が終わったこと」を表す\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%8C%E6%98%8E%E7%A2%BA%E3%81%A0%E3%81%A8%E5%A2%83%E7%95%8C%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%81%A8%E5%88%86%E3%81%8B%E3%82%8B%E3%81%AE%E3%81%8B\"\u003eなぜ、イベントが明確だと境界を越えたと分かるのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AF%E5%A2%83%E7%95%8C%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%81%93%E3%81%A8%E3%81%AE%E9%80%9A%E7%9F%A5%E3%81%A7%E3%81%82%E3%82%8B\"\u003eイベントは、境界を越えたことの通知である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%8C%E7%B5%82%E3%82%8F%E3%81%A3%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%82%82%E3%81%AE%E3%81%AF%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e判断が終わっていないものは、イベントではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"本書におけるイベントとは何か\"\u003e本書における「イベント」とは何か\u003c/h2\u003e\n\u003cp\u003e一般に、\nイベントというと、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eonClick\u003c/li\u003e\n\u003cli\u003eonTextChanged\u003c/li\u003e\n\u003cli\u003eonResume\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eのような、\n\u003cstrong\u003eUI やフレームワークが発火する通知\u003c/strong\u003e\nを思い浮かべるかもしれません。\u003c/p\u003e\n\u003cp\u003eしかし、\n本書で扱う「イベント」は、\nそれらとは少し意味が違います。\u003c/p\u003e\n\u003cp\u003e本書におけるイベントとは、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e判断が完了したことを、\n構造として外部に表現するもの\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"イベントは判断の起点ではない\"\u003eイベントは「判断の起点」ではない\u003c/h2\u003e\n\u003cp\u003eよくある誤解として、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eイベントが来たから判断する\u003c/li\u003e\n\u003cli\u003eイベントを受けて状態をチェックする\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという考え方があります。\u003c/p\u003e\n\u003cp\u003eしかしこの考え方では、\n判断はイベントの \u003cstrong\u003e後工程\u003c/strong\u003e に残ります。\u003c/p\u003e\n\u003cp\u003eその結果、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eif が増える\u003c/li\u003e\n\u003cli\u003e状態チェックが散らばる\u003c/li\u003e\n\u003cli\u003e「このイベントは安全か？」を毎回考える\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという構造になります。\u003c/p\u003e\n\u003cp\u003eこれは、\n\u003cstrong\u003eイベントが判断を内包していない\u003c/strong\u003e\n状態です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"イベントは判断が終わったことを表す\"\u003eイベントは「判断が終わったこと」を表す\u003c/h2\u003e\n\u003cp\u003e本書でのイベントは、\n次の役割を持ちます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e判断がすでに完了している\u003c/li\u003e\n\u003cli\u003e前提条件はすべて満たされている\u003c/li\u003e\n\u003cli\u003e境界を越えてよい状態になった\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eつまりイベントは、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e「ここまでの判断はすべて終わりました」\nという合図\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003cp\u003eイベントは、\nこれ以上判断を進めるための材料ではありません。\u003c/p\u003e\n\u003cp\u003e判断を \u003cstrong\u003e終わらせた結果\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"なぜイベントが明確だと境界を越えたと分かるのか\"\u003eなぜ、イベントが明確だと境界を越えたと分かるのか\u003c/h2\u003e\n\u003cp\u003eイベントが明確であるとは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e判断済みの値しか持たない\u003c/li\u003e\n\u003cli\u003e未検証・未確定な情報を含まない\u003c/li\u003e\n\u003cli\u003eそのイベントが存在するだけで前提が成立している\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという状態です。\u003c/p\u003e\n\u003cp\u003eこのようなイベントは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e境界の内側でしか生成できず\u003c/li\u003e\n\u003cli\u003e境界の外側では、前提を疑う必要がありません\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eそのため、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eそのイベントを受け取った瞬間に、\n「判断はすでに終わっている」と分かる\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eのです。\u003c/p\u003e","title":"第8章：イベントとは「判断が完了したこと」を表す構造である"},{"content":" 設計が属人化する本当の理由 レビューは、正解探しではなく判断の確認である 設計の会話は「構造」ではなく「理由」から始める 暗黙知を減らすための小さな工夫 判断が共有されると、責任も分散される チームで設計するとはどういうことか まとめ 前章では、判断をコードに残す方法として、 名前・型・境界という具体的な手段を見てきました。\nしかし、実際の開発は一人では行われません。 判断は、必ずチームの中で扱われます。\nこの章では、 判断を属人化させず、チームで扱える状態にするにはどうすればよいか をテーマに掘り下げていきます。\n設計が属人化する本当の理由 設計が属人化している現場では、よく次のような状態が見られます。\nあの人しか触れないコードがある 変更前に必ず特定の人に確認が必要 レビューが形式的になっている これは単に「その人が優秀だから」ではありません。\n多くの場合、 判断がコードの外に置かれている ことが原因です。\nなぜそうなっているのか どこを壊してよいのか どこは触ってはいけないのか これらが共有されていなければ、 設計は必然的に人にひもづきます。\nレビューは、正解探しではなく判断の確認である コードレビューというと、\n書き方が正しいか パフォーマンスに問題がないか 規約に違反していないか といった点に目が向きがちです。\nもちろん重要ですが、 それだけでは設計レビューにはなりません。\n設計レビューで確認すべきなのは、\nこの変更で、どんな判断を置いたのか 既存の判断は変わっていないか 判断の置き場所は適切か という点です。\nレビューとは、 判断の共有と再確認の場 です。\n設計の会話は「構造」ではなく「理由」から始める 設計の相談や議論が噛み合わないとき、 話題がいきなり構造から始まっていることがあります。\nこのクラスを分けるべきか モジュールを切るべきか 共通化した方がよいか こうした問いは、 理由が共有されていない状態では平行線になります。\n先に共有すべきなのは、\n何が変わりやすいのか 何を守りたいのか 今回はどこを優先するのか という判断の前提です。\n理由が共有されていれば、 構造の選択肢は自然に絞られます。\n暗黙知を減らすための小さな工夫 判断をすべてドキュメント化する必要はありません。\nしかし、 暗黙知のままにしないための小さな工夫 は有効です。\nPR の説明に「今回置いた判断」を一行書く レビューコメントで「ここはあえて分けていない理由」を残す 名前を変えるときに、責務の境界が分かる名前にする これだけでも、 判断は少しずつコードの外に漏れにくくなります。\n判断が共有されると、責任も分散される 判断が共有されていないチームでは、\n設計ミスの責任が個人に集中する 変更が怖くなる 新しい提案が出にくくなる という問題が起きがちです。\n判断が共有されていれば、\n設計はチームのものになる 壊すことへの心理的負担が減る 改善の提案がしやすくなる 設計は、 個人技からチームプレイへ 変わっていきます。\nチームで設計するとはどういうことか チームで設計するとは、 全員が同じ答えを持つことではありません。\nどこに判断があるか分かる どこを変えればよいか議論できる 違いを前提に合意できる この状態を作ることが目的です。\n設計とは、 合意形成のための共通言語 でもあります。\nまとめ 設計が属人化する原因は、判断が共有されていないことにある レビューは判断を確認し、更新する場である 構造ではなく理由から会話を始める 判断が共有されることで、設計はチームのものになる 次章では、 これまでの内容を踏まえ、 設計者の責任とは何かを改めて考えます。\n","permalink":"https://design.okuda-studio.com/books/003-design-that-locks-in-judgment/08-/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E5%B1%9E%E4%BA%BA%E5%8C%96%E3%81%99%E3%82%8B%E6%9C%AC%E5%BD%93%E3%81%AE%E7%90%86%E7%94%B1\"\u003e設計が属人化する本当の理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC%E3%81%AF%E6%AD%A3%E8%A7%A3%E6%8E%A2%E3%81%97%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%E5%88%A4%E6%96%AD%E3%81%AE%E7%A2%BA%E8%AA%8D%E3%81%A7%E3%81%82%E3%82%8B\"\u003eレビューは、正解探しではなく判断の確認である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AE%E4%BC%9A%E8%A9%B1%E3%81%AF%E6%A7%8B%E9%80%A0%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%E7%90%86%E7%94%B1%E3%81%8B%E3%82%89%E5%A7%8B%E3%82%81%E3%82%8B\"\u003e設計の会話は「構造」ではなく「理由」から始める\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9A%97%E9%BB%99%E7%9F%A5%E3%82%92%E6%B8%9B%E3%82%89%E3%81%99%E3%81%9F%E3%82%81%E3%81%AE%E5%B0%8F%E3%81%95%E3%81%AA%E5%B7%A5%E5%A4%AB\"\u003e暗黙知を減らすための小さな工夫\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%8C%E5%85%B1%E6%9C%89%E3%81%95%E3%82%8C%E3%82%8B%E3%81%A8%E8%B2%AC%E4%BB%BB%E3%82%82%E5%88%86%E6%95%A3%E3%81%95%E3%82%8C%E3%82%8B\"\u003e判断が共有されると、責任も分散される\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%81%E3%83%BC%E3%83%A0%E3%81%A7%E8%A8%AD%E8%A8%88%E3%81%99%E3%82%8B%E3%81%A8%E3%81%AF%E3%81%A9%E3%81%86%E3%81%84%E3%81%86%E3%81%93%E3%81%A8%E3%81%8B\"\u003eチームで設計するとはどういうことか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003e前章では、判断をコードに残す方法として、\n名前・型・境界という具体的な手段を見てきました。\u003c/p\u003e\n\u003cp\u003eしかし、実際の開発は一人では行われません。\n判断は、必ずチームの中で扱われます。\u003c/p\u003e\n\u003cp\u003eこの章では、\n\u003cstrong\u003e判断を属人化させず、チームで扱える状態にするにはどうすればよいか\u003c/strong\u003e\nをテーマに掘り下げていきます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"設計が属人化する本当の理由\"\u003e設計が属人化する本当の理由\u003c/h3\u003e\n\u003cp\u003e設計が属人化している現場では、よく次のような状態が見られます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eあの人しか触れないコードがある\u003c/li\u003e\n\u003cli\u003e変更前に必ず特定の人に確認が必要\u003c/li\u003e\n\u003cli\u003eレビューが形式的になっている\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれは単に「その人が優秀だから」ではありません。\u003c/p\u003e\n\u003cp\u003e多くの場合、\n\u003cstrong\u003e判断がコードの外に置かれている\u003c/strong\u003e ことが原因です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eなぜそうなっているのか\u003c/li\u003e\n\u003cli\u003eどこを壊してよいのか\u003c/li\u003e\n\u003cli\u003eどこは触ってはいけないのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらが共有されていなければ、\n設計は必然的に人にひもづきます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"レビューは正解探しではなく判断の確認である\"\u003eレビューは、正解探しではなく判断の確認である\u003c/h3\u003e\n\u003cp\u003eコードレビューというと、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e書き方が正しいか\u003c/li\u003e\n\u003cli\u003eパフォーマンスに問題がないか\u003c/li\u003e\n\u003cli\u003e規約に違反していないか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった点に目が向きがちです。\u003c/p\u003e\n\u003cp\u003eもちろん重要ですが、\nそれだけでは設計レビューにはなりません。\u003c/p\u003e\n\u003cp\u003e設計レビューで確認すべきなのは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこの変更で、どんな判断を置いたのか\u003c/li\u003e\n\u003cli\u003e既存の判断は変わっていないか\u003c/li\u003e\n\u003cli\u003e判断の置き場所は適切か\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという点です。\u003c/p\u003e\n\u003cp\u003eレビューとは、\n\u003cstrong\u003e判断の共有と再確認の場\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"設計の会話は構造ではなく理由から始める\"\u003e設計の会話は「構造」ではなく「理由」から始める\u003c/h3\u003e\n\u003cp\u003e設計の相談や議論が噛み合わないとき、\n話題がいきなり構造から始まっていることがあります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこのクラスを分けるべきか\u003c/li\u003e\n\u003cli\u003eモジュールを切るべきか\u003c/li\u003e\n\u003cli\u003e共通化した方がよいか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうした問いは、\n理由が共有されていない状態では平行線になります。\u003c/p\u003e\n\u003cp\u003e先に共有すべきなのは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e何が変わりやすいのか\u003c/li\u003e\n\u003cli\u003e何を守りたいのか\u003c/li\u003e\n\u003cli\u003e今回はどこを優先するのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという判断の前提です。\u003c/p\u003e\n\u003cp\u003e理由が共有されていれば、\n構造の選択肢は自然に絞られます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"暗黙知を減らすための小さな工夫\"\u003e暗黙知を減らすための小さな工夫\u003c/h3\u003e\n\u003cp\u003e判断をすべてドキュメント化する必要はありません。\u003c/p\u003e\n\u003cp\u003eしかし、\n\u003cstrong\u003e暗黙知のままにしないための小さな工夫\u003c/strong\u003e は有効です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ePR の説明に「今回置いた判断」を一行書く\u003c/li\u003e\n\u003cli\u003eレビューコメントで「ここはあえて分けていない理由」を残す\u003c/li\u003e\n\u003cli\u003e名前を変えるときに、責務の境界が分かる名前にする\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれだけでも、\n判断は少しずつコードの外に漏れにくくなります。\u003c/p\u003e","title":"第8章：判断をチームで共有する"},{"content":" 設計力とは、再現可能な判断の質 本書で扱ってきた設計は、実は同じ話をしている 判断はどこに置かれているか その判断は説明できるか 判断の変化を追えるか その判断は再現可能か 設計力とは、再現可能な判断の質 設計力とは、再現可能な判断の質である ここまで本書では、\nモノリスや設計改善という題材を通して、\nさまざまな話をしてきました。\n一見すると、\n章ごとにテーマは違って見えるかもしれません。\nしかし振り返ってみると、\n私たちはずっと、\n同じ対象に対して、別の角度から向き合ってきた\nことに気づきます。\nそれは、\n判断 です。\n本書でやってきたことを振り返る 各章で扱ってきた内容を、\n「判断に対して何をしてきたか」という観点で整理すると、\n次のようになります。\n判断を 見つける 判断を 切り出す 判断に 名前をつける 判断を 動かす 判断の 変化を追う 章ごとに扱っていたのは、\n構造でも、クラス分割でも、if 文でもありません。\n判断そのものに、どう向き合うか\nを扱ってきました。\n判断を見つける 多くのモノリスでは、\n判断はすでに存在しています。\nただし、\nそれは明示されていません。\nif 文の奥に隠れていたり、\n複数の条件に分散していたり、\n暗黙の前提として人の頭の中にあったりします。\n設計改善の最初の一歩は、\n新しい構造を作ることではなく、\n「ここには判断がある」\nと気づくこと\nでした。\n判断を切り出す 判断に気づいても、\nそれがコードの中に埋もれたままでは、\n扱うことができません。\nそこで私たちは、\n条件式 分岐 ロジックの塊 から、\n判断を切り出す\nということを行いました。\nこれは、判断を\n「独立した存在として扱える状態」に\nするための行為です。\n判断に名前をつける 切り出された判断は、\nまだ不安定です。\nなぜなら、\n名前がない判断は、\n意味が固定されないからです。\nisEligible SpecialDiscountPolicy こうした名前を与えることで、\n判断は初めて、\n何についての判断なのか どの文脈に属するのか を語れるようになります。\n名前をつけることは、\n判断に意味を与えること\nでした。\n判断を動かす 判断に名前がつくと、\n次に見えてくるのが\n置き場所の問題 です。\nその判断は、\n本当に今の場所にあるべきなのか。\n呼び出し側にあるべきか。 ドメインのルールとして存在すべきか。 判断を\n「よりふさわしい場所」へ移すこと。\nそれが、\nモノリスを前にしたときの\n最初の一手 でした。\n判断の変化を追う 判断を動かしたあと、\nすぐに構造全体を触りたくなる誘惑があります。\nしかし本書では、\nそこで一度立ち止まりました。\nなぜなら、\n判断がどう変わったのか\nを追えなくなるからです。\n小さな判断の変化を追うことで、\n何が改善されたのか どこに次の一手を打つべきか を自分たちの言葉で説明できるようになります。\n判断を「説明できる」 ここまで、\n判断を見つけ、\n切り出し、\n名前をつけ、\n動かし、\n変化を追ってきました。\nもう一つ、\nとても重要なことがあります。\nそれは、\n判断を説明できるかどうか です。\nコードがあっても、説明できない設計は多い 次のような説明を、\n聞いたことはないでしょうか。\n「昔からこうなっていて……」 「前の担当者がそうしていたので……」 「とりあえずこの条件が必要で……」 コードはあります。\n動きもします。\nしかし、\nなぜその判断が存在するのか\nを説明できません。\nこの状態では、\n設計はすでに失われています。\n判断を説明できるとは、どういうことか 「判断を説明できる」とは、\nなぜこの条件があるのか どんな状態を守ろうとしているのか 何が変わったら、この判断は変わるのか これを、\nコードを見せなくても言葉で話せる\n状態のことです。\n判断に所属があると、説明できる isEligible の例を思い出してください。\nclass SpecialDiscountPolicy { fun isEligible(user: User, order: Order): Boolean { ... } } この判断は、\n特別割引というルールに属している 割引の可否を定義している と説明できます。\n一方で、\nif (canApplySpecialDiscount(user, order)) { ... } この判断は、\nどの概念の判断なのか 何を守るための条件なのか を説明しにくい。\n判断の置き場所が決まると、\n説明の起点が生まれる\nということです。\n説明できない判断は、再現できない 本書では、\n設計力を\n再現可能な判断の質\nと定義します。\n説明できない判断は、\n再現できません。\nなぜそうしたのか分からない どこを真似すればよいか分からない 次の場面で応用できない からです。\n逆に言えば、\n判断を説明できるようになった瞬間、\n設計は他人に渡せるものになります。\n設計力とは何だったのか 設計力とは、\n特別なテクニックの集合ではありません。\n正しい構造を一発で作る力でもない 複雑なリファクタリング手順を知っていることでもない それは、\n判断を扱う力 です。\n見つけ、\n切り出し、\n名前をつけ、\n動かし、\n変化を追い、\n説明できる。\nこの一連の行為を、\n別のコードベースでも、\n別の文脈でも、\n繰り返せる。\nそれが、\n再現可能な判断の質\nです。\nおわりに モノリスは、\n必ずしも悪ではありません。\nただ、\n判断が見えなくなったとき、\n理解不能な塊になります。\n設計とは、\nその塊に、\n再び意味を与える行為です。\n次にあなたが\n大きなコードを前にしたとき、\n構造を見る前に、\n判断を探してみてください。\nそこから、\n設計はまた、\n動き始めます。\n","permalink":"https://design.okuda-studio.com/books/002-design-starts-with-decisions/08-what-is-design-competence/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E5%8A%9B%E3%81%A8%E3%81%AF%E5%86%8D%E7%8F%BE%E5%8F%AF%E8%83%BD%E3%81%AA%E5%88%A4%E6%96%AD%E3%81%AE%E8%B3%AA\"\u003e設計力とは、再現可能な判断の質\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9C%AC%E6%9B%B8%E3%81%A7%E6%89%B1%E3%81%A3%E3%81%A6%E3%81%8D%E3%81%9F%E8%A8%AD%E8%A8%88%E3%81%AF%E5%AE%9F%E3%81%AF%E5%90%8C%E3%81%98%E8%A9%B1%E3%82%92%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B\"\u003e本書で扱ってきた設計は、実は同じ話をしている\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AF%E3%81%A9%E3%81%93%E3%81%AB%E7%BD%AE%E3%81%8B%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E3%81%8B\"\u003e判断はどこに置かれているか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%9D%E3%81%AE%E5%88%A4%E6%96%AD%E3%81%AF%E8%AA%AC%E6%98%8E%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%8B\"\u003eその判断は説明できるか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AE%E5%A4%89%E5%8C%96%E3%82%92%E8%BF%BD%E3%81%88%E3%82%8B%E3%81%8B\"\u003e判断の変化を追えるか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%9D%E3%81%AE%E5%88%A4%E6%96%AD%E3%81%AF%E5%86%8D%E7%8F%BE%E5%8F%AF%E8%83%BD%E3%81%8B\"\u003eその判断は再現可能か\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E5%8A%9B%E3%81%A8%E3%81%AF%E5%86%8D%E7%8F%BE%E5%8F%AF%E8%83%BD%E3%81%AA%E5%88%A4%E6%96%AD%E3%81%AE%E8%B3%AA-1\"\u003e設計力とは、再現可能な判断の質\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"設計力とは再現可能な判断の質である\"\u003e設計力とは、再現可能な判断の質である\u003c/h2\u003e\n\u003cp\u003eここまで本書では、\u003cbr\u003e\nモノリスや設計改善という題材を通して、\u003cbr\u003e\nさまざまな話をしてきました。\u003c/p\u003e\n\u003cp\u003e一見すると、\u003cbr\u003e\n章ごとにテーマは違って見えるかもしれません。\u003c/p\u003e\n\u003cp\u003eしかし振り返ってみると、\u003cbr\u003e\n私たちはずっと、\u003cbr\u003e\n\u003cstrong\u003e同じ対象に対して、別の角度から向き合ってきた\u003c/strong\u003e\u003cbr\u003e\nことに気づきます。\u003c/p\u003e\n\u003cp\u003eそれは、\u003cbr\u003e\n\u003cstrong\u003e判断\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"本書でやってきたことを振り返る\"\u003e本書でやってきたことを振り返る\u003c/h3\u003e\n\u003cp\u003e各章で扱ってきた内容を、\u003cbr\u003e\n「判断に対して何をしてきたか」という観点で整理すると、\u003cbr\u003e\n次のようになります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e判断を \u003cstrong\u003e見つける\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e判断を \u003cstrong\u003e切り出す\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e判断に \u003cstrong\u003e名前をつける\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e判断を \u003cstrong\u003e動かす\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e判断の \u003cstrong\u003e変化を追う\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e章ごとに扱っていたのは、\u003cbr\u003e\n構造でも、クラス分割でも、if 文でもありません。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e判断そのものに、どう向き合うか\u003c/strong\u003e\u003cbr\u003e\nを扱ってきました。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断を見つける\"\u003e判断を見つける\u003c/h3\u003e\n\u003cp\u003e多くのモノリスでは、\u003cbr\u003e\n判断はすでに存在しています。\u003c/p\u003e\n\u003cp\u003eただし、\u003cbr\u003e\nそれは明示されていません。\u003c/p\u003e\n\u003cp\u003eif 文の奥に隠れていたり、\u003cbr\u003e\n複数の条件に分散していたり、\u003cbr\u003e\n暗黙の前提として人の頭の中にあったりします。\u003c/p\u003e\n\u003cp\u003e設計改善の最初の一歩は、\u003cbr\u003e\n新しい構造を作ることではなく、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e「ここには判断がある」\u003cbr\u003e\nと気づくこと\u003c/strong\u003e\u003cbr\u003e\nでした。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断を切り出す\"\u003e判断を切り出す\u003c/h3\u003e\n\u003cp\u003e判断に気づいても、\u003cbr\u003e\nそれがコードの中に埋もれたままでは、\u003cbr\u003e\n扱うことができません。\u003c/p\u003e\n\u003cp\u003eそこで私たちは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e条件式\u003c/li\u003e\n\u003cli\u003e分岐\u003c/li\u003e\n\u003cli\u003eロジックの塊\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eから、\u003cbr\u003e\n\u003cstrong\u003e判断を切り出す\u003c/strong\u003e\u003cbr\u003e\nということを行いました。\u003c/p\u003e\n\u003cp\u003eこれは、判断を\u003cbr\u003e\n「独立した存在として扱える状態」に\u003cbr\u003e\nするための行為です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"判断に名前をつける\"\u003e判断に名前をつける\u003c/h3\u003e\n\u003cp\u003e切り出された判断は、\u003cbr\u003e\nまだ不安定です。\u003c/p\u003e","title":"第8章：設計力とは、再現可能な判断の質である"},{"content":" はじめに 「DDD（ドメイン駆動設計）は Android には重い」\nおそらく多くの Android エンジニアが、一度はそう感じたことがあるはずです。\nClean Architecture を参考に層を分け、UseCase を作り、Repository を定義し、気づけばクラスは増え続け、変更はむしろやりにくくなっている──そんな経験は珍しくありません。\n一方で、Web や業務系の世界では「DDD は当たり前」のように語られています。その温度差の中で、Android エンジニアはこう悩みます。\nDDD をやらないと設計力が低いと思われるのではないか でも、全部やると明らかにオーバーエンジニアリングになる 結局、どこまでやれば“正解”なのか分からない 本書は、その迷いに対する 現実的な答え を提示するために書きました。\nここで扱う DDD は、教科書的なフルセットの DDD ではありません。Aggregate Root を厳密に守る話も、巨大なエンタープライズシステムを前提とした話も、基本的にはしません。\n代わりに本書が重視するのは、次の一点です。\nAndroid アプリという制約の中で、設計が“役に立つ”状態をどう作るか。\nAndroid アプリ開発は、UI と状態の変更が中心です。仕様変更の多くは画面に現れ、非同期処理とライフサイクルが複雑さを生みます。この文脈を無視したまま DDD の型だけを持ち込むと、設計はすぐに形骸化します。\n本書では、DDD を「守るべきルール」ではなく、「判断のための視点」として扱います。\nどこに境界を引くと変更が楽になるのか どの責務はドメインに置く価値があり、どれは置かなくていいのか なぜその設計を選んだのかを、言葉で説明できる状態とは何か これらを、Android の実装文脈と結びつけながら解説していきます。\n想定読者は、次のような方です。\nMVVM や Clean Architecture は一通り実装したことがある UseCase や Repository を作ってはみたが、しっくりきていない 「設計が大事なのは分かるが、何が大事なのか分からない」と感じている 逆に、DDD の原理や用語を網羅的に学びたい方や、厳密な理論体系を求める方には、本書は向いていないかもしれません。\nこの本のゴールは、あなたが次に設計をするとき、\n「Android アプリという文脈で、なぜこの構造にするのか」を自分の言葉で説明できるようになること。\nそして、設計がプロダクトの足かせではなく、変更に耐えるための武器 になることです。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/01/","summary":"\u003chr\u003e\n\u003ch2 id=\"はじめに\"\u003eはじめに\u003c/h2\u003e\n\u003cp\u003e「DDD（ドメイン駆動設計）は Android には重い」\u003c/p\u003e\n\u003cp\u003eおそらく多くの Android エンジニアが、一度はそう感じたことがあるはずです。\u003c/p\u003e\n\u003cp\u003eClean Architecture を参考に層を分け、UseCase を作り、Repository を定義し、気づけばクラスは増え続け、変更はむしろやりにくくなっている──そんな経験は珍しくありません。\u003c/p\u003e\n\u003cp\u003e一方で、Web や業務系の世界では「DDD は当たり前」のように語られています。その温度差の中で、Android エンジニアはこう悩みます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDDD をやらないと設計力が低いと思われるのではないか\u003c/li\u003e\n\u003cli\u003eでも、全部やると明らかにオーバーエンジニアリングになる\u003c/li\u003e\n\u003cli\u003e結局、どこまでやれば“正解”なのか分からない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e本書は、その迷いに対する \u003cstrong\u003e現実的な答え\u003c/strong\u003e を提示するために書きました。\u003c/p\u003e\n\u003cp\u003eここで扱う DDD は、教科書的なフルセットの DDD ではありません。Aggregate Root を厳密に守る話も、巨大なエンタープライズシステムを前提とした話も、基本的にはしません。\u003c/p\u003e\n\u003cp\u003e代わりに本書が重視するのは、次の一点です。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAndroid アプリという制約の中で、設計が“役に立つ”状態をどう作るか。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eAndroid アプリ開発は、UI と状態の変更が中心です。仕様変更の多くは画面に現れ、非同期処理とライフサイクルが複雑さを生みます。この文脈を無視したまま DDD の型だけを持ち込むと、設計はすぐに形骸化します。\u003c/p\u003e\n\u003cp\u003e本書では、DDD を「守るべきルール」ではなく、「判断のための視点」として扱います。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどこに境界を引くと変更が楽になるのか\u003c/li\u003e\n\u003cli\u003eどの責務はドメインに置く価値があり、どれは置かなくていいのか\u003c/li\u003e\n\u003cli\u003eなぜその設計を選んだのかを、言葉で説明できる状態とは何か\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらを、Android の実装文脈と結びつけながら解説していきます。\u003c/p\u003e\n\u003cp\u003e想定読者は、次のような方です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eMVVM や Clean Architecture は一通り実装したことがある\u003c/li\u003e\n\u003cli\u003eUseCase や Repository を作ってはみたが、しっくりきていない\u003c/li\u003e\n\u003cli\u003e「設計が大事なのは分かるが、何が大事なのか分からない」と感じている\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e逆に、DDD の原理や用語を網羅的に学びたい方や、厳密な理論体系を求める方には、本書は向いていないかもしれません。\u003c/p\u003e\n\u003cp\u003eこの本のゴールは、あなたが次に設計をするとき、\u003c/p\u003e\n\u003cp\u003e「Android アプリという文脈で、なぜこの構造にするのか」を自分の言葉で説明できるようになること。\u003c/p\u003e\n\u003cp\u003eそして、設計がプロダクトの足かせではなく、\u003cstrong\u003e変更に耐えるための武器\u003c/strong\u003e になることです。\u003c/p\u003e","title":"はじめに"},{"content":" 悪い例：境界を越えたか分からないイベント 何が問題なのか 良い例：境界を越えたことが分かるイベント 状態（未判断の世界） イベント（判断完了の世界） ViewModel（判断を完了させる場所） ここで何が起きているか 境界の「手前」 境界の「向こう側」 イベントが「境界を越えた通知」になる理由 なぜ sealed class が効くのか この章のまとめ 第8章では、 本書における「イベント」を次のように定義しました。\nイベントとは、「判断が完了したこと」を表す構造 です。\nこれは、\nonClick onTextChanged onResume といった UI やフレームワークが発火する通知 とは、 まったく別の概念です。\nここでは、 この違いがコードとしてどう現れるのかを、 具体例で確認します。\n悪い例：境界を越えたか分からないイベント まずは、よくある実装から見てみます。\nclass FormViewModel : ViewModel() { private var uiState = FormUiState() fun onTextChanged(text: String) { uiState = uiState.copy(inputText = text) } fun onSubmitClicked() { // 本当に送信してよい状態か？ // ここで毎回判断する必要がある } } 一見、問題なさそうに見えます。\nしかし、この onSubmit() には、 次の疑問が常につきまといます。\n入力は本当に完了しているのか バリデーションは終わっているのか この時点で「判断」は終わっているのか コード上では、 どこで判断が完了したのかが分かりません。\nつまりこの onSubmit() は、\n境界を越えてよいのか分からない 毎回、中身を読まないと安全性が判断できない という状態です。\nこれは、 イベントが「判断済み」であることを表現できていない 典型例です。\n何が問題なのか 問題は、 「onSubmit という関数があること」ではありません。\n問題は、\nこの呼び出しが、 判断の途中なのか、判断が完了した後なのかが、 型から分からない\nことです。\nそのため、\nViewModel 内で再度 if が必要になり レビューやテストに判断が押し出され 「正しく使ってね」という前提が増えていきます これは、 第3章で述べた 判断が構造で表現されていない状態 です。\n良い例：境界を越えたことが分かるイベント ポイントは 1 つだけです。\nViewModel の中に「未判断の世界」と「判断済みの世界」を両方置き、 その境界を Event で表現する\n状態（未判断の世界） data class FormUiState( val inputText: String = \u0026#34;\u0026#34; ) これは、\n入力途中 編集中 まだ Submit してよいか分からない 未判断の世界の状態 です。\nイベント（判断完了の世界） sealed interface FormEvent { data class Submit( val text: String ) : FormEvent } この Event は、\nバリデーションが終わり Submit してよいと判断された 判断完了の結果 だけを表します。\nViewModel（判断を完了させる場所） class FormViewModel : ViewModel() { private var uiState = FormUiState() fun onTextChanged(text: String) { uiState = uiState.copy(inputText = text) } fun onSubmitClicked() { val text = uiState.inputText // ここで判断を行う if (text.isBlank()) { // 判断を通過できなかったデータは境界を越えられない return } val event = FormEvent.Submit(text) handleEvent(event) } private fun handleEvent(event: FormEvent) { when (event) { is FormEvent.Submit -\u0026gt; { // ここでは「判断済み」であることを信じてよい submit(event.text) } } } private fun submit(text: String) { // 安全に処理できる } } ここで何が起きているか この ViewModel の中には、明確な境界 があります。\n境界の「手前」 FormUiState onTextChanged onSubmitClicked if による検証 ここは 未判断の世界 です。\n境界の「向こう側」 FormEvent.Submit handleEvent submit ここは 判断済みの世界 です。\nイベントが「境界を越えた通知」になる理由 この構造では、\n判断は UI 層側で完了し Event がその結果を表し ViewModel は「判断済みの世界」だけを扱う という分離が成立します。\nつまり、\nイベントとは、 「判断が完了し、境界を越えてよい状態になった」 という事実の通知 なのです。\nなぜ sealed class が効くのか sealed class を使うことで、\n判断が終わっていない状態を Event にできない 種類が増えたらコンパイルエラーで気づける 「何が起こりうるか」が構造として閉じる という効果が得られます。\nこれはまさに、\n判断を構造で表現している 状態です。\nこの章のまとめ 本書におけるイベントは、UI イベントではない イベントとは、「判断が完了したこと」を表す構造 Event が生成できた時点で、境界を越えてよい sealed class は、「判断済み」を型で保証する 第8章で述べた抽象的な定義は、 このように コードとして具体化 されます。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/08-x-event-sample/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E6%82%AA%E3%81%84%E4%BE%8B%E5%A2%83%E7%95%8C%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%81%8B%E5%88%86%E3%81%8B%E3%82%89%E3%81%AA%E3%81%84%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88\"\u003e悪い例：境界を越えたか分からないイベント\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BD%95%E3%81%8C%E5%95%8F%E9%A1%8C%E3%81%AA%E3%81%AE%E3%81%8B\"\u003e何が問題なのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E4%BE%8B%E5%A2%83%E7%95%8C%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%81%93%E3%81%A8%E3%81%8C%E5%88%86%E3%81%8B%E3%82%8B%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88\"\u003e良い例：境界を越えたことが分かるイベント\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E6%9C%AA%E5%88%A4%E6%96%AD%E3%81%AE%E4%B8%96%E7%95%8C\"\u003e状態（未判断の世界）\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E5%88%A4%E6%96%AD%E5%AE%8C%E4%BA%86%E3%81%AE%E4%B8%96%E7%95%8C\"\u003eイベント（判断完了の世界）\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#viewmodel%E5%88%A4%E6%96%AD%E3%82%92%E5%AE%8C%E4%BA%86%E3%81%95%E3%81%9B%E3%82%8B%E5%A0%B4%E6%89%80\"\u003eViewModel（判断を完了させる場所）\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%93%E3%81%A7%E4%BD%95%E3%81%8C%E8%B5%B7%E3%81%8D%E3%81%A6%E3%81%84%E3%82%8B%E3%81%8B\"\u003eここで何が起きているか\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A2%83%E7%95%8C%E3%81%AE%E6%89%8B%E5%89%8D\"\u003e境界の「手前」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A2%83%E7%95%8C%E3%81%AE%E5%90%91%E3%81%93%E3%81%86%E5%81%B4\"\u003e境界の「向こう側」\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%8C%E5%A2%83%E7%95%8C%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E9%80%9A%E7%9F%A5%E3%81%AB%E3%81%AA%E3%82%8B%E7%90%86%E7%94%B1\"\u003eイベントが「境界を越えた通知」になる理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C-sealed-class-%E3%81%8C%E5%8A%B9%E3%81%8F%E3%81%AE%E3%81%8B\"\u003eなぜ sealed class が効くのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e第8章では、\n本書における「イベント」を次のように定義しました。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eイベントとは、「判断が完了したこと」を表す構造\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003eこれは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eonClick\u003c/li\u003e\n\u003cli\u003eonTextChanged\u003c/li\u003e\n\u003cli\u003eonResume\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった\n\u003cstrong\u003eUI やフレームワークが発火する通知\u003c/strong\u003e とは、\nまったく別の概念です。\u003c/p\u003e\n\u003cp\u003eここでは、\nこの違いがコードとしてどう現れるのかを、\n具体例で確認します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"悪い例境界を越えたか分からないイベント\"\u003e悪い例：境界を越えたか分からないイベント\u003c/h2\u003e\n\u003cp\u003eまずは、よくある実装から見てみます。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eFormViewModel\u003c/span\u003e : ViewModel() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eprivate\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e uiState = FormUiState()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efun\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eonTextChanged\u003c/span\u003e(text: String) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        uiState = uiState.copy(inputText = text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efun\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eonSubmitClicked\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// 本当に送信してよい状態か？\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// ここで毎回判断する必要がある\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e一見、問題なさそうに見えます。\u003c/p\u003e\n\u003cp\u003eしかし、この \u003ccode\u003eonSubmit()\u003c/code\u003e には、\n次の疑問が常につきまといます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e入力は本当に完了しているのか\u003c/li\u003e\n\u003cli\u003eバリデーションは終わっているのか\u003c/li\u003e\n\u003cli\u003eこの時点で「判断」は終わっているのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eコード上では、\n\u003cstrong\u003eどこで判断が完了したのかが分かりません。\u003c/strong\u003e\u003c/p\u003e","title":"第8章 補足：イベントとは何か（サンプルで理解する）"},{"content":" 設計者は、正解を当てる人ではない 設計者の責任は「選び直せる状態」を作ること 良い設計は、未来への配慮である 設計し続けるという責任 この本のまとめ この本では一貫して、 設計とは「判断をどこに閉じ込めるか」という行為である、という視点を扱ってきました。\n判断は必ず変わること 壊れることを前提にすること 判断をコードに残すこと 判断をチームで共有すること ここまで読み進めてきた読者であれば、 設計という行為が、単なる構造設計やパターン選択ではないことは、 すでに感じ取っているはずです。\nこの終章では、 そうした設計観を踏まえたうえで、 設計者の責任とは何か を改めて言葉にします。\n設計者は、正解を当てる人ではない 設計者という言葉から、\n先を見通す人 最適解を選べる人 失敗しない構造を作る人 を想像するかもしれません。\nしかし、本書の立場は明確です。\n設計者は、 正解を当てる人ではありません。\nなぜなら、\n要件は変わる 前提は崩れる 想定外は必ず起きる からです。\n設計者に求められるのは、 当てる力ではなく、外れたときに耐えられる力です。\n設計者の責任は「選び直せる状態」を作ること では、設計者は何に責任を持つべきなのでしょうか。\nそれは、 将来、判断を選び直せる状態を残すこと です。\nどこに判断があるか分かる どの判断が強いか弱いか分かる どこを変えればよいか議論できる この状態を作ることが、 設計者の責任です。\n逆に言えば、\nなぜこうなっているか分からない 触るのが怖い 壊したら戻せない という状態を残すことは、 設計者の責任放棄だと言えます。\n良い設計は、未来への配慮である 設計は、 その場の問題を解くだけの行為ではありません。\n数か月後の自分 これから参加するメンバー 自分の知らない誰か そうした未来の人たちが、 コードと向き合うことになります。\n良い設計とは、 未来の他者に対する配慮 です。\n迷わなくて済むようにする 壊してよい場所を示す 判断の痕跡を残す これは、 技術的な話であると同時に、 とても人間的な話でもあります。\n設計し続けるという責任 設計は、一度して終わりではありません。\n要件が変わる チームが変わる 技術が変わる そのたびに、 判断を見直し、置き直す必要があります。\n設計者の責任とは、\n設計を固定しないこと 変化を前提に更新し続けること でもあります。\n壊れることを恐れず、 壊したら直せる状態を保ち続けること。\nそれが、 設計者としての誠実さです。\nこの本のまとめ 最後に、この本全体を一文でまとめます。\n設計とは、判断を閉じ込め、選び直せる状態を未来に残す行為である。\n構造やパターンは、その結果にすぎません。\n判断をどこに置くかを考える 判断の強度を選ぶ 判断をコードとチームに残す これらを繰り返すことが、設計です。\n完璧な設計は存在しません。\nしかし、 誠実な設計 は存在します。\nこの本が、 あなた自身の設計の判断を見直すきっかけになれば幸いです。\n","permalink":"https://design.okuda-studio.com/books/003-design-that-locks-in-judgment/09-/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E8%80%85%E3%81%AF%E6%AD%A3%E8%A7%A3%E3%82%92%E5%BD%93%E3%81%A6%E3%82%8B%E4%BA%BA%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e設計者は、正解を当てる人ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E8%80%85%E3%81%AE%E8%B2%AC%E4%BB%BB%E3%81%AF%E9%81%B8%E3%81%B3%E7%9B%B4%E3%81%9B%E3%82%8B%E7%8A%B6%E6%85%8B%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%93%E3%81%A8\"\u003e設計者の責任は「選び直せる状態」を作ること\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%AF%E6%9C%AA%E6%9D%A5%E3%81%B8%E3%81%AE%E9%85%8D%E6%85%AE%E3%81%A7%E3%81%82%E3%82%8B\"\u003e良い設計は、未来への配慮である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%97%E7%B6%9A%E3%81%91%E3%82%8B%E3%81%A8%E3%81%84%E3%81%86%E8%B2%AC%E4%BB%BB\"\u003e設計し続けるという責任\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E6%9C%AC%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの本のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eこの本では一貫して、\n設計とは「判断をどこに閉じ込めるか」という行為である、という視点を扱ってきました。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e判断は必ず変わること\u003c/li\u003e\n\u003cli\u003e壊れることを前提にすること\u003c/li\u003e\n\u003cli\u003e判断をコードに残すこと\u003c/li\u003e\n\u003cli\u003e判断をチームで共有すること\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eここまで読み進めてきた読者であれば、\n設計という行為が、単なる構造設計やパターン選択ではないことは、\nすでに感じ取っているはずです。\u003c/p\u003e\n\u003cp\u003eこの終章では、\nそうした設計観を踏まえたうえで、\n\u003cstrong\u003e設計者の責任とは何か\u003c/strong\u003e を改めて言葉にします。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"設計者は正解を当てる人ではない\"\u003e設計者は、正解を当てる人ではない\u003c/h3\u003e\n\u003cp\u003e設計者という言葉から、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e先を見通す人\u003c/li\u003e\n\u003cli\u003e最適解を選べる人\u003c/li\u003e\n\u003cli\u003e失敗しない構造を作る人\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを想像するかもしれません。\u003c/p\u003e\n\u003cp\u003eしかし、本書の立場は明確です。\u003c/p\u003e\n\u003cp\u003e設計者は、\n\u003cstrong\u003e正解を当てる人ではありません。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eなぜなら、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e要件は変わる\u003c/li\u003e\n\u003cli\u003e前提は崩れる\u003c/li\u003e\n\u003cli\u003e想定外は必ず起きる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eからです。\u003c/p\u003e\n\u003cp\u003e設計者に求められるのは、\n当てる力ではなく、外れたときに耐えられる力です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"設計者の責任は選び直せる状態を作ること\"\u003e設計者の責任は「選び直せる状態」を作ること\u003c/h3\u003e\n\u003cp\u003eでは、設計者は何に責任を持つべきなのでしょうか。\u003c/p\u003e\n\u003cp\u003eそれは、\n\u003cstrong\u003e将来、判断を選び直せる状態を残すこと\u003c/strong\u003e です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどこに判断があるか分かる\u003c/li\u003e\n\u003cli\u003eどの判断が強いか弱いか分かる\u003c/li\u003e\n\u003cli\u003eどこを変えればよいか議論できる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの状態を作ることが、\n設計者の責任です。\u003c/p\u003e\n\u003cp\u003e逆に言えば、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eなぜこうなっているか分からない\u003c/li\u003e\n\u003cli\u003e触るのが怖い\u003c/li\u003e\n\u003cli\u003e壊したら戻せない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという状態を残すことは、\n設計者の責任放棄だと言えます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"良い設計は未来への配慮である\"\u003e良い設計は、未来への配慮である\u003c/h3\u003e\n\u003cp\u003e設計は、\nその場の問題を解くだけの行為ではありません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e数か月後の自分\u003c/li\u003e\n\u003cli\u003eこれから参加するメンバー\u003c/li\u003e\n\u003cli\u003e自分の知らない誰か\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eそうした未来の人たちが、\nコードと向き合うことになります。\u003c/p\u003e\n\u003cp\u003e良い設計とは、\n\u003cstrong\u003e未来の他者に対する配慮\u003c/strong\u003e です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e迷わなくて済むようにする\u003c/li\u003e\n\u003cli\u003e壊してよい場所を示す\u003c/li\u003e\n\u003cli\u003e判断の痕跡を残す\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれは、\n技術的な話であると同時に、\nとても人間的な話でもあります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"設計し続けるという責任\"\u003e設計し続けるという責任\u003c/h3\u003e\n\u003cp\u003e設計は、一度して終わりではありません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e要件が変わる\u003c/li\u003e\n\u003cli\u003eチームが変わる\u003c/li\u003e\n\u003cli\u003e技術が変わる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eそのたびに、\n判断を見直し、置き直す必要があります。\u003c/p\u003e","title":"第9章：設計者の責任とは何か"},{"content":" 状態・イベント・境界は「同じ話」をしている 判断とは何か —— 設計で最初に決めるべきもの 状態とは「判断が終わった世界のスナップショット」である イベントとは「判断が完了したこと」を表す構造である 境界とは「判断をこれ以上持ち越さない」ための線である Tips：Flow の各関数は「判断を閉じるための境界」である ViewModel は「判断済みの世界」を作る場所である 「状態・イベント・境界」が噛み合ったときに起きること この章のまとめ：名前は違うが、問いは一つである 状態・イベント・境界は「同じ話」をしている 状態設計、イベント設計、境界設計。 これらは、多くの場合、 別々の設計トピック として語られます。\nしかし実装を重ねていくと、 こんな違和感を覚えたことはないでしょうか。\n状態をきれいに設計したはずなのに、 if が消えない イベントを分けたはずなのに、どこで判断しているのか分からない 境界を引いたはずなのに、責務がにじみ出てくる それは、あなたの設計力が足りないからではありません。\n実はこれらはすべて、 同じ問いを、違う名前で考えているだけ なのです。\n本書で扱ってきた\n状態 イベント 境界 は、どれも本質的には、\n「判断をどこで終わらせるか」\nという、ひとつの設計問題を別の角度から見たものです。\nこの章では、それらを一度すべて並べ、 「同じ話をしている」ことを明確にします。\nそうすることで、 これまでバラバラに見えていた設計判断が、 一本の軸としてつながるはずです。\n判断とは何か —— 設計で最初に決めるべきもの この章の軸になる定義\n判断とは 分岐 検証 条件評価 正常／異常の決定 つまり 「複数の可能性の中から、1つに確定させる行為」 ここで強調するポイント：\n判断は「いつまでも続いてはいけない」 判断が終わらない世界は 状態が不安定 テストできない 責務が混ざる 状態とは「判断が終わった世界のスナップショット」である 本書における 状態の再定義\n状態 = 判断がすでに完了した結果を、嘘なく表現しているもの ここでこれまでの章と接続：\nUI State に if が多い nullable が意味を持ちすぎている 「この状態でこの画面、あり得る？」という違和感 → それは 状態が、判断途中の世界を含んでしまっているから\nイベントとは「判断が完了したこと」を表す構造である 本書における イベントの再定義\n一般的な onClick / onTextChanged ではない 本書でのイベントは： 判断が完了し、その結果が境界を越えて伝えられる瞬間\nここで重要なのは：\nイベントは「判断はこれから考えてね」ではない イベントは「判断はもう考え終わったよ」の合図 境界とは「判断をこれ以上持ち越さない」ための線である ここで境界の定義を統合する。\n境界の例を挙げると\nView と ViewModel UI と Domain Flow の各種関数の前後 本質は共通：\nこの線を越えたら、もう判断させない\n境界の役割を明確化：\n境界の手前 判断してよい 境界の向こう 判断してはいけない 事実（確定情報）だけが流れる Tips：Flow の各関数は「判断を閉じるための境界」である Kotlin の Flow における map や filter、onEach といった operator は、 単なる処理の連結ではありません。\n本書の文脈では、 それぞれが「判断をこれ以上持ち越さないための境界」 です。\nFlow は「値が流れていく仕組み」ではなく、 判断が段階的に完了していく構造 として読むことができます。\noperator を一つ挟むごとに、\nそれ以前の判断は、すでに終わっている それ以降の処理は、判断済みの結果だけを扱う 上流の事情を、下流が知る必要はない という前提が成立します。\nたとえば、\nfilter 通すか、捨てるか、という判断を完了させる境界 map どの形に変換するか、という判断を完了させる境界 catch 失敗をどう扱うか、という判断を完了させる境界 です。\n重要なのは、 operator を越えて判断をやり直そうとした瞬間に、設計が崩れる という点です。\n下流で 「やはり別の条件で分岐したい」 「ここでもう一度 null を見たい」 と感じたなら、\nそれは判断の位置、 つまり 境界の引き方が間違っている というサインです。\nJetpack Compose においては、\nViewModel 内の Flow 判断を完了させていく場所 UI に届く Flow 判断が終わった世界の表現 であるべきです。\nFlow の operator は、処理のための道具ではありません。\n判断を閉じ、責任を分けるための線 それが、Flow における境界です。\nViewModel は「判断済みの世界」を作る場所である 一般的に想定される ViewModel の責務は： UI イベントを受け取ること onClick を処理すること しかし、その本質は、\n判断を完了させ、 状態とイベントを「判断済みの形」で外に出すこと\n判断の観点で UI と ViewModel の責務を明確にすると\nUI ユーザー操作を通知するだけ ViewModel 判断を完了させる UI が受け取るのは： 判断済みの State 判断済みの Event 「状態・イベント・境界」が噛み合ったときに起きること if が消える sealed class が自然に増える 「この分岐どこでやる？」で迷わなくなる Flow の各関数の境界が説明できる 「なぜここで map / transform なのか」が言語化できる → 設計の一貫性が生まれる\nこの章のまとめ：名前は違うが、問いは一つである 状態を考えているときも イベントを設計しているときも 境界を引いているときも\n私たちはずっと 「判断をどこで終わらせるか」 という同じ問いに答えている。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/09-state-event-devider-is-similar/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E5%A2%83%E7%95%8C%E3%81%AF%E5%90%8C%E3%81%98%E8%A9%B1%E3%82%92%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B\"\u003e状態・イベント・境界は「同じ話」をしている\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B--%E8%A8%AD%E8%A8%88%E3%81%A7%E6%9C%80%E5%88%9D%E3%81%AB%E6%B1%BA%E3%82%81%E3%82%8B%E3%81%B9%E3%81%8D%E3%82%82%E3%81%AE\"\u003e判断とは何か —— 設計で最初に決めるべきもの\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E3%81%A8%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%8C%E7%B5%82%E3%82%8F%E3%81%A3%E3%81%9F%E4%B8%96%E7%95%8C%E3%81%AE%E3%82%B9%E3%83%8A%E3%83%83%E3%83%97%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%E3%81%A7%E3%81%82%E3%82%8B\"\u003e状態とは「判断が終わった世界のスナップショット」である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%A8%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%8C%E5%AE%8C%E4%BA%86%E3%81%97%E3%81%9F%E3%81%93%E3%81%A8%E3%82%92%E8%A1%A8%E3%81%99%E6%A7%8B%E9%80%A0%E3%81%A7%E3%81%82%E3%82%8B\"\u003eイベントとは「判断が完了したこと」を表す構造である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A2%83%E7%95%8C%E3%81%A8%E3%81%AF%E5%88%A4%E6%96%AD%E3%82%92%E3%81%93%E3%82%8C%E4%BB%A5%E4%B8%8A%E6%8C%81%E3%81%A1%E8%B6%8A%E3%81%95%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%81%AE%E7%B7%9A%E3%81%A7%E3%81%82%E3%82%8B\"\u003e境界とは「判断をこれ以上持ち越さない」ための線である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#tipsflow-%E3%81%AE%E5%90%84%E9%96%A2%E6%95%B0%E3%81%AF%E5%88%A4%E6%96%AD%E3%82%92%E9%96%89%E3%81%98%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E5%A2%83%E7%95%8C%E3%81%A7%E3%81%82%E3%82%8B\"\u003eTips：Flow の各関数は「判断を閉じるための境界」である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#viewmodel-%E3%81%AF%E5%88%A4%E6%96%AD%E6%B8%88%E3%81%BF%E3%81%AE%E4%B8%96%E7%95%8C%E3%82%92%E4%BD%9C%E3%82%8B%E5%A0%B4%E6%89%80%E3%81%A7%E3%81%82%E3%82%8B\"\u003eViewModel は「判断済みの世界」を作る場所である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E5%A2%83%E7%95%8C%E3%81%8C%E5%99%9B%E3%81%BF%E5%90%88%E3%81%A3%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AB%E8%B5%B7%E3%81%8D%E3%82%8B%E3%81%93%E3%81%A8\"\u003e「状態・イベント・境界」が噛み合ったときに起きること\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81%E5%90%8D%E5%89%8D%E3%81%AF%E9%81%95%E3%81%86%E3%81%8C%E5%95%8F%E3%81%84%E3%81%AF%E4%B8%80%E3%81%A4%E3%81%A7%E3%81%82%E3%82%8B\"\u003eこの章のまとめ：名前は違うが、問いは一つである\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"状態イベント境界は同じ話をしている\"\u003e状態・イベント・境界は「同じ話」をしている\u003c/h2\u003e\n\u003cp\u003e状態設計、イベント設計、境界設計。\nこれらは、多くの場合、 \u003cstrong\u003e別々の設計トピック\u003c/strong\u003e として語られます。\u003c/p\u003e\n\u003cp\u003eしかし実装を重ねていくと、\nこんな違和感を覚えたことはないでしょうか。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e状態をきれいに設計したはずなのに、 if が消えない\u003c/li\u003e\n\u003cli\u003eイベントを分けたはずなのに、どこで判断しているのか分からない\u003c/li\u003e\n\u003cli\u003e境界を引いたはずなのに、責務がにじみ出てくる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eそれは、あなたの設計力が足りないからではありません。\u003c/p\u003e\n\u003cp\u003e実はこれらはすべて、\n\u003cstrong\u003e同じ問いを、違う名前で考えているだけ\u003c/strong\u003e なのです。\u003c/p\u003e\n\u003cp\u003e本書で扱ってきた\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e状態\u003c/li\u003e\n\u003cli\u003eイベント\u003c/li\u003e\n\u003cli\u003e境界\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eは、どれも本質的には、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e「判断をどこで終わらせるか」\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eという、ひとつの設計問題を別の角度から見たものです。\u003c/p\u003e\n\u003cp\u003eこの章では、それらを一度すべて並べ、\n「同じ話をしている」ことを明確にします。\u003c/p\u003e\n\u003cp\u003eそうすることで、\nこれまでバラバラに見えていた設計判断が、\n一本の軸としてつながるはずです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"判断とは何か--設計で最初に決めるべきもの\"\u003e判断とは何か —— 設計で最初に決めるべきもの\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eこの章の軸になる定義\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e判断とは\n\u003cul\u003e\n\u003cli\u003e分岐\u003c/li\u003e\n\u003cli\u003e検証\u003c/li\u003e\n\u003cli\u003e条件評価\u003c/li\u003e\n\u003cli\u003e正常／異常の決定\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eつまり\n\u003cstrong\u003e「複数の可能性の中から、1つに確定させる行為」\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eここで強調するポイント：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e判断は「いつまでも続いてはいけない」\u003c/li\u003e\n\u003cli\u003e判断が終わらない世界は\n\u003cul\u003e\n\u003cli\u003e状態が不安定\u003c/li\u003e\n\u003cli\u003eテストできない\u003c/li\u003e\n\u003cli\u003e責務が混ざる\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"状態とは判断が終わった世界のスナップショットである\"\u003e状態とは「判断が終わった世界のスナップショット」である\u003c/h2\u003e\n\u003cp\u003e本書における \u003cstrong\u003e状態の再定義\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e状態 =\n\u003cstrong\u003e判断がすでに完了した結果を、嘘なく表現しているもの\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eここでこれまでの章と接続：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUI State に if が多い\u003c/li\u003e\n\u003cli\u003enullable が意味を持ちすぎている\u003c/li\u003e\n\u003cli\u003e「この状態でこの画面、あり得る？」という違和感\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e→ それは\n\u003cstrong\u003e状態が、判断途中の世界を含んでしまっているから\u003c/strong\u003e\u003c/p\u003e","title":"第9章：状態・イベント・境界は「同じ話」をしている"},{"content":" 状態設計のチェック イベント設計のチェック 境界設計のチェック ViewModel / UI 分離のチェック（Android） 統合チェック（最重要） 状態設計のチェック この状態は 判断がすでに完了した結果 だけを表しているか 「この状態の UI はあり得る？」と自分に聞いて、即答できるか nullable や flag の組み合わせで「状態を表現していないか」 状態を見ただけで、 これ以上判断が不要だ と分かるか イベント設計のチェック このイベントは「これから判断してほしい」通知になっていないか イベントの型を見ただけで、何が確定したのか が分かるか Boolean や Int で「意味を持たせて」いないか sealed class にしたとき、アプリがとり得る状態として過不足がないか 境界設計のチェック この境界を越えたあと、判断が発生していないか 境界の向こう側で if / when が増えていないか Flow の各関数の前後が「意味の切れ目」になっているか 「ここから先は事実だけが流れる」と断言できるか ViewModel / UI 分離のチェック（Android） ViewModel は「判断済みの世界」だけを外に出しているか UI は判断せず、状態とイベントを そのまま描画／反映 しているか UI の onClick などから、判断済みのイベントを作成しているか 「この判断、UI でも ViewModel でもできるよね」と思う箇所が残っていないか 統合チェック（最重要） 「これは判断前／判断後のどちらか？」と即答できるか 新しいコードを書く前に「判断はどこで終わらせる？」と自問しているか → これが自然にできていれば、設計は崩れにくい\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/09-x-checklist/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E8%A8%AD%E8%A8%88%E3%81%AE%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF\"\u003e状態設計のチェック\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E8%A8%AD%E8%A8%88%E3%81%AE%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF\"\u003eイベント設計のチェック\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A2%83%E7%95%8C%E8%A8%AD%E8%A8%88%E3%81%AE%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF\"\u003e境界設計のチェック\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#viewmodel--ui-%E5%88%86%E9%9B%A2%E3%81%AE%E3%83%81%E3%82%A7%E3%83%83%E3%82%AFandroid\"\u003eViewModel / UI 分離のチェック（Android）\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%B5%B1%E5%90%88%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E6%9C%80%E9%87%8D%E8%A6%81\"\u003e統合チェック（最重要）\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"状態設計のチェック\"\u003e状態設計のチェック\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eこの状態は \u003cstrong\u003e判断がすでに完了した結果\u003c/strong\u003e だけを表しているか\u003c/li\u003e\n\u003cli\u003e「この状態の UI はあり得る？」と自分に聞いて、即答できるか\u003c/li\u003e\n\u003cli\u003enullable や flag の組み合わせで「状態を表現していないか」\u003c/li\u003e\n\u003cli\u003e状態を見ただけで、 \u003cstrong\u003eこれ以上判断が不要だ\u003c/strong\u003e と分かるか\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"イベント設計のチェック\"\u003eイベント設計のチェック\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eこのイベントは「これから判断してほしい」通知になっていないか\u003c/li\u003e\n\u003cli\u003eイベントの型を見ただけで、\u003cstrong\u003e何が確定したのか\u003c/strong\u003e が分かるか\u003c/li\u003e\n\u003cli\u003eBoolean や Int で「意味を持たせて」いないか\u003c/li\u003e\n\u003cli\u003esealed class にしたとき、アプリがとり得る状態として過不足がないか\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"境界設計のチェック\"\u003e境界設計のチェック\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eこの境界を越えたあと、判断が発生していないか\u003c/li\u003e\n\u003cli\u003e境界の向こう側で if / when が増えていないか\u003c/li\u003e\n\u003cli\u003eFlow の各関数の前後が「意味の切れ目」になっているか\u003c/li\u003e\n\u003cli\u003e「ここから先は事実だけが流れる」と断言できるか\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"viewmodel--ui-分離のチェックandroid\"\u003eViewModel / UI 分離のチェック（Android）\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eViewModel は「判断済みの世界」だけを外に出しているか\u003c/li\u003e\n\u003cli\u003eUI は判断せず、状態とイベントを \u003cstrong\u003eそのまま描画／反映\u003c/strong\u003e しているか\u003c/li\u003e\n\u003cli\u003eUI の onClick などから、判断済みのイベントを作成しているか\u003c/li\u003e\n\u003cli\u003e「この判断、UI でも ViewModel でもできるよね」と思う箇所が残っていないか\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"統合チェック最重要\"\u003e統合チェック（最重要）\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e「これは判断前／判断後のどちらか？」と即答できるか\u003c/li\u003e\n\u003cli\u003e新しいコードを書く前に「判断はどこで終わらせる？」と自問しているか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e→ これが自然にできていれば、設計は崩れにくい\u003c/p\u003e","title":"資料：「状態・イベント・境界」設計チェックリスト"},{"content":" 「後戻りできない」の正体は、構造の蓄積である 最初に置いた判断が、全体の前提になる 暗黙の前提は、静かに複製される 設計を変えたいと思ったとき、すでに遅い 境界を後から引き直すのが難しい理由 「設計はあとからでも直せる」は、なぜ魅力的なのか 技術的負債の正体は「判断の負債」である 小さな設計は、後戻りできる 良い設計は「決断を早くする」 設計とは、未来の選択肢を整理すること この章のまとめ 設計の話をしていると、 よくこんな言葉を耳にします。\nとりあえず作って、あとで直せばいい 実装しながら設計を詰めればいい\n一見すると、合理的に聞こえます。\nしかし現実には、 設計は、後から直そうとするほど難しくなっていく という現象が、ほぼ必ず起こります。\nこの章では、その理由を 精神論ではなく 構造の問題 として説明します。\n「後戻りできない」の正体は、構造の蓄積である 設計が後戻りできなくなる理由は、単純です。\n判断が、コード全体に染み出していくから です。\n判断を構造として表現せずに実装を進めると、 その判断は次のような形で現れ始めます。\nif 文として 呼び出し順の前提として コメントの注意書きとして テストの前提条件として つまり、 ひとつの判断が あらゆる場所に複製 されていきます。\nこの状態になると、 もはや一箇所を直すだけでは済みません。\n最初に置いた判断が、全体の前提になる 初期段階では、設計を深く考えずに とりあえず次のようなコードを書いてしまうことがあります。\nfun submit(data: Data) { if (data.isValid()) { // 処理 } } このコードは、一見すると何の問題もありません。 しかし、この一行には、すでに 重要な設計判断 が含まれています。\nこの時点で置かれている判断は、次の二つです。\nData は「不正な状態」で渡される可能性がある その妥当性を判断する責任は submit が持つ つまりこのコードは、\n「呼び出し元は、Data の正しさを気にしなくてよい」\nという前提を、 コードの構造として表現している のです。\n暗黙の前提は、静かに複製される この前提のまま実装が進むと、 同じ考え方が別の場所にも持ち込まれます。\nfun submitDraft(data: Data) { if (data.isValid()) { // 別の処理 } } あるいは、\nif (data.isValid()) { submit(data) } といったコードが現れ始めます。\nここで起きているのは、\n妥当性チェックが複数箇所に現れる 「どこで判断するのか」が揺れ始める 判断の責任が、構造として整理されなくなる という状態です。\nこの段階では、 まだ「少し重複している」程度にしか見えません。\n設計を変えたいと思ったとき、すでに遅い しばらく実装が進んだ後で、 次のように考え直すことがあります。\n実は、Data は生成時点で必ず valid にしたい submit には、正しい Data しか渡らない設計にしたい\nこれは、より良い設計判断 です。\nしかし、この判断を構造として表現し直そうとすると、 すぐに問題にぶつかります。\nすでに submit の中でチェックしている 呼び出し側にもチェックが存在する テストが「invalid な Data を渡す前提」で書かれている つまり、\n「Data は invalid かもしれない」 という判断が、 コード全体の前提として表現されてしまっているのです。\nこの状態では、\nif を消すだけでは済まない 前提を洗い出す必要がある 影響範囲が読めない という状況になります。\nこれが、\n設計は後から直せない\nと感じる正体です。\n境界を後から引き直すのが難しい理由 境界は、\n依存関係 呼び出し順 型 ライフサイクル と深く結びついています。\n一度、判断を曖昧なままにして実装を進めると、\nあちこちから直接触られ 暗黙の前提が増え 例外的な扱いが混ざり込む 結果として、 境界を引き直すだけで大量の修正が必要 になります。\nこれは、 境界が単なる「線」ではなく、 構造全体の形そのもの だからです。\n「設計はあとからでも直せる」は、なぜ魅力的なのか この考え方が魅力的に見えるのは、\n早く動くものが見える 考える時間を減らせる 手戻りしている感覚がない からです。\nしかし実際には、\n判断を表現しない 境界を定めない 構造を意識しない という 設計上の借金 を、 静かに積み上げています。\n技術的負債の正体は「判断の負債」である 技術的負債という言葉は、 しばしば曖昧に使われます。\n本書では、次のように捉えます。\n技術的負債とは、 構造で表現すべき判断を、 人と時間に押し付けた結果 です。\n「ここは気をつけて」 「この順番だけ守って」 「この条件は暗黙で」 これらが増えるほど、 設計を修正するコストは指数関数的に増えていきます。\n小さな設計は、後戻りできる ここで重要な補足があります。\nすべての設計が、 後戻りできないわけではありません。\n小さな関数 局所的なクラス 閉じたモジュール これらは、 判断の影響範囲が小さい ため、 後から直すことができます。\n問題になるのは、\n境界 依存関係の向き 状態の持ち方 といった 構造の根幹 です。\n良い設計は「決断を早くする」 設計とは、 可能性を狭める行為です。\nできることを減らし 書けるコードを制限し 判断を構造として表現する これは一見、 不自由に見えるかもしれません。\nしかし、この制限こそが、\n後から迷わない 変更時に悩まない 壊れにくい という自由を生みます。\n設計とは、未来の選択肢を整理すること 設計は、 未来を縛る行為ではありません。\n未来の選択肢を、 安全な形に整理する行為 です。\n危険な選択肢を消し 正しい変更だけを残す そのために、 判断を構造として表現します。\nこの章のまとめ 設計が後戻りできなくなるのは、判断が広がるから 判断は、構造で表現しないと複製される 境界や依存関係は、後から直しにくい 技術的負債の正体は「判断の負債」 良い設計は、決断を早くする 次の章では、 ここまでの話を踏まえて、\n「では、設計はいつやるべきなのか」 ――タイミングの話に進みます。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/10-design-cannot-undo/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%BE%8C%E6%88%BB%E3%82%8A%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E3%81%AE%E6%AD%A3%E4%BD%93%E3%81%AF%E6%A7%8B%E9%80%A0%E3%81%AE%E8%93%84%E7%A9%8D%E3%81%A7%E3%81%82%E3%82%8B\"\u003e「後戻りできない」の正体は、構造の蓄積である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9C%80%E5%88%9D%E3%81%AB%E7%BD%AE%E3%81%84%E3%81%9F%E5%88%A4%E6%96%AD%E3%81%8C%E5%85%A8%E4%BD%93%E3%81%AE%E5%89%8D%E6%8F%90%E3%81%AB%E3%81%AA%E3%82%8B\"\u003e最初に置いた判断が、全体の前提になる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9A%97%E9%BB%99%E3%81%AE%E5%89%8D%E6%8F%90%E3%81%AF%E9%9D%99%E3%81%8B%E3%81%AB%E8%A4%87%E8%A3%BD%E3%81%95%E3%82%8C%E3%82%8B\"\u003e暗黙の前提は、静かに複製される\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%82%92%E5%A4%89%E3%81%88%E3%81%9F%E3%81%84%E3%81%A8%E6%80%9D%E3%81%A3%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%99%E3%81%A7%E3%81%AB%E9%81%85%E3%81%84\"\u003e設計を変えたいと思ったとき、すでに遅い\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A2%83%E7%95%8C%E3%82%92%E5%BE%8C%E3%81%8B%E3%82%89%E5%BC%95%E3%81%8D%E7%9B%B4%E3%81%99%E3%81%AE%E3%81%8C%E9%9B%A3%E3%81%97%E3%81%84%E7%90%86%E7%94%B1\"\u003e境界を後から引き直すのが難しい理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AF%E3%81%82%E3%81%A8%E3%81%8B%E3%82%89%E3%81%A7%E3%82%82%E7%9B%B4%E3%81%9B%E3%82%8B%E3%81%AF%E3%81%AA%E3%81%9C%E9%AD%85%E5%8A%9B%E7%9A%84%E3%81%AA%E3%81%AE%E3%81%8B\"\u003e「設計はあとからでも直せる」は、なぜ魅力的なのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%8A%80%E8%A1%93%E7%9A%84%E8%B2%A0%E5%82%B5%E3%81%AE%E6%AD%A3%E4%BD%93%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%AE%E8%B2%A0%E5%82%B5%E3%81%A7%E3%81%82%E3%82%8B\"\u003e技術的負債の正体は「判断の負債」である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%B0%8F%E3%81%95%E3%81%AA%E8%A8%AD%E8%A8%88%E3%81%AF%E5%BE%8C%E6%88%BB%E3%82%8A%E3%81%A7%E3%81%8D%E3%82%8B\"\u003e小さな設計は、後戻りできる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%AF%E6%B1%BA%E6%96%AD%E3%82%92%E6%97%A9%E3%81%8F%E3%81%99%E3%82%8B\"\u003e良い設計は「決断を早くする」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%A8%E3%81%AF%E6%9C%AA%E6%9D%A5%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E6%95%B4%E7%90%86%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8\"\u003e設計とは、未来の選択肢を整理すること\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e設計の話をしていると、\nよくこんな言葉を耳にします。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eとりあえず作って、あとで直せばいい\n実装しながら設計を詰めればいい\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e一見すると、合理的に聞こえます。\u003c/p\u003e\n\u003cp\u003eしかし現実には、\n\u003cstrong\u003e設計は、後から直そうとするほど難しくなっていく\u003c/strong\u003e\nという現象が、ほぼ必ず起こります。\u003c/p\u003e\n\u003cp\u003eこの章では、その理由を\n精神論ではなく \u003cstrong\u003e構造の問題\u003c/strong\u003e として説明します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"後戻りできないの正体は構造の蓄積である\"\u003e「後戻りできない」の正体は、構造の蓄積である\u003c/h2\u003e\n\u003cp\u003e設計が後戻りできなくなる理由は、単純です。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e判断が、コード全体に染み出していくから\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003e判断を構造として表現せずに実装を進めると、\nその判断は次のような形で現れ始めます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eif 文として\u003c/li\u003e\n\u003cli\u003e呼び出し順の前提として\u003c/li\u003e\n\u003cli\u003eコメントの注意書きとして\u003c/li\u003e\n\u003cli\u003eテストの前提条件として\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eつまり、\nひとつの判断が \u003cstrong\u003eあらゆる場所に複製\u003c/strong\u003e されていきます。\u003c/p\u003e\n\u003cp\u003eこの状態になると、\nもはや一箇所を直すだけでは済みません。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"最初に置いた判断が全体の前提になる\"\u003e最初に置いた判断が、全体の前提になる\u003c/h2\u003e\n\u003cp\u003e初期段階では、設計を深く考えずに\nとりあえず次のようなコードを書いてしまうことがあります。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efun\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003esubmit\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003edata\u003c/span\u003e: Data) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#66d9ef\"\u003edata\u003c/span\u003e.isValid()) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// 処理\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eこのコードは、一見すると何の問題もありません。\nしかし、この一行には、すでに \u003cstrong\u003e重要な設計判断\u003c/strong\u003e が含まれています。\u003c/p\u003e\n\u003cp\u003eこの時点で置かれている判断は、次の二つです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eData\u003c/code\u003e は「不正な状態」で渡される可能性がある\u003c/li\u003e\n\u003cli\u003eその妥当性を判断する責任は \u003ccode\u003esubmit\u003c/code\u003e が持つ\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eつまりこのコードは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e「呼び出し元は、Data の正しさを気にしなくてよい」\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eという前提を、\n\u003cstrong\u003eコードの構造として表現している\u003c/strong\u003e のです。\u003c/p\u003e","title":"第10章：設計はなぜ後戻りできないのか"},{"content":" 設計は「判断を構造に置く」タイミングでやる 実装前にやる設計、実装中にやる設計 実装前にやる設計 実装中にやる設計 「動くものを作ってから考える」の落とし穴 設計は「早すぎる」のではなく「深すぎる」と失敗する 良い設計は「観測してから行う」 設計をやるべきサイン 設計は、一度で終わらない 設計を「後回し」にしてよいケース 設計とは、タイミングの技術である この章のまとめ 設計について語ると、 必ず出てくる問いがあります。\n設計は、いつやるべきですか？\nこの問いに対して、 よくある答えは曖昧です。\n最初にやりすぎてもダメ 実装しながら考えるのが大事 状況による どれも間違ってはいません。 しかし、 判断基準が書かれていない のです。\n本書では、 この問いに対して、 はっきりした答えを出します。\n設計は「判断を構造に置く」タイミングでやる 設計をやるべきタイミングは、\n判断を、人の頭から構造に移す必要が生じたとき\nです。\nつまり、\nまだ判断が曖昧な段階 仕様が流動的な段階 では、無理に設計を固める必要はありません。\nしかし、\nその判断が繰り返し使われ始めたとき 複数人が触り始めたとき 変更が入り始めたとき その瞬間が、 設計のタイミング です。\n実装前にやる設計、実装中にやる設計 設計には、大きく二種類あります。\n実装前にやる設計 境界の仮置き 責任の大まかな分割 依存関係の向き これは、 「壊れ方を予測するための設計」 です。\n正解を決めるためではありません。\n実装中にやる設計 判断が散らばり始めたとき if が増え始めたとき 呼び出し順が暗黙になったとき このタイミングで行う設計は、\n判断を構造として回収する行為 です。\nこれは、遅すぎると致命的になります。\n「動くものを作ってから考える」の落とし穴 「まず動かす」は、非常に強力な考え方です。\nしかし注意点があります。\n動くものを作る過程で、\n判断を仮置きしたまま 境界を曖昧にしたまま 型で表現しなかったまま 進んでしまうと、\nその仮置きが、事実上の設計になる からです。\n動いているコードは、 心理的にも、 組織的にも、 直しにくくなります。\n設計は「早すぎる」のではなく「深すぎる」と失敗する 設計が失敗する原因は、 早すぎることではありません。\n深くやりすぎること です。\nまだ存在しない判断 まだ使われない境界 まだ確定していない責任 これらまで構造に落とすと、 柔軟性を失います。\n設計は、\n今、確実に存在する判断 すでに痛みが出ている判断 だけを、構造に置く行為です。\n良い設計は「観測してから行う」 設計が上手な人ほど、 すぐに決めません。\n代わりに、\nどこで迷っているか どこで判断が繰り返されているか どこで壊れやすいか を 観測 します。\n設計とは、 思いつきではなく、 現象への対応 です。\n設計をやるべきサイン 次の兆候が出たら、設計のタイミングです。\n同じ判断が何度も出てくる 正しい使い方を説明しないと伝わらない テストが前提条件だらけになる 修正時に触る範囲が読めない これらはすべて、\n判断が構造に置かれていない サインです。\n設計は、一度で終わらない 設計は、一度やって終わりではありません。\n判断が増えたら 状態が増えたら 境界が変わったら 再び、構造を見直す必要があります。\nただし、\n毎回ゼロからやり直すわけではありません。\n良い設計は、 変更に耐えながら、 少しずつ形を整えていきます。\n設計を「後回し」にしてよいケース すべてを設計する必要はありません。\n次のような場合は、後回しで問題ありません。\n一度きりの処理 実験的なコード 捨てる前提の実装 重要なのは、 後回しにしていると自覚しているか です。\n無自覚な後回しが、最も危険です。\n設計とは、タイミングの技術である 設計は、才能ではありません。\n判断を見極める技術 です。\n今か まだか ここか もっと内側か この見極めができるようになると、 設計は怖くなくなります。\nこの章のまとめ 設計は、判断を構造に移すときにやる 実装前は「壊れ方を予測するための設計」 実装中は「判断を構造として回収する行為」 早すぎるのではなく、深すぎると失敗する 設計は観測してから行う 設計はタイミングの技術である 次の章では、ここまでの概念を使って、\n「設計ができる人と、できない人の違い」\nを言語化していきます。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/11-when-should-we-design/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AF%E5%88%A4%E6%96%AD%E3%82%92%E6%A7%8B%E9%80%A0%E3%81%AB%E7%BD%AE%E3%81%8F%E3%82%BF%E3%82%A4%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%A7%E3%82%84%E3%82%8B\"\u003e設計は「判断を構造に置く」タイミングでやる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E5%89%8D%E3%81%AB%E3%82%84%E3%82%8B%E8%A8%AD%E8%A8%88%E5%AE%9F%E8%A3%85%E4%B8%AD%E3%81%AB%E3%82%84%E3%82%8B%E8%A8%AD%E8%A8%88\"\u003e実装前にやる設計、実装中にやる設計\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E5%89%8D%E3%81%AB%E3%82%84%E3%82%8B%E8%A8%AD%E8%A8%88\"\u003e実装前にやる設計\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E4%B8%AD%E3%81%AB%E3%82%84%E3%82%8B%E8%A8%AD%E8%A8%88\"\u003e実装中にやる設計\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%8B%95%E3%81%8F%E3%82%82%E3%81%AE%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%8B%E3%82%89%E8%80%83%E3%81%88%E3%82%8B%E3%81%AE%E8%90%BD%E3%81%A8%E3%81%97%E7%A9%B4\"\u003e「動くものを作ってから考える」の落とし穴\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AF%E6%97%A9%E3%81%99%E3%81%8E%E3%82%8B%E3%81%AE%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%E6%B7%B1%E3%81%99%E3%81%8E%E3%82%8B%E3%81%A8%E5%A4%B1%E6%95%97%E3%81%99%E3%82%8B\"\u003e設計は「早すぎる」のではなく「深すぎる」と失敗する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84%E8%A8%AD%E8%A8%88%E3%81%AF%E8%A6%B3%E6%B8%AC%E3%81%97%E3%81%A6%E3%81%8B%E3%82%89%E8%A1%8C%E3%81%86\"\u003e良い設計は「観測してから行う」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%82%92%E3%82%84%E3%82%8B%E3%81%B9%E3%81%8D%E3%82%B5%E3%82%A4%E3%83%B3\"\u003e設計をやるべきサイン\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AF%E4%B8%80%E5%BA%A6%E3%81%A7%E7%B5%82%E3%82%8F%E3%82%89%E3%81%AA%E3%81%84\"\u003e設計は、一度で終わらない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%82%92%E5%BE%8C%E5%9B%9E%E3%81%97%E3%81%AB%E3%81%97%E3%81%A6%E3%82%88%E3%81%84%E3%82%B1%E3%83%BC%E3%82%B9\"\u003e設計を「後回し」にしてよいケース\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%A8%E3%81%AF%E3%82%BF%E3%82%A4%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E6%8A%80%E8%A1%93%E3%81%A7%E3%81%82%E3%82%8B\"\u003e設計とは、タイミングの技術である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e設計について語ると、\n必ず出てくる問いがあります。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e設計は、いつやるべきですか？\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eこの問いに対して、\nよくある答えは曖昧です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e最初にやりすぎてもダメ\u003c/li\u003e\n\u003cli\u003e実装しながら考えるのが大事\u003c/li\u003e\n\u003cli\u003e状況による\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eどれも間違ってはいません。\nしかし、\n\u003cstrong\u003e判断基準が書かれていない\u003c/strong\u003e のです。\u003c/p\u003e\n\u003cp\u003e本書では、\nこの問いに対して、\nはっきりした答えを出します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"設計は判断を構造に置くタイミングでやる\"\u003e設計は「判断を構造に置く」タイミングでやる\u003c/h2\u003e\n\u003cp\u003e設計をやるべきタイミングは、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e判断を、人の頭から構造に移す必要が生じたとき\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003cp\u003eつまり、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eまだ判断が曖昧な段階\u003c/li\u003e\n\u003cli\u003e仕様が流動的な段階\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eでは、無理に設計を固める必要はありません。\u003c/p\u003e\n\u003cp\u003eしかし、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eその判断が繰り返し使われ始めたとき\u003c/li\u003e\n\u003cli\u003e複数人が触り始めたとき\u003c/li\u003e\n\u003cli\u003e変更が入り始めたとき\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eその瞬間が、 \u003cstrong\u003e設計のタイミング\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"実装前にやる設計実装中にやる設計\"\u003e実装前にやる設計、実装中にやる設計\u003c/h2\u003e\n\u003cp\u003e設計には、大きく二種類あります。\u003c/p\u003e\n\u003ch3 id=\"実装前にやる設計\"\u003e実装前にやる設計\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e境界の仮置き\u003c/li\u003e\n\u003cli\u003e責任の大まかな分割\u003c/li\u003e\n\u003cli\u003e依存関係の向き\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれは、 \u003cstrong\u003e「壊れ方を予測するための設計」\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003e正解を決めるためではありません。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"実装中にやる設計\"\u003e実装中にやる設計\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e判断が散らばり始めたとき\u003c/li\u003e\n\u003cli\u003eif が増え始めたとき\u003c/li\u003e\n\u003cli\u003e呼び出し順が暗黙になったとき\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこのタイミングで行う設計は、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e判断を構造として回収する行為\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003eこれは、遅すぎると致命的になります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"動くものを作ってから考えるの落とし穴\"\u003e「動くものを作ってから考える」の落とし穴\u003c/h2\u003e\n\u003cp\u003e「まず動かす」は、非常に強力な考え方です。\u003c/p\u003e\n\u003cp\u003eしかし注意点があります。\u003c/p\u003e\n\u003cp\u003e動くものを作る過程で、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e判断を仮置きしたまま\u003c/li\u003e\n\u003cli\u003e境界を曖昧にしたまま\u003c/li\u003e\n\u003cli\u003e型で表現しなかったまま\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e進んでしまうと、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eその仮置きが、事実上の設計になる\u003c/strong\u003e からです。\u003c/p\u003e","title":"第11章：設計はいつやるべきか"},{"content":" 設計ができない人は、正しさを探す 設計ができる人は、壊れ方を見る 設計ができない人は、実装でカバーしようとする 設計ができる人は、判断を減らす 設計ができない人は、「あとで直す」と言う 設計ができる人は、「今は決めない」を決める 設計ができない人は、境界をまたぐ 設計ができる人は、境界で止まる 設計ができる人は、説明できる 設計ができない人は、結果で語る 設計ができる人は、未来の自分を見る 設計ができる人は、速さを急がない この章のまとめ 設計ができる人と、 できない人の違いは、 知識量ではありません。\n経験年数でも、 使っているフレームワークでもありません。\n違いが出るのは、 コードを書く前と後の「見え方」 です。\n設計ができない人は、正しさを探す 設計がうまくいかないとき、 多くの場合、 こう考えています。\n正しい書き方はどれか ベストプラクティスは何か サンプルはどうなっているか これは、 正解を探す思考 です。\nしかし設計の世界では、 正解は一つではありません。\n必要なのは、 正解探しではなく、 壊れ方を想像する力 です。\n設計ができる人は、壊れ方を見る 設計ができる人は、 コードを見てこう考えます。\nこれは、どこから壊れるか 判断は、どこに漏れそうか 誰が、どこで迷うか つまり、\n「失敗のルート」から設計を見る\nのです。\nこれは、 悲観的 という意味ではありません。 現実的 という意味です。\n設計ができない人は、実装でカバーしようとする 判断が曖昧なとき、 設計ができない人は、\nif を足す チェックを増やす テストで守る という方向に進みがちです。\nこれは、 構造で解くべき問題を、実装で無理やり押し込んでいる 状態です。\n一時的には動きますが、 壊れやすさは増えていきます。\n設計ができる人は、判断を減らす 設計ができる人は、 逆の方向に進みます。\nそもそも書けなくできないか 間違った状態を表現できないか 呼び出し順を型で縛れないか つまり、\n人の判断を、構造に引き取らせる\n方向に進みます。\n設計ができない人は、「あとで直す」と言う 設計が曖昧なまま進むと、 よく聞く言葉があります。\nとりあえず、あとで直します\nこの「あとで」は、 ほとんどの場合、 来ません。\nなぜなら、\n動いている テストも通っている 誰も止めていない からです。\n設計ができる人は、「今は決めない」を決める 設計ができる人は、 「決めない」ことを恐れません。\nただし、\n意図して決めない\nという判断をします。\n今は仮置き ここは後で構造化する 判断が出揃ってからやる この区別がないと、 ただの放置になります。\n設計ができない人は、境界をまたぐ 設計ができない人は、 境界を軽く越えます。\n別レイヤーの事情を知る 他の責任に手を出す ついでに処理を書く その場では、 便利に見えます。\nしかし、\n境界を越えた瞬間に、判断が漏れる\nのです。\n設計ができる人は、境界で止まる 設計ができる人は、 境界で止まります。\nこれはここまで それ以上は知らない 知らなくていい構造にする 境界は、 不便にするためのものではありません。\n判断を閉じ込めるための装置 です。\n設計ができる人は、説明できる 設計ができる人は、 自分の設計を説明できます。\nなぜこの責任なのか なぜこの境界なのか なぜこの制約なのか これは、 口がうまいという意味ではありません。\n判断を構造に落とした記憶がある ということです。\n設計ができない人は、結果で語る 一方で、 設計ができない人は、 こう言いがちです。\nとりあえず動いてます 今のところ問題ないです バグは出ていません これらは、 設計の説明ではありません。\nたまたま壊れていないだけ です。\n設計ができる人は、未来の自分を見る 設計ができる人は、 常に未来を見ています。\n半年後の自分 初めて触る人 深夜に直す人 この視点があると、\n判断を残さない 暗黙知を作らない 説明がなくても読める 構造を作ろうとします。\n設計ができる人は、速さを急がない 速く書くことと、 速く作れることは違います。\n設計ができる人は、\n判断が多いところでは止まり 構造が決まれば一気に書く このメリハリがあります。\n結果として、 一番速くゴールに着く のです。\nこの章のまとめ 設計ができる人は、\n正解を探さない 壊れ方を見る 判断を構造に移す 境界で止まる 意図して決めない 説明できる 設計力とは、 才能ではありません。 判断を見る力と、構造に落とす習慣 です。\n次の章では、 ここまでの話を踏まえて、\n「なぜ、速さが価値に見えてしまうのか」\nという、 最初の問いに立ち返ります。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/12-what-is-the-difference/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E4%BA%BA%E3%81%AF%E6%AD%A3%E3%81%97%E3%81%95%E3%82%92%E6%8E%A2%E3%81%99\"\u003e設計ができない人は、正しさを探す\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E4%BA%BA%E3%81%AF%E5%A3%8A%E3%82%8C%E6%96%B9%E3%82%92%E8%A6%8B%E3%82%8B\"\u003e設計ができる人は、壊れ方を見る\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E4%BA%BA%E3%81%AF%E5%AE%9F%E8%A3%85%E3%81%A7%E3%82%AB%E3%83%90%E3%83%BC%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E3%81%99%E3%82%8B\"\u003e設計ができない人は、実装でカバーしようとする\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E4%BA%BA%E3%81%AF%E5%88%A4%E6%96%AD%E3%82%92%E6%B8%9B%E3%82%89%E3%81%99\"\u003e設計ができる人は、判断を減らす\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E4%BA%BA%E3%81%AF%E3%81%82%E3%81%A8%E3%81%A7%E7%9B%B4%E3%81%99%E3%81%A8%E8%A8%80%E3%81%86\"\u003e設計ができない人は、「あとで直す」と言う\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E4%BA%BA%E3%81%AF%E4%BB%8A%E3%81%AF%E6%B1%BA%E3%82%81%E3%81%AA%E3%81%84%E3%82%92%E6%B1%BA%E3%82%81%E3%82%8B\"\u003e設計ができる人は、「今は決めない」を決める\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E4%BA%BA%E3%81%AF%E5%A2%83%E7%95%8C%E3%82%92%E3%81%BE%E3%81%9F%E3%81%90\"\u003e設計ができない人は、境界をまたぐ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E4%BA%BA%E3%81%AF%E5%A2%83%E7%95%8C%E3%81%A7%E6%AD%A2%E3%81%BE%E3%82%8B\"\u003e設計ができる人は、境界で止まる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E4%BA%BA%E3%81%AF%E8%AA%AC%E6%98%8E%E3%81%A7%E3%81%8D%E3%82%8B\"\u003e設計ができる人は、説明できる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E4%BA%BA%E3%81%AF%E7%B5%90%E6%9E%9C%E3%81%A7%E8%AA%9E%E3%82%8B\"\u003e設計ができない人は、結果で語る\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E4%BA%BA%E3%81%AF%E6%9C%AA%E6%9D%A5%E3%81%AE%E8%87%AA%E5%88%86%E3%82%92%E8%A6%8B%E3%82%8B\"\u003e設計ができる人は、未来の自分を見る\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E4%BA%BA%E3%81%AF%E9%80%9F%E3%81%95%E3%82%92%E6%80%A5%E3%81%8C%E3%81%AA%E3%81%84\"\u003e設計ができる人は、速さを急がない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e設計ができる人と、\nできない人の違いは、\n知識量ではありません。\u003c/p\u003e\n\u003cp\u003e経験年数でも、\n使っているフレームワークでもありません。\u003c/p\u003e\n\u003cp\u003e違いが出るのは、\n\u003cstrong\u003eコードを書く前と後の「見え方」\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"設計ができない人は正しさを探す\"\u003e設計ができない人は、正しさを探す\u003c/h2\u003e\n\u003cp\u003e設計がうまくいかないとき、\n多くの場合、\nこう考えています。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e正しい書き方はどれか\u003c/li\u003e\n\u003cli\u003eベストプラクティスは何か\u003c/li\u003e\n\u003cli\u003eサンプルはどうなっているか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれは、 \u003cstrong\u003e正解を探す思考\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003eしかし設計の世界では、\n正解は一つではありません。\u003c/p\u003e\n\u003cp\u003e必要なのは、\n正解探しではなく、\n\u003cstrong\u003e壊れ方を想像する力\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"設計ができる人は壊れ方を見る\"\u003e設計ができる人は、壊れ方を見る\u003c/h2\u003e\n\u003cp\u003e設計ができる人は、\nコードを見てこう考えます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこれは、どこから壊れるか\u003c/li\u003e\n\u003cli\u003e判断は、どこに漏れそうか\u003c/li\u003e\n\u003cli\u003e誰が、どこで迷うか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eつまり、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e「失敗のルート」から設計を見る\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eのです。\u003c/p\u003e\n\u003cp\u003eこれは、\n\u003cstrong\u003e悲観的\u003c/strong\u003e という意味ではありません。\n\u003cstrong\u003e現実的\u003c/strong\u003e という意味です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"設計ができない人は実装でカバーしようとする\"\u003e設計ができない人は、実装でカバーしようとする\u003c/h2\u003e\n\u003cp\u003e判断が曖昧なとき、\n設計ができない人は、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eif を足す\u003c/li\u003e\n\u003cli\u003eチェックを増やす\u003c/li\u003e\n\u003cli\u003eテストで守る\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという方向に進みがちです。\u003c/p\u003e\n\u003cp\u003eこれは、\n\u003cstrong\u003e構造で解くべき問題を、実装で無理やり押し込んでいる\u003c/strong\u003e\n状態です。\u003c/p\u003e\n\u003cp\u003e一時的には動きますが、\n壊れやすさは増えていきます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"設計ができる人は判断を減らす\"\u003e設計ができる人は、判断を減らす\u003c/h2\u003e\n\u003cp\u003e設計ができる人は、\n逆の方向に進みます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eそもそも書けなくできないか\u003c/li\u003e\n\u003cli\u003e間違った状態を表現できないか\u003c/li\u003e\n\u003cli\u003e呼び出し順を型で縛れないか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eつまり、\u003c/p\u003e","title":"第12章：設計ができる人は、何が違うのか"},{"content":" 速さは、目に見える 設計の価値は、時間差で現れる 人間は、未来の価値を割り引く 「まず動くものを作る」は、間違いではない 問題は、「速さで止まってしまう」こと 速さは、設計を先送りにする免罪符になる 本当に速い人は、止まれる人 設計は、速さを否定しない この章のまとめ 多くの現場で、 こんな評価がされがちです。\n早く実装できる人は優秀 手が止まらない人は頼りになる とりあえず動くものを出せる人が強い 設計よりも、 速さが価値として見える瞬間 です。\nなぜ、 こうなってしまうのでしょうか。\n速さは、目に見える まず、 速さはとてもわかりやすい指標です。\n何日でできたか どれくらいの量を書いたか すぐに画面が動いたか これらは、 誰の目にも見えます。\n一方で、\n判断が構造に閉じ込められているか 責任がきれいに分かれているか 将来の変更に耐えられるか といった設計の価値は、 その場では見えません。\n設計の価値は、時間差で現れる 設計の良し悪しは、 あとから効いてきます。\n仕様変更が入ったとき 人が入れ替わったとき 想定外の使われ方をしたとき その瞬間に初めて、\n修正が一瞬で終わる 影響範囲が限定されている 原因がすぐに特定できる といった差が現れます。\nつまり、 設計は未来のための仕事 です。\n人間は、未来の価値を割り引く ここに、 人間の認知の癖があります。\n人は、\n今すぐ得られる成果 目の前の評価 今日怒られないこと を優先しがちです。\n半年後の自分の苦労より、 今日の「進んでいる感」の方が、 強く感じられます。\nその結果、 設計より速さを選んでしまう のです。\n「まず動くものを作る」は、間違いではない ここで、 大事な補足があります。\n「まず動くものを作る」 という考え方自体は、 間違いではありません。\nむしろ、\n要件が曖昧な段階 正解がまだ見えていない段階 問題空間を理解する段階 では、 動くものがないと、設計できない ことも多いです。\nいきなり、 最初からリファクタリング不要なコードを書くのは、 シニアでもほぼ不可能です。\n問題は、「速さで止まってしまう」こと 問題は、\n速く作ること ではなく 速く作ったまま止まってしまうこと です。\nプロトタイプのはずが、 いつの間にか本番コードになり、\n判断が散らばり 責任が混ざり 構造が育たない まま、機能だけが増えていきます。\n速さは、設計を先送りにする免罪符になる 「今は速さが大事だから」 という言葉は、\n設計をしない理由 判断を曖昧にする理由 境界を越える理由 として使われがちです。\nしかしそれは、 設計をしないことを正当化しているだけ かもしれません。\n本当に速い人は、止まれる人 皮肉なことに、 本当に速い人ほど、 よく止まります。\n判断が増え始めたところで止まる 構造が崩れそうなところで止まる このまま進むと壊れると気づいて止まる その上で、\n判断を構造に戻し 責任を分け直し 境界を引き直す だから結果的に、 全体として一番速い のです。\n設計は、速さを否定しない この本は、 速さを否定しません。\nただし、\n速さだけを評価しない 速さで設計を潰さない 速さの裏にある判断を見る ことを勧めています。\n設計とは、 スピードを落とす行為ではありません。 スピードを維持できる構造を作る行為 です。\nこの章のまとめ 速さは、目に見える価値 設計の価値は、時間差で現れる 人は未来の価値を過小評価する 「まず動くもの」は間違いではない 問題は、速さで止まってしまうこと 本当に速い人は、設計のために止まれる人 次の章では、 この本全体を締めくくる形で、\n「では、設計とどう向き合えばいいのか」\nという実践的な話に進みます。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/13-why-does-speed-seem-valuable2/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E9%80%9F%E3%81%95%E3%81%AF%E7%9B%AE%E3%81%AB%E8%A6%8B%E3%81%88%E3%82%8B\"\u003e速さは、目に見える\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AE%E4%BE%A1%E5%80%A4%E3%81%AF%E6%99%82%E9%96%93%E5%B7%AE%E3%81%A7%E7%8F%BE%E3%82%8C%E3%82%8B\"\u003e設計の価値は、時間差で現れる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BA%BA%E9%96%93%E3%81%AF%E6%9C%AA%E6%9D%A5%E3%81%AE%E4%BE%A1%E5%80%A4%E3%82%92%E5%89%B2%E3%82%8A%E5%BC%95%E3%81%8F\"\u003e人間は、未来の価値を割り引く\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%9A%E5%8B%95%E3%81%8F%E3%82%82%E3%81%AE%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%AF%E9%96%93%E9%81%95%E3%81%84%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e「まず動くものを作る」は、間違いではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%95%8F%E9%A1%8C%E3%81%AF%E9%80%9F%E3%81%95%E3%81%A7%E6%AD%A2%E3%81%BE%E3%81%A3%E3%81%A6%E3%81%97%E3%81%BE%E3%81%86%E3%81%93%E3%81%A8\"\u003e問題は、「速さで止まってしまう」こと\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%80%9F%E3%81%95%E3%81%AF%E8%A8%AD%E8%A8%88%E3%82%92%E5%85%88%E9%80%81%E3%82%8A%E3%81%AB%E3%81%99%E3%82%8B%E5%85%8D%E7%BD%AA%E7%AC%A6%E3%81%AB%E3%81%AA%E3%82%8B\"\u003e速さは、設計を先送りにする免罪符になる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9C%AC%E5%BD%93%E3%81%AB%E9%80%9F%E3%81%84%E4%BA%BA%E3%81%AF%E6%AD%A2%E3%81%BE%E3%82%8C%E3%82%8B%E4%BA%BA\"\u003e本当に速い人は、止まれる人\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AF%E9%80%9F%E3%81%95%E3%82%92%E5%90%A6%E5%AE%9A%E3%81%97%E3%81%AA%E3%81%84\"\u003e設計は、速さを否定しない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e多くの現場で、\nこんな評価がされがちです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e早く実装できる人は優秀\u003c/li\u003e\n\u003cli\u003e手が止まらない人は頼りになる\u003c/li\u003e\n\u003cli\u003eとりあえず動くものを出せる人が強い\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e設計よりも、\n\u003cstrong\u003e速さが価値として見える瞬間\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003eなぜ、\nこうなってしまうのでしょうか。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"速さは目に見える\"\u003e速さは、目に見える\u003c/h2\u003e\n\u003cp\u003eまず、\n速さはとてもわかりやすい指標です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e何日でできたか\u003c/li\u003e\n\u003cli\u003eどれくらいの量を書いたか\u003c/li\u003e\n\u003cli\u003eすぐに画面が動いたか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは、\n誰の目にも見えます。\u003c/p\u003e\n\u003cp\u003e一方で、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e判断が構造に閉じ込められているか\u003c/li\u003e\n\u003cli\u003e責任がきれいに分かれているか\u003c/li\u003e\n\u003cli\u003e将来の変更に耐えられるか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった設計の価値は、\n\u003cstrong\u003eその場では見えません。\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"設計の価値は時間差で現れる\"\u003e設計の価値は、時間差で現れる\u003c/h2\u003e\n\u003cp\u003e設計の良し悪しは、\nあとから効いてきます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e仕様変更が入ったとき\u003c/li\u003e\n\u003cli\u003e人が入れ替わったとき\u003c/li\u003e\n\u003cli\u003e想定外の使われ方をしたとき\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eその瞬間に初めて、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e修正が一瞬で終わる\u003c/li\u003e\n\u003cli\u003e影響範囲が限定されている\u003c/li\u003e\n\u003cli\u003e原因がすぐに特定できる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった差が現れます。\u003c/p\u003e\n\u003cp\u003eつまり、\n\u003cstrong\u003e設計は未来のための仕事\u003c/strong\u003e\nです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"人間は未来の価値を割り引く\"\u003e人間は、未来の価値を割り引く\u003c/h2\u003e\n\u003cp\u003eここに、\n人間の認知の癖があります。\u003c/p\u003e\n\u003cp\u003e人は、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e今すぐ得られる成果\u003c/li\u003e\n\u003cli\u003e目の前の評価\u003c/li\u003e\n\u003cli\u003e今日怒られないこと\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを優先しがちです。\u003c/p\u003e\n\u003cp\u003e半年後の自分の苦労より、\n今日の「進んでいる感」の方が、\n強く感じられます。\u003c/p\u003e\n\u003cp\u003eその結果、\n\u003cstrong\u003e設計より速さを選んでしまう\u003c/strong\u003e\nのです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"まず動くものを作るは間違いではない\"\u003e「まず動くものを作る」は、間違いではない\u003c/h2\u003e\n\u003cp\u003eここで、\n大事な補足があります。\u003c/p\u003e\n\u003cp\u003e「まず動くものを作る」\nという考え方自体は、\n間違いではありません。\u003c/p\u003e\n\u003cp\u003eむしろ、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e要件が曖昧な段階\u003c/li\u003e\n\u003cli\u003e正解がまだ見えていない段階\u003c/li\u003e\n\u003cli\u003e問題空間を理解する段階\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eでは、\n\u003cstrong\u003e動くものがないと、設計できない\u003c/strong\u003e\nことも多いです。\u003c/p\u003e","title":"第13章：なぜ、速さが価値に見えてしまうのか"},{"content":" 設計は、未来への投資 まず小さく止めて、判断を構造に埋め込む 状態・境界・判断を意識する 「速さ」と「設計」は両立できる この章のまとめ：設計との向き合い方 最後に 設計の本質は 責任の分割 であり、 それを 構造で保証する ことが重要です。\nこれまで述べてきた 判断を構造で表現する ことで、それが実現できます。\nでは、実際の開発現場で、 私たちは、どのように設計と向き合うべきでしょうか。\n設計は、未来への投資 設計は、未来のための行為です。\n今すぐ動かすことが最優先の時もある その場で作るコードに価値がある それでも、設計を全く無視すると、\n判断が散らばり 責任が混ざり 境界が曖昧なコードが増え 結果として、未来の変更コストが爆発します。\n設計とは、 将来の自分やチームを守る投資 だと理解しましょう。\nまず小さく止めて、判断を構造に埋め込む 設計と向き合う第一歩は、\n「まず止まること」 です。\nこの変更はどこに影響するか ここでの判断はどこに置くべきか 責任は分かれているか そして、それを コードの構造に落とし込む のです。\n小さく止まることは、速さを失うことではありません。 むしろ、全体としての速さを保つための準備です。\n状態・境界・判断を意識する 設計と向き合う際の基本は、次の3つです。\n状態\n状態を正確に表現する ありえない状態を作れないようにする 判断\n「やってよい／いけない」を構造で表現する 型、API、オブジェクト生成条件、モジュール境界に集約する 境界\n判断や責任を閉じ込め、影響範囲を限定する モジュール間、画面間、レイヤー間で明確にする この3つは、別々の話ではなく、同じ設計の本質を違う角度で見たものです。\n「速さ」と「設計」は両立できる 速さを求めながらも設計を無視しない方法があります。\n小さな単位で止まる 判断を構造に埋め込む 境界を明確にする 状態を正しく管理する このプロセスを繰り返すことで、コードは壊れにくく、かつ速く開発できるようになります。\nこの章のまとめ：設計との向き合い方 設計とは、単なる図や抽象化ではありません。\n設計は、責任を分割し、構造に落とし込み、判断を閉じ込めること。\n向き合い方のポイントは次の通りです。\n止まる勇気を持つ\n判断や責任が散らばる前に、構造に埋め込む 構造を信頼する\n人に頼らず、構造が守る 未来の価値を意識する\n今の速さよりも、将来の保守性と拡張性を優先 小さく繰り返す\n状態・判断・境界を意識しながら、少しずつ改善 設計とは、人間のスキルや努力ではなく、 構造そのものが正しい判断を引き受けること です。\n最後に この本で伝えたかったことは、\n設計は抽象的な美学ではなく、構造による保証のこと 判断を構造に集約することで、コードは壊れにくくなる 速さと設計は両立できる です。\nこの考え方を理解すれば、\nあなたのコードはより安全で、 未来のチームはより速く、 あなた自身もより少ない思考コストで開発できる ようになります。\n設計は怖いものでも、面倒なものでもありません。 正しく向き合うだけで、強力な味方になるものです。\n","permalink":"https://design.okuda-studio.com/books/001-the-essence-of-design/14-how-to-deal-with-design/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AF%E6%9C%AA%E6%9D%A5%E3%81%B8%E3%81%AE%E6%8A%95%E8%B3%87\"\u003e設計は、未来への投資\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%9A%E5%B0%8F%E3%81%95%E3%81%8F%E6%AD%A2%E3%82%81%E3%81%A6%E5%88%A4%E6%96%AD%E3%82%92%E6%A7%8B%E9%80%A0%E3%81%AB%E5%9F%8B%E3%82%81%E8%BE%BC%E3%82%80\"\u003eまず小さく止めて、判断を構造に埋め込む\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E5%A2%83%E7%95%8C%E5%88%A4%E6%96%AD%E3%82%92%E6%84%8F%E8%AD%98%E3%81%99%E3%82%8B\"\u003e状態・境界・判断を意識する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%80%9F%E3%81%95%E3%81%A8%E8%A8%AD%E8%A8%88%E3%81%AF%E4%B8%A1%E7%AB%8B%E3%81%A7%E3%81%8D%E3%82%8B\"\u003e「速さ」と「設計」は両立できる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81%E8%A8%AD%E8%A8%88%E3%81%A8%E3%81%AE%E5%90%91%E3%81%8D%E5%90%88%E3%81%84%E6%96%B9\"\u003eこの章のまとめ：設計との向き合い方\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9C%80%E5%BE%8C%E3%81%AB\"\u003e最後に\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e設計の本質は \u003cstrong\u003e責任の分割\u003c/strong\u003e であり、\nそれを \u003cstrong\u003e構造で保証する\u003c/strong\u003e ことが重要です。\u003c/p\u003e\n\u003cp\u003eこれまで述べてきた\n\u003cstrong\u003e判断を構造で表現する\u003c/strong\u003e\nことで、それが実現できます。\u003c/p\u003e\n\u003cp\u003eでは、実際の開発現場で、\n私たちは、どのように設計と向き合うべきでしょうか。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"設計は未来への投資\"\u003e設計は、未来への投資\u003c/h2\u003e\n\u003cp\u003e設計は、未来のための行為です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e今すぐ動かすことが最優先の時もある\u003c/li\u003e\n\u003cli\u003eその場で作るコードに価値がある\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eそれでも、設計を全く無視すると、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e判断が散らばり\u003c/li\u003e\n\u003cli\u003e責任が混ざり\u003c/li\u003e\n\u003cli\u003e境界が曖昧なコードが増え\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e結果として、未来の変更コストが爆発します。\u003c/p\u003e\n\u003cp\u003e設計とは、 \u003cstrong\u003e将来の自分やチームを守る投資\u003c/strong\u003e だと理解しましょう。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"まず小さく止めて判断を構造に埋め込む\"\u003eまず小さく止めて、判断を構造に埋め込む\u003c/h2\u003e\n\u003cp\u003e設計と向き合う第一歩は、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e「まず止まること」\u003c/strong\u003e です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこの変更はどこに影響するか\u003c/li\u003e\n\u003cli\u003eここでの判断はどこに置くべきか\u003c/li\u003e\n\u003cli\u003e責任は分かれているか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eそして、それを \u003cstrong\u003eコードの構造に落とし込む\u003c/strong\u003e のです。\u003c/p\u003e\n\u003cp\u003e小さく止まることは、速さを失うことではありません。\nむしろ、全体としての速さを保つための準備です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"状態境界判断を意識する\"\u003e状態・境界・判断を意識する\u003c/h2\u003e\n\u003cp\u003e設計と向き合う際の基本は、次の3つです。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e状態\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e状態を正確に表現する\u003c/li\u003e\n\u003cli\u003eありえない状態を作れないようにする\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e判断\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e「やってよい／いけない」を構造で表現する\u003c/li\u003e\n\u003cli\u003e型、API、オブジェクト生成条件、モジュール境界に集約する\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e境界\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e判断や責任を閉じ込め、影響範囲を限定する\u003c/li\u003e\n\u003cli\u003eモジュール間、画面間、レイヤー間で明確にする\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eこの3つは、別々の話ではなく、\u003cstrong\u003e同じ設計の本質を違う角度で見たもの\u003c/strong\u003eです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"速さと設計は両立できる\"\u003e「速さ」と「設計」は両立できる\u003c/h2\u003e\n\u003cp\u003e速さを求めながらも設計を無視しない方法があります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e小さな単位で止まる\u003c/li\u003e\n\u003cli\u003e判断を構造に埋め込む\u003c/li\u003e\n\u003cli\u003e境界を明確にする\u003c/li\u003e\n\u003cli\u003e状態を正しく管理する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこのプロセスを繰り返すことで、コードは壊れにくく、かつ速く開発できるようになります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"この章のまとめ設計との向き合い方\"\u003eこの章のまとめ：設計との向き合い方\u003c/h2\u003e\n\u003cp\u003e設計とは、単なる図や抽象化ではありません。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e設計は、責任を分割し、構造に落とし込み、判断を閉じ込めること。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e向き合い方のポイントは次の通りです。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e止まる勇気を持つ\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e判断や責任が散らばる前に、構造に埋め込む\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e構造を信頼する\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e人に頼らず、構造が守る\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e未来の価値を意識する\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e今の速さよりも、将来の保守性と拡張性を優先\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e小さく繰り返す\u003c/strong\u003e\u003c/p\u003e","title":"第14章：では、設計とどう向き合えばいいのか"},{"content":" Android アプリは「UI 駆動・状態駆動」である 変更理由の大半は「ビジネスロジック」ではない レイヤードアーキテクチャが破綻しやすい理由 MVVM + UseCase が量産されて価値を失う場合 本書が前提とする現実 Android アプリは「UI 駆動・状態駆動」である Android アプリ開発の現実を一言で表すなら、「UI と状態の変更がすべて」と言っても過言ではありません。\n多くの仕様変更は、次のような形で現れます。\n画面に表示する項目が増える／減る 表示条件が変わる ローディングやエラーの出し方が変わる 画面遷移の分岐が増える つまり、変更の起点はほぼ常に UI にあります。\nWeb や業務系システムのように「ドメインロジックが主役で、UI はその結果を表示するだけ」という構造とは、前提が大きく異なります。Android では、UI と状態管理が設計の中心に座らざるを得ません。\nこの事実を無視して設計を始めると、あとで必ず歪みが生まれます。\n変更理由の大半は「ビジネスロジック」ではない DDD という言葉を聞くと、多くの人は「複雑なビジネスロジック」を思い浮かべます。しかし、実際の Android アプリ開発で頻発する変更理由は、それとは少し違います。\n文言の変更 表示順の変更 UI の状態分岐の追加 API レスポンスの仕様変更への追従 これらは、いわゆる「ビジネスルールの変更」とは言いづらいものです。\nそれにもかかわらず、すべてをドメインロジックとして抽象化しようとすると、設計は一気に重くなります。結果として、「変更が楽になるはずの設計」が、逆に変更の足かせになります。\nここで重要なのは、すべての判断をドメインに集約しなくていい という認識です。\nレイヤードアーキテクチャが破綻しやすい理由 多くの Android プロジェクトは、次のような構成から始まります。\nUI（View / Compose） ViewModel UseCase Repository DataSource 一見すると、責務がきれいに分離されているように見えます。しかし、プロジェクトが成長するにつれて、次のような問題が表面化します。\nUseCase が単なる中継層になる ViewModel が肥大化する Repository に判断ロジックが混入する これは、設計が悪いから起きる問題ではありません。Android の変更特性と、この構造が噛み合っていない ことが原因です。\nUI 起点の変更が増えるほど、「どこにロジックを置くべきか」の判断が曖昧になり、結果としてレイヤー間の責務が崩れていきます。\nMVVM + UseCase が量産されて価値を失う場合 MVVM + UseCase という構成は、多くの Android チームで採用されています。しかし、一定規模を超えたあたりから、次のような兆候が見え始めます。\n画面ごとに UseCase が増え続ける 名前の違いしかない UseCase が並ぶ テストされない UseCase が溜まっていく これは、UseCase という概念が悪いわけではありません。\n問題は、「UseCase を作ること」が目的化してしまうことです。本来は責務を明確にするための手段だったはずが、いつの間にか層を埋めるための存在になってしまいます。\nこの状態では、DDD を導入した意味はほとんど残りません。\n本書が前提とする現実 本書では、次のような前提に立って話を進めます。\nAndroid アプリは UI 変更が中心である すべてのロジックをドメインに集約する必要はない 設計は「きれいさ」よりも「壊しやすさ」が重要である この前提を受け入れた上で、次章以降では「それでも DDD の考え方が役に立つ場面」を具体的に見ていきます。\nDDD を捨てるためではなく、使える形に削ぎ落とすために。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/02/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003eAndroid アプリは「UI 駆動・状態駆動」である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003e変更理由の大半は「ビジネスロジック」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eレイヤードアーキテクチャが破綻しやすい理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eMVVM + UseCase が量産されて価値を失う場合\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003e本書が前提とする現実\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"android-アプリはui-駆動状態駆動である\"\u003eAndroid アプリは「UI 駆動・状態駆動」である\u003c/h3\u003e\n\u003cp\u003eAndroid アプリ開発の現実を一言で表すなら、「UI と状態の変更がすべて」と言っても過言ではありません。\u003c/p\u003e\n\u003cp\u003e多くの仕様変更は、次のような形で現れます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e画面に表示する項目が増える／減る\u003c/li\u003e\n\u003cli\u003e表示条件が変わる\u003c/li\u003e\n\u003cli\u003eローディングやエラーの出し方が変わる\u003c/li\u003e\n\u003cli\u003e画面遷移の分岐が増える\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eつまり、変更の起点はほぼ常に UI にあります。\u003c/p\u003e\n\u003cp\u003eWeb や業務系システムのように「ドメインロジックが主役で、UI はその結果を表示するだけ」という構造とは、前提が大きく異なります。Android では、UI と状態管理が設計の中心に座らざるを得ません。\u003c/p\u003e\n\u003cp\u003eこの事実を無視して設計を始めると、あとで必ず歪みが生まれます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"変更理由の大半はビジネスロジックではない\"\u003e変更理由の大半は「ビジネスロジック」ではない\u003c/h3\u003e\n\u003cp\u003eDDD という言葉を聞くと、多くの人は「複雑なビジネスロジック」を思い浮かべます。しかし、実際の Android アプリ開発で頻発する変更理由は、それとは少し違います。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e文言の変更\u003c/li\u003e\n\u003cli\u003e表示順の変更\u003c/li\u003e\n\u003cli\u003eUI の状態分岐の追加\u003c/li\u003e\n\u003cli\u003eAPI レスポンスの仕様変更への追従\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは、いわゆる「ビジネスルールの変更」とは言いづらいものです。\u003c/p\u003e\n\u003cp\u003eそれにもかかわらず、すべてをドメインロジックとして抽象化しようとすると、設計は一気に重くなります。結果として、「変更が楽になるはずの設計」が、逆に変更の足かせになります。\u003c/p\u003e\n\u003cp\u003eここで重要なのは、\u003cstrong\u003eすべての判断をドメインに集約しなくていい\u003c/strong\u003e という認識です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"レイヤードアーキテクチャが破綻しやすい理由\"\u003eレイヤードアーキテクチャが破綻しやすい理由\u003c/h3\u003e\n\u003cp\u003e多くの Android プロジェクトは、次のような構成から始まります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUI（View / Compose）\u003c/li\u003e\n\u003cli\u003eViewModel\u003c/li\u003e\n\u003cli\u003eUseCase\u003c/li\u003e\n\u003cli\u003eRepository\u003c/li\u003e\n\u003cli\u003eDataSource\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e一見すると、責務がきれいに分離されているように見えます。しかし、プロジェクトが成長するにつれて、次のような問題が表面化します。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUseCase が単なる中継層になる\u003c/li\u003e\n\u003cli\u003eViewModel が肥大化する\u003c/li\u003e\n\u003cli\u003eRepository に判断ロジックが混入する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれは、設計が悪いから起きる問題ではありません。\u003cstrong\u003eAndroid の変更特性と、この構造が噛み合っていない\u003c/strong\u003e ことが原因です。\u003c/p\u003e\n\u003cp\u003eUI 起点の変更が増えるほど、「どこにロジックを置くべきか」の判断が曖昧になり、結果としてレイヤー間の責務が崩れていきます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"mvvm--usecase-が量産されて価値を失う場合\"\u003eMVVM + UseCase が量産されて価値を失う場合\u003c/h3\u003e\n\u003cp\u003eMVVM + UseCase という構成は、多くの Android チームで採用されています。しかし、一定規模を超えたあたりから、次のような兆候が見え始めます。\u003c/p\u003e","title":"第1章：Android アプリ開発の現実"},{"content":" なぜ「DDDは難しい」と言われるのか DDDは「EntityとValue Objectを作ること」ではない DDDは「Repositoryをinterfaceにすること」ではない DDDはClean Architectureと同義ではない なぜ設計は時間とともに壊れていくのか この本で扱うDDD なぜ「DDDは難しい」と言われるのか 「DDD（ドメイン駆動設計）は難しい」──これは、多くのエンジニアが一度は口にする言葉です。実際、DDDに関する書籍や記事を読み、Entity、Value Object、Aggregate、Repositoryといった用語を学んだにもかかわらず、「で、実際のプロジェクトでどう使えばいいのか分からない」という感覚を抱いた人は少なくないでしょう。\nしかし、本当にDDDそのものが難しいのでしょうか。筆者は、DDDが難しく感じられる最大の理由は、「DDDが何であるか」を学ぶ前に、「DDDが何ではないか」を十分に理解しないまま、表面的な技法だけを適用しようとしてしまう点にあると考えています。\nDDDは、フレームワークでも、設計パターン集でもありません。ましてや、Entityクラスを作り、Repositoryインターフェースを定義すれば完成するようなチェックリストでもありません。にもかかわらず、多くの現場では、DDDが「特定のクラス構成」や「お作法の集合」として誤解されたまま導入されています。\nこの章ではまず、DDDを正しく理解するための第一歩として、「DDDとは何ではないのか」を整理します。これはDDDを否定する章ではなく、むしろDDDの本質に近づくために、不要な誤解を一つずつ取り除いていくための章です。\nDDDは「EntityとValue Objectを作ること」ではない DDDの説明として、最もよく見かけるのが次のようなものです。\nIDを持つものが Entity 値で同一性を判断するものが Value Object これ自体は間違いではありません。しかし、この説明だけを鵜呑みにしてしまうと、「DDD = EntityとValue Objectを定義すること」という非常に危険な短絡に陥ります。\n実際の現場では、次のようなコードをよく目にします。\nただのDTOにすぎないEntity ロジックを一切持たないValue Object 生成されるが、ほとんど使われないドメインモデル これらは、DDDの用語を使ってはいるものの、DDDの考え方はほとんど反映されていません。EntityやValue Objectは、DDDの「結果」であって「目的」ではないのです。\nDDDが本当に扱おうとしているのは、「そのシステムにおいて、何が重要で、何を守るべきか」という問いです。EntityかValue Objectか、という分類は、その問いに答えた結果として自然に現れるものにすぎません。\nDDDは「Repositoryをinterfaceにすること」ではない DDDやClean Architectureの文脈で、Repositoryはしばしば次のように説明されます。\n永続化処理を隠蔽する データベースへの依存を排除するためにinterfaceを切る これも一部は正しいのですが、ここでも「手段」が「目的」にすり替わる危険があります。Repositoryをinterfaceにした瞬間にDDDが成立するわけではありません。\nRepositoryの本質的な役割は、「ドメインモデルのコレクションとして振る舞う」ことです。データベースの都合ではなく、ドメインの言葉でモデルを取得・保存できるようにする。その結果として、永続化の詳細が隠蔽されるのであって、interfaceを切ること自体が目的ではありません。\nもしRepositoryが、単なるCRUD操作のラッパーになっているのであれば、それはDDD的なRepositoryとは言いがたいでしょう。\nDDDはClean Architectureと同義ではない DDDの話題になると、必ずと言っていいほどClean ArchitectureやHexagonal Architectureといった言葉が並びます。そのため、「DDD = Clean Architecture」だと誤解されがちです。\nしかし、両者は扱っているレイヤーが異なります。DDDは「どうモデルを考えるか」「業務の本質をどうコードに落とすか」という思考法であり、Clean Architectureは「依存関係をどう制御するか」という構造の話です。\n両者は相性が良く、組み合わせて使われることも多いですが、同一ではありません。Clean Architectureの形を整えただけでは、ドメインが貧血状態のまま放置されることもあります。\nつまり、DDDはアーキテクチャ図を描く前に始まっているのです。\nなぜ設計は時間とともに壊れていくのか 多くのプロジェクトでは、開発初期の設計はそれなりに整っています。しかし、機能追加や仕様変更を繰り返すうちに、次第に次のような状態に陥ります。\n条件分岐だらけのUseCase あちこちから呼ばれる共通関数 変更の影響範囲が読めないコード これは、エンジニアの技術力不足だけが原因ではありません。設計が「変更に耐えられない形」で作られていた場合、どれだけ注意深く書いても、いずれ破綻します。\nDDDは、この「変更によって設計が壊れていく問題」に正面から向き合うための考え方です。どこにルールを閉じ込め、どこを変更可能にするのか。その境界を明確にすることが、DDDの出発点です。\nこの本で扱うDDD 本書では、DDDを「銀の弾丸」としては扱いません。また、すべてのプロジェクトにDDDを適用すべきだとも主張しません。\n本書で扱うDDDは、次の問いに答えるための道具です。\nなぜこのロジックはここにあるのか なぜこの変更は怖いのか なぜ設計を説明できないのか これらの問いに向き合う準備ができたとき、DDDは初めて意味を持ちます。\n次章では、「ドメイン」とは何か、そしてなぜそれが設計の中心になるのかを、もう一段深く掘り下げていきます。\n","permalink":"https://design.okuda-studio.com/books/004-ddd/01/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9Cddd%E3%81%AF%E9%9B%A3%E3%81%97%E3%81%84%E3%81%A8%E8%A8%80%E3%82%8F%E3%82%8C%E3%82%8B%E3%81%AE%E3%81%8B\"\u003eなぜ「DDDは難しい」と言われるのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ddd%E3%81%AFentity%E3%81%A8value-object%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%93%E3%81%A8%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003eDDDは「EntityとValue Objectを作ること」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ddd%E3%81%AFrepository%E3%82%92interface%E3%81%AB%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003eDDDは「Repositoryをinterfaceにすること」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ddd%E3%81%AFclean-architecture%E3%81%A8%E5%90%8C%E7%BE%A9%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003eDDDはClean Architectureと同義ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E8%A8%AD%E8%A8%88%E3%81%AF%E6%99%82%E9%96%93%E3%81%A8%E3%81%A8%E3%82%82%E3%81%AB%E5%A3%8A%E3%82%8C%E3%81%A6%E3%81%84%E3%81%8F%E3%81%AE%E3%81%8B\"\u003eなぜ設計は時間とともに壊れていくのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E6%9C%AC%E3%81%A7%E6%89%B1%E3%81%86ddd\"\u003eこの本で扱うDDD\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"なぜdddは難しいと言われるのか\"\u003eなぜ「DDDは難しい」と言われるのか\u003c/h2\u003e\n\u003cp\u003e「DDD（ドメイン駆動設計）は難しい」──これは、多くのエンジニアが一度は口にする言葉です。実際、DDDに関する書籍や記事を読み、Entity、Value Object、Aggregate、Repositoryといった用語を学んだにもかかわらず、「で、実際のプロジェクトでどう使えばいいのか分からない」という感覚を抱いた人は少なくないでしょう。\u003c/p\u003e\n\u003cp\u003eしかし、本当にDDDそのものが難しいのでしょうか。筆者は、DDDが難しく感じられる最大の理由は、「DDDが何であるか」を学ぶ前に、「DDDが何ではないか」を十分に理解しないまま、表面的な技法だけを適用しようとしてしまう点にあると考えています。\u003c/p\u003e\n\u003cp\u003eDDDは、フレームワークでも、設計パターン集でもありません。ましてや、Entityクラスを作り、Repositoryインターフェースを定義すれば完成するようなチェックリストでもありません。にもかかわらず、多くの現場では、DDDが「特定のクラス構成」や「お作法の集合」として誤解されたまま導入されています。\u003c/p\u003e\n\u003cp\u003eこの章ではまず、DDDを正しく理解するための第一歩として、「DDDとは何ではないのか」を整理します。これはDDDを否定する章ではなく、むしろDDDの本質に近づくために、不要な誤解を一つずつ取り除いていくための章です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"dddはentityとvalue-objectを作ることではない\"\u003eDDDは「EntityとValue Objectを作ること」ではない\u003c/h2\u003e\n\u003cp\u003eDDDの説明として、最もよく見かけるのが次のようなものです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eIDを持つものが Entity\u003c/li\u003e\n\u003cli\u003e値で同一性を判断するものが Value Object\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれ自体は間違いではありません。しかし、この説明だけを鵜呑みにしてしまうと、「DDD = EntityとValue Objectを定義すること」という非常に危険な短絡に陥ります。\u003c/p\u003e\n\u003cp\u003e実際の現場では、次のようなコードをよく目にします。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eただのDTOにすぎないEntity\u003c/li\u003e\n\u003cli\u003eロジックを一切持たないValue Object\u003c/li\u003e\n\u003cli\u003e生成されるが、ほとんど使われないドメインモデル\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは、DDDの用語を使ってはいるものの、DDDの考え方はほとんど反映されていません。EntityやValue Objectは、DDDの「結果」であって「目的」ではないのです。\u003c/p\u003e\n\u003cp\u003eDDDが本当に扱おうとしているのは、「そのシステムにおいて、何が重要で、何を守るべきか」という問いです。EntityかValue Objectか、という分類は、その問いに答えた結果として自然に現れるものにすぎません。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"dddはrepositoryをinterfaceにすることではない\"\u003eDDDは「Repositoryをinterfaceにすること」ではない\u003c/h2\u003e\n\u003cp\u003eDDDやClean Architectureの文脈で、Repositoryはしばしば次のように説明されます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e永続化処理を隠蔽する\u003c/li\u003e\n\u003cli\u003eデータベースへの依存を排除するためにinterfaceを切る\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれも一部は正しいのですが、ここでも「手段」が「目的」にすり替わる危険があります。Repositoryをinterfaceにした瞬間にDDDが成立するわけではありません。\u003c/p\u003e\n\u003cp\u003eRepositoryの本質的な役割は、「ドメインモデルのコレクションとして振る舞う」ことです。データベースの都合ではなく、ドメインの言葉でモデルを取得・保存できるようにする。その結果として、永続化の詳細が隠蔽されるのであって、interfaceを切ること自体が目的ではありません。\u003c/p\u003e\n\u003cp\u003eもしRepositoryが、単なるCRUD操作のラッパーになっているのであれば、それはDDD的なRepositoryとは言いがたいでしょう。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"dddはclean-architectureと同義ではない\"\u003eDDDはClean Architectureと同義ではない\u003c/h2\u003e\n\u003cp\u003eDDDの話題になると、必ずと言っていいほどClean ArchitectureやHexagonal Architectureといった言葉が並びます。そのため、「DDD = Clean Architecture」だと誤解されがちです。\u003c/p\u003e\n\u003cp\u003eしかし、両者は扱っているレイヤーが異なります。DDDは「どうモデルを考えるか」「業務の本質をどうコードに落とすか」という思考法であり、Clean Architectureは「依存関係をどう制御するか」という構造の話です。\u003c/p\u003e\n\u003cp\u003e両者は相性が良く、組み合わせて使われることも多いですが、同一ではありません。Clean Architectureの形を整えただけでは、ドメインが貧血状態のまま放置されることもあります。\u003c/p\u003e\n\u003cp\u003eつまり、DDDはアーキテクチャ図を描く前に始まっているのです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"なぜ設計は時間とともに壊れていくのか\"\u003eなぜ設計は時間とともに壊れていくのか\u003c/h2\u003e\n\u003cp\u003e多くのプロジェクトでは、開発初期の設計はそれなりに整っています。しかし、機能追加や仕様変更を繰り返すうちに、次第に次のような状態に陥ります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e条件分岐だらけのUseCase\u003c/li\u003e\n\u003cli\u003eあちこちから呼ばれる共通関数\u003c/li\u003e\n\u003cli\u003e変更の影響範囲が読めないコード\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれは、エンジニアの技術力不足だけが原因ではありません。設計が「変更に耐えられない形」で作られていた場合、どれだけ注意深く書いても、いずれ破綻します。\u003c/p\u003e\n\u003cp\u003eDDDは、この「変更によって設計が壊れていく問題」に正面から向き合うための考え方です。どこにルールを閉じ込め、どこを変更可能にするのか。その境界を明確にすることが、DDDの出発点です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"この本で扱うddd\"\u003eこの本で扱うDDD\u003c/h2\u003e\n\u003cp\u003e本書では、DDDを「銀の弾丸」としては扱いません。また、すべてのプロジェクトにDDDを適用すべきだとも主張しません。\u003c/p\u003e\n\u003cp\u003e本書で扱うDDDは、次の問いに答えるための道具です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eなぜこのロジックはここにあるのか\u003c/li\u003e\n\u003cli\u003eなぜこの変更は怖いのか\u003c/li\u003e\n\u003cli\u003eなぜ設計を説明できないのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらの問いに向き合う準備ができたとき、DDDは初めて意味を持ちます。\u003c/p\u003e","title":"第1章：DDDによくある誤解"},{"content":" DDD のフルセットは Android には過剰になりやすい Android に必要なのは、この 3 つだけ 境界は「層」ではなく「理由」で引く ユビキタス言語はクラス名よりも会話に現れる 変更に耐える構造とは「壊しやすい」こと 捨てていい DDD の要素、慎重に使う要素 この章のまとめ DDD のフルセットは Android には過剰になりやすい DDD には多くの構成要素があります。Aggregate、Repository、Factory、Domain Service、Specification など\u0026hellip;。これらは、複雑で長寿命なドメインを扱うシステムでは強力に機能します。\nしかし、Android アプリの多くは、\n画面と状態の変更が中心 要件の変化が早い チーム規模が小さい という前提のもとで開発されます。この文脈に DDD のフルセットをそのまま持ち込むと、構造はすぐに過剰になります。\nここで大事なのは、「DDD をどこまで削っても本質は残るのか」を見極めることです。\nAndroid に必要なのは、この 3 つだけ 本書では、Android において最低限持ち込むべき DDD の要点を、次の 3 つに絞ります。\n境界（責務の分離） 言葉（ユビキタス言語） 変更に耐える構造 この 3 つが守られていれば、DDD の「考え方」は十分に機能します。逆に言えば、これ以外は文脈次第で捨てて構いません。\n境界は「層」ではなく「理由」で引く 多くの設計議論では、「どの層に置くか」が主語になりがちです。しかし DDD の本質は、層ではなく変更理由にあります。\nなぜ、このロジックはここにあるのか どんな変更が入ったら、このコードを触ることになるのか この問いに答えられる場所に、コードを置くべきです。\nAndroid では、UI 変更とドメイン（意味やルール）の変更の頻度が極端に違うことが多く、層だけで境界を引くと責務が混ざります。本書では、「変更理由が違うものは分ける」という単純なルールを、設計判断の軸にします。\nユビキタス言語はクラス名よりも会話に現れる ユビキタス言語というと、難しいドメイン用語を正確にクラス名に落とすことだと思われがちです。しかし、本当に重要なのは、チーム内の会話で言葉が揃っていることです。\nその「状態」は何を指しているのか 「有効」とは、どの条件を満たした状態なのか 「未設定」と「空」は同じ意味なのか これらが曖昧なまま実装が進むと、設計はすぐに崩れます。\n本書では、ユビキタス言語を「コードを書く前に合意しておく言葉」として扱い、クラス設計よりも前段の思考として重視します。\n変更に耐える構造とは「壊しやすい」こと DDD の文脈では、「変更に強い設計」という言い方がよくされます。しかし Android 開発では、これは少し誤解を生みやすい表現です。\n本書では、変更に耐える構造を、\n壊しやすく、直しやすい構造\nと定義します。\n過剰に抽象化された構造は、一見すると堅牢ですが、実際には変更点を見つけにくく、修正コストが高くなりがちです。\nAndroid では、将来を守るよりも、次の変更を素早く受け止められることの方が重要な場面が多くあります。\n捨てていい DDD の要素、慎重に使う要素 ここで、本書の立場を明確にしておきます。\nAggregate：多くの Android アプリでは不要、または極小で十分 Factory：生成ロジックが複雑な場合のみ検討する Domain Service：UseCase と役割が被るなら作らない Repository：永続化抽象としてではなく、取得・保存の窓口として扱う これらは「使ってはいけない」わけではありません。必要になったときに、理由を説明できるなら使う というスタンスで進めます。\nこの章のまとめ DDD を Android に持ち込む際に重要なのは、\n型を守ることではなく、判断軸を持つこと 完成形を目指すのではなく、変化に合わせて育てること 次章では、「そもそも Android におけるドメインとは何か」を掘り下げ、どこまでをドメインと呼ぶべきかを整理していきます。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/03/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003eDDD のフルセットは Android には過剰になりやすい\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eAndroid に必要なのは、この 3 つだけ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003e境界は「層」ではなく「理由」で引く\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eユビキタス言語はクラス名よりも会話に現れる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003e変更に耐える構造とは「壊しやすい」こと\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003e捨てていい DDD の要素、慎重に使う要素\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"ddd-のフルセットは-android-には過剰になりやすい\"\u003eDDD のフルセットは Android には過剰になりやすい\u003c/h3\u003e\n\u003cp\u003eDDD には多くの構成要素があります。Aggregate、Repository、Factory、Domain Service、Specification など\u0026hellip;。これらは、複雑で長寿命なドメインを扱うシステムでは強力に機能します。\u003c/p\u003e\n\u003cp\u003eしかし、Android アプリの多くは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e画面と状態の変更が中心\u003c/li\u003e\n\u003cli\u003e要件の変化が早い\u003c/li\u003e\n\u003cli\u003eチーム規模が小さい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという前提のもとで開発されます。この文脈に DDD のフルセットをそのまま持ち込むと、構造はすぐに過剰になります。\u003c/p\u003e\n\u003cp\u003eここで大事なのは、「DDD をどこまで削っても本質は残るのか」を見極めることです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"android-に必要なのはこの-3-つだけ\"\u003eAndroid に必要なのは、この 3 つだけ\u003c/h3\u003e\n\u003cp\u003e本書では、Android において最低限持ち込むべき DDD の要点を、次の 3 つに絞ります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e境界（責務の分離）\u003c/li\u003e\n\u003cli\u003e言葉（ユビキタス言語）\u003c/li\u003e\n\u003cli\u003e変更に耐える構造\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの 3 つが守られていれば、DDD の「考え方」は十分に機能します。逆に言えば、これ以外は文脈次第で捨てて構いません。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"境界は層ではなく理由で引く\"\u003e境界は「層」ではなく「理由」で引く\u003c/h3\u003e\n\u003cp\u003e多くの設計議論では、「どの層に置くか」が主語になりがちです。しかし DDD の本質は、層ではなく\u003cstrong\u003e変更理由\u003c/strong\u003eにあります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eなぜ、このロジックはここにあるのか\u003c/li\u003e\n\u003cli\u003eどんな変更が入ったら、このコードを触ることになるのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの問いに答えられる場所に、コードを置くべきです。\u003c/p\u003e\n\u003cp\u003eAndroid では、UI 変更とドメイン（意味やルール）の変更の頻度が極端に違うことが多く、層だけで境界を引くと責務が混ざります。本書では、「変更理由が違うものは分ける」という単純なルールを、設計判断の軸にします。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"ユビキタス言語はクラス名よりも会話に現れる\"\u003eユビキタス言語はクラス名よりも会話に現れる\u003c/h3\u003e\n\u003cp\u003eユビキタス言語というと、難しいドメイン用語を正確にクラス名に落とすことだと思われがちです。しかし、本当に重要なのは、チーム内の会話で言葉が揃っていることです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eその「状態」は何を指しているのか\u003c/li\u003e\n\u003cli\u003e「有効」とは、どの条件を満たした状態なのか\u003c/li\u003e\n\u003cli\u003e「未設定」と「空」は同じ意味なのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらが曖昧なまま実装が進むと、設計はすぐに崩れます。\u003c/p\u003e\n\u003cp\u003e本書では、ユビキタス言語を「コードを書く前に合意しておく言葉」として扱い、クラス設計よりも前段の思考として重視します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"変更に耐える構造とは壊しやすいこと\"\u003e変更に耐える構造とは「壊しやすい」こと\u003c/h3\u003e\n\u003cp\u003eDDD の文脈では、「変更に強い設計」という言い方がよくされます。しかし Android 開発では、これは少し誤解を生みやすい表現です。\u003c/p\u003e","title":"第2章：DDD の要点だけを Android に持ち込む"},{"content":" ドメインとは「業務ロジック」のことではない なぜ「判断」が重要なのか ドメインは「処理の流れ」を知らない ドメインとUseCaseの違い ドメインは中心に置かれるが、万能ではない ドメインを見失った設計の末路 ドメインとは「業務ロジック」のことではない 「ドメインとは何ですか？」と聞かれたとき、多くの人は次のように答えます。\n業務ロジックのこと ビジネスルールのこと これらは、完全に間違いではありません。しかし、この理解のまま設計を進めると、ほぼ確実にドメインは壊れていきます。\nなぜなら、「業務ロジック」という言葉はあまりにも広く、そして曖昧だからです。画面遷移の条件も業務ロジックですし、APIを呼ぶタイミングも業務ロジックと言えてしまいます。その結果、「どこまでがドメインなのか」が誰にも説明できなくなります。\n本書では、ドメインをもう少し狭く、そして厳密に扱います。\nドメインとは、そのシステムが守るべき判断とルールの集合です。\nなぜ「判断」が重要なのか システムが存在する理由は、計算をすることでも、画面を表示することでもありません。多くの場合、システムは「判断」をするために存在しています。\nこの注文は成立してよいか この支払いは受け付けてよいか この状態で次の操作に進んでよいか これらはすべて判断です。そして、この判断には必ずルールがあります。もしルールがなければ、判断はできません。\nDDDが注目するのは、この「判断」と「ルール」がどこに書かれているのか、そしてそれが守られているのか、という点です。\nもし判断のロジックが、\nUseCaseのあちこちに散らばっていたり UI層に紛れ込んでいたり 仕様書の文章にしか存在していなかったり する場合、そのシステムは非常に壊れやすい状態にあります。\nドメインは「処理の流れ」を知らない ドメインを設計するとき、多くの人が最初につまずくポイントがあります。それは、「ドメインは何を知っていて、何を知らなくてよいのか」という問題です。\n結論から言うと、ドメインは処理の流れを知る必要はありません。\nどの画面から呼ばれたのか API経由なのか、バッチなのか 同期処理なのか、非同期処理なのか こうした情報は、ドメインにとって本質的ではありません。ドメインが知るべきなのは、「この状態で、この操作は許されるか」という一点だけです。\nこの切り分けができていないと、ドメインモデルはすぐに肥大化し、テストも困難になります。\nドメインとUseCaseの違い DDDを学び始めると、ドメインとUseCaseの役割の違いが分からなくなることがあります。両方とも「業務の中心」を扱っているように見えるからです。\nしかし、両者の責務は明確に異なります。\nドメイン：判断とルールを守る UseCase：処理の流れを組み立てる UseCaseは、「何を」「どの順番で」行うかを知っています。一方で、ドメインは「それをしてよいかどうか」だけを知っています。\nもしUseCaseの中に大量のif文が現れ始めたら、それはドメインが本来持つべき判断をUseCaseが肩代わりしているサインです。\nドメインは中心に置かれるが、万能ではない DDDでは、「ドメインを中心に置く」という表現がよく使われます。この言葉は非常に強く、誤解を招きやすい表現でもあります。\nドメインを中心に置くとは、\nすべての処理をドメインに書くこと すべてのクラスをドメインから呼ぶこと ではありません。\n中心に置くとは、「設計上の判断基準をドメインに寄せる」という意味です。このルールはドメインにあるべきか、それともUseCaseやUIにあってよいのか。その判断を常に意識することが重要です。\nドメインを見失った設計の末路 ドメインが曖昧なまま設計されたシステムでは、次のような現象が起こります。\n似たようなチェック処理があちこちに増える 仕様変更のたびに複数箇所を直す必要がある 「なぜこの条件があるのか」を誰も説明できない これは、コードの問題というより、「考え方の問題」です。\nDDDは、これらの問題を一気に解決する魔法ではありません。しかし、「どこにルールを書くべきか」という判断軸を与えてくれます。それだけでも、設計の寿命は大きく変わります。\n次章では、ドメインをコードとして表現するための最初の道具である「モデル」について掘り下げていきます。\n","permalink":"https://design.okuda-studio.com/books/004-ddd/02/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%A8%E3%81%AF%E6%A5%AD%E5%8B%99%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF%E3%81%AE%E3%81%93%E3%81%A8%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003eドメインとは「業務ロジック」のことではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E5%88%A4%E6%96%AD%E3%81%8C%E9%87%8D%E8%A6%81%E3%81%AA%E3%81%AE%E3%81%8B\"\u003eなぜ「判断」が重要なのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AF%E5%87%A6%E7%90%86%E3%81%AE%E6%B5%81%E3%82%8C%E3%82%92%E7%9F%A5%E3%82%89%E3%81%AA%E3%81%84\"\u003eドメインは「処理の流れ」を知らない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%A8usecase%E3%81%AE%E9%81%95%E3%81%84\"\u003eドメインとUseCaseの違い\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AF%E4%B8%AD%E5%BF%83%E3%81%AB%E7%BD%AE%E3%81%8B%E3%82%8C%E3%82%8B%E3%81%8C%E4%B8%87%E8%83%BD%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003eドメインは中心に置かれるが、万能ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92%E8%A6%8B%E5%A4%B1%E3%81%A3%E3%81%9F%E8%A8%AD%E8%A8%88%E3%81%AE%E6%9C%AB%E8%B7%AF\"\u003eドメインを見失った設計の末路\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"ドメインとは業務ロジックのことではない\"\u003eドメインとは「業務ロジック」のことではない\u003c/h2\u003e\n\u003cp\u003e「ドメインとは何ですか？」と聞かれたとき、多くの人は次のように答えます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e業務ロジックのこと\u003c/li\u003e\n\u003cli\u003eビジネスルールのこと\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは、完全に間違いではありません。しかし、この理解のまま設計を進めると、ほぼ確実にドメインは壊れていきます。\u003c/p\u003e\n\u003cp\u003eなぜなら、「業務ロジック」という言葉はあまりにも広く、そして曖昧だからです。画面遷移の条件も業務ロジックですし、APIを呼ぶタイミングも業務ロジックと言えてしまいます。その結果、「どこまでがドメインなのか」が誰にも説明できなくなります。\u003c/p\u003e\n\u003cp\u003e本書では、ドメインをもう少し狭く、そして厳密に扱います。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eドメインとは、そのシステムが守るべき判断とルールの集合\u003c/strong\u003eです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"なぜ判断が重要なのか\"\u003eなぜ「判断」が重要なのか\u003c/h2\u003e\n\u003cp\u003eシステムが存在する理由は、計算をすることでも、画面を表示することでもありません。多くの場合、システムは「判断」をするために存在しています。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこの注文は成立してよいか\u003c/li\u003e\n\u003cli\u003eこの支払いは受け付けてよいか\u003c/li\u003e\n\u003cli\u003eこの状態で次の操作に進んでよいか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらはすべて判断です。そして、この判断には必ずルールがあります。もしルールがなければ、判断はできません。\u003c/p\u003e\n\u003cp\u003eDDDが注目するのは、この「判断」と「ルール」がどこに書かれているのか、そしてそれが守られているのか、という点です。\u003c/p\u003e\n\u003cp\u003eもし判断のロジックが、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUseCaseのあちこちに散らばっていたり\u003c/li\u003e\n\u003cli\u003eUI層に紛れ込んでいたり\u003c/li\u003e\n\u003cli\u003e仕様書の文章にしか存在していなかったり\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eする場合、そのシステムは非常に壊れやすい状態にあります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"ドメインは処理の流れを知らない\"\u003eドメインは「処理の流れ」を知らない\u003c/h2\u003e\n\u003cp\u003eドメインを設計するとき、多くの人が最初につまずくポイントがあります。それは、「ドメインは何を知っていて、何を知らなくてよいのか」という問題です。\u003c/p\u003e\n\u003cp\u003e結論から言うと、ドメインは処理の流れを知る必要はありません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどの画面から呼ばれたのか\u003c/li\u003e\n\u003cli\u003eAPI経由なのか、バッチなのか\u003c/li\u003e\n\u003cli\u003e同期処理なのか、非同期処理なのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうした情報は、ドメインにとって本質的ではありません。ドメインが知るべきなのは、「この状態で、この操作は許されるか」という一点だけです。\u003c/p\u003e\n\u003cp\u003eこの切り分けができていないと、ドメインモデルはすぐに肥大化し、テストも困難になります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"ドメインとusecaseの違い\"\u003eドメインとUseCaseの違い\u003c/h2\u003e\n\u003cp\u003eDDDを学び始めると、ドメインとUseCaseの役割の違いが分からなくなることがあります。両方とも「業務の中心」を扱っているように見えるからです。\u003c/p\u003e\n\u003cp\u003eしかし、両者の責務は明確に異なります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eドメイン：判断とルールを守る\u003c/li\u003e\n\u003cli\u003eUseCase：処理の流れを組み立てる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eUseCaseは、「何を」「どの順番で」行うかを知っています。一方で、ドメインは「それをしてよいかどうか」だけを知っています。\u003c/p\u003e\n\u003cp\u003eもしUseCaseの中に大量のif文が現れ始めたら、それはドメインが本来持つべき判断をUseCaseが肩代わりしているサインです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"ドメインは中心に置かれるが万能ではない\"\u003eドメインは中心に置かれるが、万能ではない\u003c/h2\u003e\n\u003cp\u003eDDDでは、「ドメインを中心に置く」という表現がよく使われます。この言葉は非常に強く、誤解を招きやすい表現でもあります。\u003c/p\u003e\n\u003cp\u003eドメインを中心に置くとは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eすべての処理をドメインに書くこと\u003c/li\u003e\n\u003cli\u003eすべてのクラスをドメインから呼ぶこと\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eではありません。\u003c/p\u003e\n\u003cp\u003e中心に置くとは、「設計上の判断基準をドメインに寄せる」という意味です。このルールはドメインにあるべきか、それともUseCaseやUIにあってよいのか。その判断を常に意識することが重要です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"ドメインを見失った設計の末路\"\u003eドメインを見失った設計の末路\u003c/h2\u003e\n\u003cp\u003eドメインが曖昧なまま設計されたシステムでは、次のような現象が起こります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e似たようなチェック処理があちこちに増える\u003c/li\u003e\n\u003cli\u003e仕様変更のたびに複数箇所を直す必要がある\u003c/li\u003e\n\u003cli\u003e「なぜこの条件があるのか」を誰も説明できない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれは、コードの問題というより、「考え方の問題」です。\u003c/p\u003e\n\u003cp\u003eDDDは、これらの問題を一気に解決する魔法ではありません。しかし、「どこにルールを書くべきか」という判断軸を与えてくれます。それだけでも、設計の寿命は大きく変わります。\u003c/p\u003e\n\u003cp\u003e次章では、ドメインをコードとして表現するための最初の道具である「モデル」について掘り下げていきます。\u003c/p\u003e","title":"第2章：ドメインとは何か"},{"content":" 「ドメイン = ビジネスロジック」は半分間違い Android のドメインは「判断」と「ルール」 UI ロジックとの境界線 Data 層にドメインを置いてはいけない理由 ドメインは薄くていい、でも曖昧にしてはいけない この章のまとめ 「ドメイン = ビジネスロジック」は半分間違い 「ドメインとはビジネスロジックである」\nこの説明は、間違いではありません。しかし、Android アプリ開発の文脈ではそれだけでは足りない、というのが本書の立場です。\nAndroid アプリで頻繁に書かれているのは、次のようなコードです。\nどの状態のときに、どの UI を出すか どの条件を満たしたら操作を許可するか どの値を正とみなし、どの値を無効とみなすか これらは純粋なビジネスロジックとは言いづらい一方で、アプリとしての振る舞いを決定する重要な判断です。Android におけるドメインは、この「判断」を含んだ領域だと捉える方が、実態に近いと言えます。\nAndroid のドメインは「判断」と「ルール」 本書では、Android におけるドメインを、次のように定義します。\nアプリがどう振る舞うかを決める、判断とルールの集合\nそれは必ずしも、サーバー側のビジネスルールと一致する必要はありません。\n表示対象をどう選ぶか ユーザー操作をいつ無効にするか 状態遷移をどの順序で許可するか これらは UI ロジックとも密接に関わりますが、UI そのものではありません。View や Compose の中に散らばると、変更時に全体像が見えなくなります。\nUI ロジックとの境界線 「これは UI ロジックか、ドメインロジックか」という問いは、しばしば議論になります。しかし、白黒をはっきり分けようとすると、設計は硬直します。\n本書では、次の問いを境界判断の基準にします。\nこの判断は、画面が変わっても同じか このルールは、UI を捨てても意味が残るか どちらか一方でも「Yes」なら、そのロジックはドメイン側に寄せる価値があります。逆に、特定の UI 表現に強く依存しているなら、UI 側に残した方が自然です。\nData 層にドメインを置いてはいけない理由 Android プロジェクトでは、ドメインロジックが Data 層に入り込んでしまうケースが少なくありません。\nRepository 内で条件分岐が増える API レスポンスをその場で解釈し始める キャッシュ有無によって振る舞いが変わる これらは一見便利ですが、結果として「なぜそうなるのか」が見えなくなります。Data 層は、あくまで データを取得・保存する責務 に集中させるべきです。\n判断やルールを Data 層に置くと、テストもしづらく、UI 側からも追いにくい構造になります。\nドメインは薄くていい、でも曖昧にしてはいけない Android におけるドメインは、Web や業務系と比べると、どうしても薄くなりがちです。それ自体は、悪いことではありません。\n問題になるのは、ドメインが薄いことではなく、\nどこにあるのか分からない 何を担っているのか説明できない 状態になることです。\nたとえ数個の関数やクラスしかなくても、「ここがアプリの判断を集約している場所だ」と言えるなら、それは十分にドメインです。\nこの章のまとめ Android におけるドメインは、\n純粋なビジネスロジックだけではない UI とデータの間にある「判断とルール」を担う という位置づけになります。\n次章では、このドメインを どのように UseCase や ViewModel と接続するのか、そして多くのプロジェクトが陥る「UseCase 地獄」をどう回避するかを具体的に見ていきます。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/04/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003e「ドメイン = ビジネスロジック」は半分間違い\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eAndroid のドメインは「判断」と「ルール」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eUI ロジックとの境界線\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eData 層にドメインを置いてはいけない理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eドメインは薄くていい、でも曖昧にしてはいけない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"ドメイン--ビジネスロジックは半分間違い\"\u003e「ドメイン = ビジネスロジック」は半分間違い\u003c/h3\u003e\n\u003cp\u003e「ドメインとはビジネスロジックである」\u003c/p\u003e\n\u003cp\u003eこの説明は、間違いではありません。しかし、Android アプリ開発の文脈では\u003cstrong\u003eそれだけでは足りない\u003c/strong\u003e、というのが本書の立場です。\u003c/p\u003e\n\u003cp\u003eAndroid アプリで頻繁に書かれているのは、次のようなコードです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどの状態のときに、どの UI を出すか\u003c/li\u003e\n\u003cli\u003eどの条件を満たしたら操作を許可するか\u003c/li\u003e\n\u003cli\u003eどの値を正とみなし、どの値を無効とみなすか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは純粋なビジネスロジックとは言いづらい一方で、\u003cstrong\u003eアプリとしての振る舞いを決定する重要な判断\u003c/strong\u003eです。Android におけるドメインは、この「判断」を含んだ領域だと捉える方が、実態に近いと言えます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"android-のドメインは判断とルール\"\u003eAndroid のドメインは「判断」と「ルール」\u003c/h3\u003e\n\u003cp\u003e本書では、Android におけるドメインを、次のように定義します。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eアプリがどう振る舞うかを決める、判断とルールの集合\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eそれは必ずしも、サーバー側のビジネスルールと一致する必要はありません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e表示対象をどう選ぶか\u003c/li\u003e\n\u003cli\u003eユーザー操作をいつ無効にするか\u003c/li\u003e\n\u003cli\u003e状態遷移をどの順序で許可するか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは UI ロジックとも密接に関わりますが、UI そのものではありません。View や Compose の中に散らばると、変更時に全体像が見えなくなります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"ui-ロジックとの境界線\"\u003eUI ロジックとの境界線\u003c/h3\u003e\n\u003cp\u003e「これは UI ロジックか、ドメインロジックか」という問いは、しばしば議論になります。しかし、白黒をはっきり分けようとすると、設計は硬直します。\u003c/p\u003e\n\u003cp\u003e本書では、次の問いを境界判断の基準にします。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこの判断は、画面が変わっても同じか\u003c/li\u003e\n\u003cli\u003eこのルールは、UI を捨てても意味が残るか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eどちらか一方でも「Yes」なら、そのロジックはドメイン側に寄せる価値があります。逆に、特定の UI 表現に強く依存しているなら、UI 側に残した方が自然です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"data-層にドメインを置いてはいけない理由\"\u003eData 層にドメインを置いてはいけない理由\u003c/h3\u003e\n\u003cp\u003eAndroid プロジェクトでは、ドメインロジックが Data 層に入り込んでしまうケースが少なくありません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eRepository 内で条件分岐が増える\u003c/li\u003e\n\u003cli\u003eAPI レスポンスをその場で解釈し始める\u003c/li\u003e\n\u003cli\u003eキャッシュ有無によって振る舞いが変わる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは一見便利ですが、結果として「なぜそうなるのか」が見えなくなります。Data 層は、あくまで \u003cstrong\u003eデータを取得・保存する責務\u003c/strong\u003e に集中させるべきです。\u003c/p\u003e","title":"第3章：Android における「ドメイン」とは何か"},{"content":" モデルは「データ構造」ではない なぜロジックをモデルに寄せるのか 不変条件という考え方 モデルは「正しい使い方」しか提供しない EntityとValue Objectは結果として現れる モデルを薄くすると、設計は長持ちしない この章のまとめ モデルは「データ構造」ではない 「モデルとは何ですか？」と聞かれたとき、多くの人は次のように答えます。\nデータベースのテーブルに対応するクラス APIレスポンスを受け取るための構造体 画面に表示するためのデータ これらはすべて、モデルの“使われ方”ではありますが、モデルそのものの役割を表してはいません。\nDDDにおけるモデルは、データを運ぶ箱ではなく、判断とルールを守る主体です。もしモデルが値を保持するだけの存在になっているとしたら、その設計はすでにドメインから遠ざかっています。\nなぜロジックをモデルに寄せるのか 設計の現場では、次のような判断がよく行われます。\nロジックはUseCaseに書く モデルはシンプルなデータクラスにする テストしづらくなったら後で考える 一見すると合理的ですが、この判断を積み重ねると、UseCaseは次第に判断の塊になります。そして、同じような判断が別のUseCaseにも現れ始めます。\nモデルにロジックを寄せる理由は、コードをきれいにするためではありません。判断を一箇所に集め、必ず守らせるためです。\nモデルが自分自身の状態を知り、その状態に対して許される操作だけを提供する。この形を取ることで、「うっかりルールを破る」余地が大きく減ります。\n不変条件という考え方 モデルを理解するうえで、重要な概念に「不変条件（invariant）」があります。\n不変条件とは、そのモデルが存在し続ける限り、常に成り立っていなければならないルールのことです。\n金額は必ず0以上である 完了済みの注文は変更できない 無効な状態の組み合わせは存在しない これらは、UseCaseの都合や画面の事情によって変わってよいものではありません。だからこそ、モデル自身が責任を持って守る必要があります。\nもし不変条件がUseCaseやUIに散らばっていると、そのモデルは簡単に壊れます。\nモデルは「正しい使い方」しか提供しない 良いモデルは、誤った使い方ができないように設計されています。\n不正な値では生成できない 不正な状態遷移を表現できない ルールを無視した操作が存在しない これは、例外を投げるかどうか、という話ではありません。そもそも「できてはいけない操作」をAPIとして提供しない、という姿勢の話です。\nこの考え方を採用すると、UseCaseは驚くほどシンプルになります。なぜなら、「正しいかどうか」を心配する必要がなくなるからです。\nEntityとValue Objectは結果として現れる ここで初めて、DDDでよく知られている用語が登場します。\nEntityとValue Objectは、モデルを設計した“結果”として現れる分類です。最初から分類ありきで考えるものではありません。\nライフサイクルを持ち、状態が変化するもの 値として扱われ、置き換え可能なもの この違いは、IDの有無といった表面的な特徴よりも、「何を守る責務を持っているか」によって決まります。\n重要なのは、EntityかValue Objectかを正しく当てることではありません。そのモデルが、守るべき判断とルールを本当に守れているかどうかです。\nモデルを薄くすると、設計は長持ちしない 「モデルを薄く保つ」という設計方針が語られることがあります。しかし、その言葉が意味するものを誤解すると、設計は短命になります。\nモデルが薄いとは、責務が少ないことではありません。責務が曖昧であることです。\n判断を持たないモデルは、どこからでも好き勝手に扱えます。その自由さは、一時的には開発速度を上げますが、変更が始まった瞬間に足を引っ張ります。\nこの章のまとめ モデルは、データを表すための存在ではありません。モデルは、ドメインの判断とルールを守るための最後の砦です。\n次章では、複数のモデルをどのような単位でまとめ、どこまでを一つのルールとして扱うのか、という問題に進みます。そこで登場するのが「集約」という考え方です。\n","permalink":"https://design.okuda-studio.com/books/004-ddd/03/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AF%E3%83%87%E3%83%BC%E3%82%BF%E6%A7%8B%E9%80%A0%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003eモデルは「データ構造」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF%E3%82%92%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AB%E5%AF%84%E3%81%9B%E3%82%8B%E3%81%AE%E3%81%8B\"\u003eなぜロジックをモデルに寄せるのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6%E3%81%A8%E3%81%84%E3%81%86%E8%80%83%E3%81%88%E6%96%B9\"\u003e不変条件という考え方\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AF%E6%AD%A3%E3%81%97%E3%81%84%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%97%E3%81%8B%E6%8F%90%E4%BE%9B%E3%81%97%E3%81%AA%E3%81%84\"\u003eモデルは「正しい使い方」しか提供しない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#entity%E3%81%A8value-object%E3%81%AF%E7%B5%90%E6%9E%9C%E3%81%A8%E3%81%97%E3%81%A6%E7%8F%BE%E3%82%8C%E3%82%8B\"\u003eEntityとValue Objectは結果として現れる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A2%E3%83%87%E3%83%AB%E3%82%92%E8%96%84%E3%81%8F%E3%81%99%E3%82%8B%E3%81%A8%E8%A8%AD%E8%A8%88%E3%81%AF%E9%95%B7%E6%8C%81%E3%81%A1%E3%81%97%E3%81%AA%E3%81%84\"\u003eモデルを薄くすると、設計は長持ちしない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"モデルはデータ構造ではない\"\u003eモデルは「データ構造」ではない\u003c/h2\u003e\n\u003cp\u003e「モデルとは何ですか？」と聞かれたとき、多くの人は次のように答えます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eデータベースのテーブルに対応するクラス\u003c/li\u003e\n\u003cli\u003eAPIレスポンスを受け取るための構造体\u003c/li\u003e\n\u003cli\u003e画面に表示するためのデータ\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらはすべて、モデルの“使われ方”ではありますが、モデルそのものの役割を表してはいません。\u003c/p\u003e\n\u003cp\u003eDDDにおけるモデルは、\u003cstrong\u003eデータを運ぶ箱\u003c/strong\u003eではなく、\u003cstrong\u003e判断とルールを守る主体\u003c/strong\u003eです。もしモデルが値を保持するだけの存在になっているとしたら、その設計はすでにドメインから遠ざかっています。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"なぜロジックをモデルに寄せるのか\"\u003eなぜロジックをモデルに寄せるのか\u003c/h2\u003e\n\u003cp\u003e設計の現場では、次のような判断がよく行われます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eロジックはUseCaseに書く\u003c/li\u003e\n\u003cli\u003eモデルはシンプルなデータクラスにする\u003c/li\u003e\n\u003cli\u003eテストしづらくなったら後で考える\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e一見すると合理的ですが、この判断を積み重ねると、UseCaseは次第に判断の塊になります。そして、同じような判断が別のUseCaseにも現れ始めます。\u003c/p\u003e\n\u003cp\u003eモデルにロジックを寄せる理由は、コードをきれいにするためではありません。\u003cstrong\u003e判断を一箇所に集め、必ず守らせるため\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp\u003eモデルが自分自身の状態を知り、その状態に対して許される操作だけを提供する。この形を取ることで、「うっかりルールを破る」余地が大きく減ります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"不変条件という考え方\"\u003e不変条件という考え方\u003c/h2\u003e\n\u003cp\u003eモデルを理解するうえで、重要な概念に「不変条件（invariant）」があります。\u003c/p\u003e\n\u003cp\u003e不変条件とは、そのモデルが存在し続ける限り、\u003cstrong\u003e常に成り立っていなければならないルール\u003c/strong\u003eのことです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e金額は必ず0以上である\u003c/li\u003e\n\u003cli\u003e完了済みの注文は変更できない\u003c/li\u003e\n\u003cli\u003e無効な状態の組み合わせは存在しない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは、UseCaseの都合や画面の事情によって変わってよいものではありません。だからこそ、モデル自身が責任を持って守る必要があります。\u003c/p\u003e\n\u003cp\u003eもし不変条件がUseCaseやUIに散らばっていると、そのモデルは簡単に壊れます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"モデルは正しい使い方しか提供しない\"\u003eモデルは「正しい使い方」しか提供しない\u003c/h2\u003e\n\u003cp\u003e良いモデルは、誤った使い方ができないように設計されています。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e不正な値では生成できない\u003c/li\u003e\n\u003cli\u003e不正な状態遷移を表現できない\u003c/li\u003e\n\u003cli\u003eルールを無視した操作が存在しない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれは、例外を投げるかどうか、という話ではありません。そもそも「できてはいけない操作」をAPIとして提供しない、という姿勢の話です。\u003c/p\u003e\n\u003cp\u003eこの考え方を採用すると、UseCaseは驚くほどシンプルになります。なぜなら、「正しいかどうか」を心配する必要がなくなるからです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"entityとvalue-objectは結果として現れる\"\u003eEntityとValue Objectは結果として現れる\u003c/h2\u003e\n\u003cp\u003eここで初めて、DDDでよく知られている用語が登場します。\u003c/p\u003e\n\u003cp\u003eEntityとValue Objectは、モデルを設計した“結果”として現れる分類です。最初から分類ありきで考えるものではありません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eライフサイクルを持ち、状態が変化するもの\u003c/li\u003e\n\u003cli\u003e値として扱われ、置き換え可能なもの\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの違いは、IDの有無といった表面的な特徴よりも、「何を守る責務を持っているか」によって決まります。\u003c/p\u003e\n\u003cp\u003e重要なのは、EntityかValue Objectかを正しく当てることではありません。そのモデルが、守るべき判断とルールを本当に守れているかどうかです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"モデルを薄くすると設計は長持ちしない\"\u003eモデルを薄くすると、設計は長持ちしない\u003c/h2\u003e\n\u003cp\u003e「モデルを薄く保つ」という設計方針が語られることがあります。しかし、その言葉が意味するものを誤解すると、設計は短命になります。\u003c/p\u003e\n\u003cp\u003eモデルが薄いとは、責務が少ないことではありません。\u003cstrong\u003e責務が曖昧であること\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp\u003e判断を持たないモデルは、どこからでも好き勝手に扱えます。その自由さは、一時的には開発速度を上げますが、変更が始まった瞬間に足を引っ張ります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"この章のまとめ\"\u003eこの章のまとめ\u003c/h2\u003e\n\u003cp\u003eモデルは、データを表すための存在ではありません。モデルは、ドメインの判断とルールを守るための最後の砦です。\u003c/p\u003e\n\u003cp\u003e次章では、複数のモデルをどのような単位でまとめ、どこまでを一つのルールとして扱うのか、という問題に進みます。そこで登場するのが「集約」という考え方です。\u003c/p\u003e","title":"第3章：モデルとは何を表現するものか"},{"content":" ざっくり一言で もう少し噛み砕くと ドメインとは何か モデルとは何か よくある誤解ポイント Evans 本の有名な一文 モデルに種類があるのはなぜか まとめ ざっくり一言で ドメイン (Domain) → 解こうとしている「問題そのもの・業務の世界」\nモデル (Model) → そのドメインを理解・表現するために人間が作った「写像（抽象化）」\nもう少し噛み砕くと ドメインとは何か ドメインは コードでではありません 。\n業務ルール 制約 用語 価値判断 現実世界で「そうなっている理由」 たとえば口座振替アプリなら：\n「引き落とし元口座は必ず1つ存在する」 「同じ支払先に対して複数の引き落とし元は持てない」 「金額は0円以上でなければならない」 これ全部 ドメイン。まだコードの話は何も出てきてません。\nモデルとは何か モデルは、そのドメインを扱うために作る表現です。\nEntity Value Object Aggregate ドメインサービス それらの関係性 例：\ndata class DirectDebit( val sourceAccountId: AccountId, val destination: Destination, val amount: Money ) これは「口座振替」という現実の概念を、プログラムで扱える形に落としたもの。\nこれが ドメインモデル。\nよくある誤解ポイント 「ドメイン = ドメインモデル」\nこれは 半分正しくて半分間違い。\nドメイン → 現実世界・業務世界そのもの ドメインモデル → それを 近似 したもの モデルはあくまで「モデル」なので：\n省略しているものがある 嘘（近似）が含まれる ユースケースや文脈ごとに違う形になり得る Evans 本の有名な一文 The model is not the domain.\nモデルはドメインそのものではない。 ドメインを理解するための道具にすぎない。\nこれを忘れると\n「このクラス設計がドメインだ」 「コードが現実を支配し始める」 設計変更＝世界観の崩壊、になる モデルに種類があるのはなぜか ドメインは 画面遷移やUIとは無関係 モデルは 永続化や通信形式とも本来は無関係 UI都合でモデルを歪めると → ドメイン理解が壊れる だから、\nDB Entity API DTO Domain Model を分ける意味が出てきます。\n全部「モデル」だけど、見ているドメインの切り取り方が違う\nまとめ ドメイン → 「この世界では何が正しいか」 モデル → 「それを扱うための表現」 ドメインモデル → ドメイン理解をコードに落とした近似図 そして一番大事なのは：\nモデルは育て直せる。でもドメインを見失ったら終わり\n","permalink":"https://design.okuda-studio.com/books/004-ddd/03-1-domain-vs-model/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%96%E3%81%A3%E3%81%8F%E3%82%8A%E4%B8%80%E8%A8%80%E3%81%A7\"\u003eざっくり一言で\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%82%E3%81%86%E5%B0%91%E3%81%97%E5%99%9B%E3%81%BF%E7%A0%95%E3%81%8F%E3%81%A8\"\u003eもう少し噛み砕くと\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B\"\u003eドメインとは何か\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A2%E3%83%87%E3%83%AB%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B\"\u003eモデルとは何か\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%88%E3%81%8F%E3%81%82%E3%82%8B%E8%AA%A4%E8%A7%A3%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88\"\u003eよくある誤解ポイント\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#evans-%E6%9C%AC%E3%81%AE%E6%9C%89%E5%90%8D%E3%81%AA%E4%B8%80%E6%96%87\"\u003eEvans 本の有名な一文\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AB%E7%A8%AE%E9%A1%9E%E3%81%8C%E3%81%82%E3%82%8B%E3%81%AE%E3%81%AF%E3%81%AA%E3%81%9C%E3%81%8B\"\u003eモデルに種類があるのはなぜか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"ざっくり一言で\"\u003eざっくり一言で\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eドメイン (Domain)\u003c/strong\u003e\n→ \u003cem\u003e解こうとしている「問題そのもの・業務の世界」\u003c/em\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eモデル (Model)\u003c/strong\u003e\n→ \u003cem\u003eそのドメインを理解・表現するために人間が作った「写像（抽象化）」\u003c/em\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"もう少し噛み砕くと\"\u003eもう少し噛み砕くと\u003c/h2\u003e\n\u003ch3 id=\"ドメインとは何か\"\u003eドメインとは何か\u003c/h3\u003e\n\u003cp\u003eドメインは \u003cstrong\u003eコードでではありません\u003c/strong\u003e 。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e業務ルール\u003c/li\u003e\n\u003cli\u003e制約\u003c/li\u003e\n\u003cli\u003e用語\u003c/li\u003e\n\u003cli\u003e価値判断\u003c/li\u003e\n\u003cli\u003e現実世界で「そうなっている理由」\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eたとえば口座振替アプリなら：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e「引き落とし元口座は必ず1つ存在する」\u003c/li\u003e\n\u003cli\u003e「同じ支払先に対して複数の引き落とし元は持てない」\u003c/li\u003e\n\u003cli\u003e「金額は0円以上でなければならない」\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれ全部 \u003cstrong\u003eドメイン\u003c/strong\u003e。まだコードの話は何も出てきてません。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"モデルとは何か\"\u003eモデルとは何か\u003c/h3\u003e\n\u003cp\u003eモデルは、\u003cstrong\u003eそのドメインを扱うために作る表現\u003c/strong\u003eです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEntity\u003c/li\u003e\n\u003cli\u003eValue Object\u003c/li\u003e\n\u003cli\u003eAggregate\u003c/li\u003e\n\u003cli\u003eドメインサービス\u003c/li\u003e\n\u003cli\u003eそれらの関係性\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e例：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edata\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eDirectDebit\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e sourceAccountId: AccountId,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e destination: Destination,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e amount: Money\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eこれは「口座振替」という\u003cstrong\u003e現実の概念を、プログラムで扱える形に落としたもの\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003eこれが \u003cstrong\u003eドメインモデル\u003c/strong\u003e。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"よくある誤解ポイント\"\u003eよくある誤解ポイント\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e「ドメイン = ドメインモデル」\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eこれは \u003cstrong\u003e半分正しくて半分間違い\u003c/strong\u003e。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eドメイン\n→ 現実世界・業務世界そのもの\u003c/li\u003e\n\u003cli\u003eドメインモデル\n→ それを \u003cem\u003e近似\u003c/em\u003e したもの\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eモデルはあくまで「モデル」なので：\u003c/p\u003e","title":"参考：ドメインとモデルの違い"},{"content":" なぜ UseCase が肥大化するのか UseCase は「必須レイヤー」ではない Flow を返す UseCase と suspend UseCase の境界 Command と Query を分けるという現実解 UseCase を作らないという選択肢 非同期を UseCase に閉じ込めすぎない この章のまとめ なぜ UseCase が肥大化するのか UseCase は、本来「アプリケーションとしての振る舞い」を表現するための概念です。しかし Android 開発の現場では、次のような理由で簡単に肥大化します。\n画面単位で UseCase を作り始める Repository を直接触らせないための中継層になる 非同期処理（Flow / suspend）の置き場として使われる その結果、UseCase は「何をしているのか分からないが、とりあえずここを通す場所」になりがちです。これは設計ミスというより、役割が曖昧なまま使われ続けた結果 です。\nUseCase は「必須レイヤー」ではない 多くのアーキテクチャ解説では、UseCase（あるいは Interactor）は必須レイヤーとして描かれます。しかし、本書の立場は明確です。\nUseCase は、必要になったときにだけ導入する道具である。\nUseCase が価値を持つのは、次のような場合です。\n複数の UI から同じ振る舞いを呼び出す 一連の操作を「1つの意味ある処理」としてまとめたい ドメインの判断を UI から切り離したい 逆に言えば、単に Repository を呼ぶだけの処理や、画面専用の薄い処理に UseCase を挟む必然性はありません。\nFlow を返す UseCase と suspend UseCase の境界 Android では、UseCase が Flow を返すのか、suspend 関数なのかで悩む場面が頻発します。この問題の本質は、非同期 API の選択ではありません。\n判断基準は、\nその処理は「状態を監視するもの」か それとも「1回の命令」か という点にあります。\n状態を継続的に監視する → Flow 1回きりの処理を命令する → suspend これを曖昧にすると、UseCase の責務がぼやけ、ViewModel 側も扱いづらくなります。\nCommand と Query を分けるという現実解 UseCase 地獄を抜けるための、非常に実践的な解決策が Command / Query の分離 です。\nQuery：状態やデータを取得する Command：状態を変化させる命令 これを分けるだけで、次のような効果があります。\nFlow を返すのは Query だけになる Command は suspend 関数として明確になる 名前と責務が一致しやすくなる すべてを UseCase に押し込めるのではなく、「役割ごとに分ける」ことで、構造は驚くほどシンプルになります。\nUseCase を作らないという選択肢 本書では、あえてこの選択肢も提示します。\nUseCase を作らなくてもよいケースは、確実に存在する。\nたとえば、\n画面専用の処理である ViewModel から直接呼んでも責務が明確 将来的に再利用される見込みがない このような場合、無理に UseCase を挟むよりも、ViewModel と Repository の間で完結させた方が、構造が分かりやすくなることもあります。\n重要なのは、「UseCase があるかどうか」ではなく、判断がどこに集約されているか です。\n非同期を UseCase に閉じ込めすぎない Android 開発では、UseCase を導入するときに 「UseCase は suspend 関数にするもの」 「非同期処理はすべて UseCase に隠すもの」 という設計になりがちです。\nしかし、非同期処理をすべて UseCase に押し込めると、設計は次第に歪んでいきます。\nまず起きやすいのが、ViewModel が極端に薄くなる という問題です。\nUseCase を呼ぶ 結果をそのまま UI に流す だけの存在になり、 「画面としてどういう状態を持つか」という判断が、どこにも存在しなくなります。\n次に問題になるのが、エラーやローディングの責務の所在が曖昧になることです。\n非同期をすべて UseCase に閉じ込めると、\nローディング状態は UseCase が持つのか エラーを UI 向けの形に変換するのは誰なのか 再試行やキャンセルはどこで扱うのか といった判断が、UseCase と ViewModel の間を漂い始めます。\n結果として、\nResult や sealed class が UseCase から返ってくる UI の都合が UseCase の戻り値に混ざる 「これはドメインの話？UI の話？」という迷いが生まれる という状態になります。\nもう一つ、見えにくいですが深刻なのが、 UI 状態とドメイン判断の境界が曖昧になることです。\n非同期というのは、\nいつ開始するか いつ終わるか 途中経過をどう扱うか といった、アプリ全体の都合に強く結びついた関心事です。\n一方で、ドメインが関心を持つのは、\n何が有効か どう分類されるか どんなルールで扱われるか といった 意味や判断 です。\nこの二つは、変更理由がまったく異なります。\n非同期を無理に UseCase に押し込めると、 この異なる変更理由が 1 つの関数の中に混ざり込み、 「なぜこのロジックがここにあるのか」を説明できなくなります。\n本書で言いたいのは、 非同期を UseCase から排除すべき、ということではありません。\n重要なのは、\nこれはドメインの判断か それとも UI 状態を組み立てるための非同期制御か を、意識的に分けることです。\nドメインの判断そのものは UseCase に置く ローディングやエラー、画面状態の組み立ては ViewModel が担う この役割分担が見えていれば、\nUseCase が増えすぎない ViewModel が責務を持った存在になる 「UseCase 地獄」に陥りにくくなる という状態に近づきます。\n非同期は強力ですが、同時に設計を曖昧にしやすい要素でもあります。 だからこそ、「とりあえず UseCase に入れる」 という判断を避け、 その非同期が 誰の都合なのか を、一度立ち止まって考える必要があります。\nこの章のまとめ UseCase は、\n作ること自体が目的ではない 責務を明確にするための選択肢の1つ に過ぎません。\nCommand / Query の分離や、UseCase を作らない判断も含めて、「なぜこの形を選んだのか」を説明できることが、設計としての完成度を高めます。\n次章では、エンティティやモデルを Android 文脈でどう設計するかを掘り下げていきます。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/05/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003eなぜ UseCase が肥大化するのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eUseCase は「必須レイヤー」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eFlow を返す UseCase と suspend UseCase の境界\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eCommand と Query を分けるという現実解\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eUseCase を作らないという選択肢\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003e非同期を UseCase に閉じ込めすぎない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"なぜ-usecase-が肥大化するのか\"\u003eなぜ UseCase が肥大化するのか\u003c/h3\u003e\n\u003cp\u003eUseCase は、本来「アプリケーションとしての振る舞い」を表現するための概念です。しかし Android 開発の現場では、次のような理由で簡単に肥大化します。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e画面単位で UseCase を作り始める\u003c/li\u003e\n\u003cli\u003eRepository を直接触らせないための中継層になる\u003c/li\u003e\n\u003cli\u003e非同期処理（Flow / suspend）の置き場として使われる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eその結果、UseCase は「何をしているのか分からないが、とりあえずここを通す場所」になりがちです。これは設計ミスというより、\u003cstrong\u003e役割が曖昧なまま使われ続けた結果\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"usecase-は必須レイヤーではない\"\u003eUseCase は「必須レイヤー」ではない\u003c/h3\u003e\n\u003cp\u003e多くのアーキテクチャ解説では、UseCase（あるいは Interactor）は必須レイヤーとして描かれます。しかし、本書の立場は明確です。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eUseCase は、必要になったときにだけ導入する道具である。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eUseCase が価値を持つのは、次のような場合です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e複数の UI から同じ振る舞いを呼び出す\u003c/li\u003e\n\u003cli\u003e一連の操作を「1つの意味ある処理」としてまとめたい\u003c/li\u003e\n\u003cli\u003eドメインの判断を UI から切り離したい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e逆に言えば、単に Repository を呼ぶだけの処理や、画面専用の薄い処理に UseCase を挟む必然性はありません。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"flow-を返す-usecase-と-suspend-usecase-の境界\"\u003eFlow を返す UseCase と suspend UseCase の境界\u003c/h3\u003e\n\u003cp\u003eAndroid では、UseCase が Flow を返すのか、suspend 関数なのかで悩む場面が頻発します。この問題の本質は、非同期 API の選択ではありません。\u003c/p\u003e","title":"第4章：UseCase 地獄からの脱出"},{"content":" 集約は「クラスの集まり」ではない なぜモデルを「まとめる」必要があるのか 不変条件は「同時性」の問題でもある 集約ルートが持つ責務 集約が大きくなりすぎる理由 集約を分けるという判断 集約は設計を難しくするための概念ではない この章のまとめ 集約は「クラスの集まり」ではない 集約（Aggregate）という言葉を聞いたとき、多くの人は次のようなイメージを持ちます。\nEntityとValue Objectを束ねたもの 1対多の関連をまとめた構造 ルートEntityを持つオブジェクトグラフ これらはすべて、集約の“形”を説明してはいますが、集約の本質を説明してはいません。\n集約は、構造の話ではありません。集約とは、判断とルールを守るための単位です。どの範囲までを一つの判断として扱い、どこから先は別の判断として切り離すのか。その線引きこそが、集約を設計するという行為です。\nなぜモデルを「まとめる」必要があるのか 第3章では、モデルが判断とルールを守る主体であることを説明しました。しかし、実際のシステムでは、判断は一つのモデルだけで完結しないことがほとんどです。\n注文は、顧客と商品と支払いに関係する 予約は、日時と空き状況と制約条件に依存する これらをすべて単一のモデルに押し込めると、モデルはすぐに破綻します。逆に、完全に分離してしまうと、「同時に守るべきルール」を保証できなくなります。\n集約は、このジレンマに対する答えです。同時に守るべき不変条件を、一つの境界に閉じ込める。それが集約の役割です。\n不変条件は「同時性」の問題でもある 集約を理解するうえで、重要なのは「同時性」という視点です。\nこの操作とあの操作は、同時に行われてよいのか 状態が途中で食い違っても許されるのか 一貫性はどこまで保証されるべきか これらは、ビジネスルールであると同時に、トランザクションの問題でもあります。\n集約の境界とは、強い一貫性を保証する範囲です。この範囲の中では、不変条件が必ず守られなければなりません。一方で、境界の外側とは、最終的に整合すればよい、という設計も選択できます。\n集約ルートが持つ責務 集約には、必ず外部との窓口となる存在があります。それが集約ルートです。\n集約ルートの責務は単純です。\n集約内部の不変条件を守る 外部からの操作を一元的に受け付ける 重要なのは、「内部のオブジェクトを直接操作させない」ことです。もし外部から内部のEntityやValue Objectを自由に変更できると、不変条件は簡単に破られてしまいます。\n集約ルートは、門番のような存在です。正しい手続きを踏んだ操作だけを通し、それ以外はそもそも表現できないようにします。\n集約が大きくなりすぎる理由 集約設計でよくある失敗は、「安全そうだから」という理由で、あらゆるものを一つの集約に詰め込んでしまうことです。\n確かに、大きな集約は不変条件を守りやすく見えます。しかし、その代償として次の問題が発生します。\n更新のたびに多くのデータを読み込む必要がある ロック範囲が広がり、並行性が下がる 変更の影響範囲が大きくなる 集約を小さくするとは、責任を放棄することではありません。どの一貫性を本当に守る必要があるのかを見極めることです。\n集約を分けるという判断 集約を分けるときは、次のような判断基準で考えます。\n同時に変更される必要があるか 不整合が一瞬でも許されないか 一つの操作として扱うべきか これらの問いに「はい」と答えられる範囲が、一つの集約になります。\nそれ以外の関係は、IDによる参照やイベントによる連携で十分な場合がほとんどです。\n集約は設計を難しくするための概念ではない 集約は、DDDの中でも特に難解だと感じられがちな概念です。しかし、その理由の多くは、「正解を探そうとする」姿勢にあります。\n集約に唯一の正解はありません。重要なのは、その集約が\nどの不変条件を守っているのか なぜその境界なのか を説明できることです。\nこの章のまとめ 集約とは、モデルをまとめるための構造ではありません。集約とは、同時に守るべき判断とルールの単位です。\n次章では、この集約をどのように取得し、保存し、システムの外側とつなぐのか。そのための仕組みである「Repository」について掘り下げていきます。\n","permalink":"https://design.okuda-studio.com/books/004-ddd/04/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E9%9B%86%E7%B4%84%E3%81%AF%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E9%9B%86%E3%81%BE%E3%82%8A%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e集約は「クラスの集まり」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E3%83%A2%E3%83%87%E3%83%AB%E3%82%92%E3%81%BE%E3%81%A8%E3%82%81%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8B%E3%81%AE%E3%81%8B\"\u003eなぜモデルを「まとめる」必要があるのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6%E3%81%AF%E5%90%8C%E6%99%82%E6%80%A7%E3%81%AE%E5%95%8F%E9%A1%8C%E3%81%A7%E3%82%82%E3%81%82%E3%82%8B\"\u003e不変条件は「同時性」の問題でもある\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%9B%86%E7%B4%84%E3%83%AB%E3%83%BC%E3%83%88%E3%81%8C%E6%8C%81%E3%81%A4%E8%B2%AC%E5%8B%99\"\u003e集約ルートが持つ責務\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%9B%86%E7%B4%84%E3%81%8C%E5%A4%A7%E3%81%8D%E3%81%8F%E3%81%AA%E3%82%8A%E3%81%99%E3%81%8E%E3%82%8B%E7%90%86%E7%94%B1\"\u003e集約が大きくなりすぎる理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%9B%86%E7%B4%84%E3%82%92%E5%88%86%E3%81%91%E3%82%8B%E3%81%A8%E3%81%84%E3%81%86%E5%88%A4%E6%96%AD\"\u003e集約を分けるという判断\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%9B%86%E7%B4%84%E3%81%AF%E8%A8%AD%E8%A8%88%E3%82%92%E9%9B%A3%E3%81%97%E3%81%8F%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E6%A6%82%E5%BF%B5%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e集約は設計を難しくするための概念ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"集約はクラスの集まりではない\"\u003e集約は「クラスの集まり」ではない\u003c/h2\u003e\n\u003cp\u003e集約（Aggregate）という言葉を聞いたとき、多くの人は次のようなイメージを持ちます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEntityとValue Objectを束ねたもの\u003c/li\u003e\n\u003cli\u003e1対多の関連をまとめた構造\u003c/li\u003e\n\u003cli\u003eルートEntityを持つオブジェクトグラフ\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらはすべて、集約の“形”を説明してはいますが、集約の本質を説明してはいません。\u003c/p\u003e\n\u003cp\u003e集約は、構造の話ではありません。\u003cstrong\u003e集約とは、判断とルールを守るための単位\u003c/strong\u003eです。どの範囲までを一つの判断として扱い、どこから先は別の判断として切り離すのか。その線引きこそが、集約を設計するという行為です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"なぜモデルをまとめる必要があるのか\"\u003eなぜモデルを「まとめる」必要があるのか\u003c/h2\u003e\n\u003cp\u003e第3章では、モデルが判断とルールを守る主体であることを説明しました。しかし、実際のシステムでは、判断は一つのモデルだけで完結しないことがほとんどです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e注文は、顧客と商品と支払いに関係する\u003c/li\u003e\n\u003cli\u003e予約は、日時と空き状況と制約条件に依存する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらをすべて単一のモデルに押し込めると、モデルはすぐに破綻します。逆に、完全に分離してしまうと、「同時に守るべきルール」を保証できなくなります。\u003c/p\u003e\n\u003cp\u003e集約は、このジレンマに対する答えです。\u003cstrong\u003e同時に守るべき不変条件を、一つの境界に閉じ込める\u003c/strong\u003e。それが集約の役割です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"不変条件は同時性の問題でもある\"\u003e不変条件は「同時性」の問題でもある\u003c/h2\u003e\n\u003cp\u003e集約を理解するうえで、重要なのは「同時性」という視点です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこの操作とあの操作は、同時に行われてよいのか\u003c/li\u003e\n\u003cli\u003e状態が途中で食い違っても許されるのか\u003c/li\u003e\n\u003cli\u003e一貫性はどこまで保証されるべきか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは、ビジネスルールであると同時に、トランザクションの問題でもあります。\u003c/p\u003e\n\u003cp\u003e集約の境界とは、\u003cstrong\u003e強い一貫性を保証する範囲\u003c/strong\u003eです。この範囲の中では、不変条件が必ず守られなければなりません。一方で、境界の外側とは、最終的に整合すればよい、という設計も選択できます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"集約ルートが持つ責務\"\u003e集約ルートが持つ責務\u003c/h2\u003e\n\u003cp\u003e集約には、必ず外部との窓口となる存在があります。それが集約ルートです。\u003c/p\u003e\n\u003cp\u003e集約ルートの責務は単純です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e集約内部の不変条件を守る\u003c/li\u003e\n\u003cli\u003e外部からの操作を一元的に受け付ける\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e重要なのは、「内部のオブジェクトを直接操作させない」ことです。もし外部から内部のEntityやValue Objectを自由に変更できると、不変条件は簡単に破られてしまいます。\u003c/p\u003e\n\u003cp\u003e集約ルートは、門番のような存在です。正しい手続きを踏んだ操作だけを通し、それ以外はそもそも表現できないようにします。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"集約が大きくなりすぎる理由\"\u003e集約が大きくなりすぎる理由\u003c/h2\u003e\n\u003cp\u003e集約設計でよくある失敗は、「安全そうだから」という理由で、あらゆるものを一つの集約に詰め込んでしまうことです。\u003c/p\u003e\n\u003cp\u003e確かに、大きな集約は不変条件を守りやすく見えます。しかし、その代償として次の問題が発生します。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e更新のたびに多くのデータを読み込む必要がある\u003c/li\u003e\n\u003cli\u003eロック範囲が広がり、並行性が下がる\u003c/li\u003e\n\u003cli\u003e変更の影響範囲が大きくなる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e集約を小さくするとは、責任を放棄することではありません。\u003cstrong\u003eどの一貫性を本当に守る必要があるのかを見極めること\u003c/strong\u003eです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"集約を分けるという判断\"\u003e集約を分けるという判断\u003c/h2\u003e\n\u003cp\u003e集約を分けるときは、次のような判断基準で考えます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e同時に変更される必要があるか\u003c/li\u003e\n\u003cli\u003e不整合が一瞬でも許されないか\u003c/li\u003e\n\u003cli\u003e一つの操作として扱うべきか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらの問いに「はい」と答えられる範囲が、一つの集約になります。\u003c/p\u003e\n\u003cp\u003eそれ以外の関係は、IDによる参照やイベントによる連携で十分な場合がほとんどです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"集約は設計を難しくするための概念ではない\"\u003e集約は設計を難しくするための概念ではない\u003c/h2\u003e\n\u003cp\u003e集約は、DDDの中でも特に難解だと感じられがちな概念です。しかし、その理由の多くは、「正解を探そうとする」姿勢にあります。\u003c/p\u003e\n\u003cp\u003e集約に唯一の正解はありません。重要なのは、その集約が\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどの不変条件を守っているのか\u003c/li\u003e\n\u003cli\u003eなぜその境界なのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを説明できることです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"この章のまとめ\"\u003eこの章のまとめ\u003c/h2\u003e\n\u003cp\u003e集約とは、モデルをまとめるための構造ではありません。集約とは、\u003cstrong\u003e同時に守るべき判断とルールの単位\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp\u003e次章では、この集約をどのように取得し、保存し、システムの外側とつなぐのか。そのための仕組みである「Repository」について掘り下げていきます。\u003c/p\u003e","title":"第4章：集約とは何を守る単位なのか"},{"content":" Repositoryは「永続化層」ではない Repositoryが扱うのは「集約」である なぜRepositoryを介さずに触ってはいけないのか interfaceを切ることが目的ではない 良いRepositoryは「問い」を持っている RepositoryとUseCaseの健全な距離 Repositoryを薄くしすぎない この章のまとめ Repositoryは「永続化層」ではない Repositoryと聞いて、多くの人がまず思い浮かべるのは次のような役割です。\nデータベースへのアクセスを隠蔽する CRUD処理をまとめる ORMやSQLの詳細を隔離する これらはRepositoryの“効果”ではありますが、Repositoryそのものの本質ではありません。\nRepositoryは、永続化のための仕組みではなく、集約を扱うための抽象です。もしRepositoryを「DB操作クラス」として設計してしまうと、DDDの重要な意図はほぼ失われます。\nRepositoryが扱うのは「集約」である 前章で述べた通り、集約は「同時に守るべき判断とルールの単位」でした。\nRepositoryは、その集約を\n取得する 保存する ための唯一の窓口です。\n重要なのは、Repositoryが\nEntity単体 テーブル単位のレコード を扱う存在ではない、という点です。Repositoryが扱うのは、常に意味を持った集約全体です。\nこの制約があるからこそ、集約の不変条件は安全に保たれます。\nなぜRepositoryを介さずに触ってはいけないのか もし集約の内部オブジェクトを、Repositoryを介さずに直接取得・更新できてしまうと、次のような問題が起こります。\n不変条件を守らずに状態を書き換えられる 集約の境界が形骸化する 「正しい操作」が分からなくなる これは、設計が破綻する典型的なパターンです。\nRepositoryは、「この集約は、こういう単位でしか扱えない」というルールをシステム全体に強制する役割を持っています。\ninterfaceを切ることが目的ではない Repositoryはしばしばinterfaceとして定義されます。そのため、「Repository = interface」という理解が広まりがちです。\nしかし、interfaceを切ること自体は目的ではありません。\nRepositoryを抽象として定義する理由は、\n集約の概念をインフラから切り離すため モデルの言葉で取得・保存を表現するため です。\nもしinterfaceを切ったにもかかわらず、\nfindById save delete といった汎用的なCRUDメソッドしか存在しないのであれば、そのRepositoryはドメインの言葉をほとんど語っていません。\n良いRepositoryは「問い」を持っている 良いRepositoryは、ドメインの問いをそのままメソッドとして表現します。\n有効な注文を取得する 処理待ちの支払いを探す 特定の条件を満たす集約を取得する これらは、SQLやクエリの話ではありません。ドメインが何を知りたいかという問いです。\nこの形でRepositoryを設計すると、UseCaseのコードは自然言語に近づいていきます。\nRepositoryとUseCaseの健全な距離 UseCaseは、Repositoryを使って集約を取得し、操作し、結果を保存します。\nここで重要なのは、UseCaseが\n集約の内部構造を知らない 永続化の詳細を知らない という状態を保つことです。\nUseCaseが知っているのは、\nどの集約を使うか どの操作を呼ぶか 結果を保存する必要があるか だけで十分です。\nこの距離感が保たれていると、UseCaseは「流れ」に集中でき、判断はモデルと集約に委ねられます。\nRepositoryを薄くしすぎない 「Repositoryは薄く保つべきだ」という言葉も、誤解されやすい表現です。\nRepositoryが薄いとは、ロジックを持たないことではありません。 ドメインの「判断」を持たないことです。\nRepositoryは、ドメインモデルを永続化の世界に橋渡しする責務だけを持ちます。\nキャッシュ戦略 データソースの切り替え 永続化の最適化 これらはRepositoryの内部にあって構いません。重要なのは、それらがUseCaseやモデルに漏れ出さないことです。\nこの章のまとめ Repositoryは、永続化のための仕組みではありません。Repositoryは、集約を集約として扱うための境界です。\n次章では、Repositoryを使って処理の流れを組み立てる存在である「UseCase」について掘り下げていきます。そこで、DDDとアプリケーション層の関係が、より明確になります。\n","permalink":"https://design.okuda-studio.com/books/004-ddd/05/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#repository%E3%81%AF%E6%B0%B8%E7%B6%9A%E5%8C%96%E5%B1%A4%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003eRepositoryは「永続化層」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#repository%E3%81%8C%E6%89%B1%E3%81%86%E3%81%AE%E3%81%AF%E9%9B%86%E7%B4%84%E3%81%A7%E3%81%82%E3%82%8B\"\u003eRepositoryが扱うのは「集約」である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9Crepository%E3%82%92%E4%BB%8B%E3%81%95%E3%81%9A%E3%81%AB%E8%A7%A6%E3%81%A3%E3%81%A6%E3%81%AF%E3%81%84%E3%81%91%E3%81%AA%E3%81%84%E3%81%AE%E3%81%8B\"\u003eなぜRepositoryを介さずに触ってはいけないのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#interface%E3%82%92%E5%88%87%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E7%9B%AE%E7%9A%84%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003einterfaceを切ることが目的ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%89%AF%E3%81%84repository%E3%81%AF%E5%95%8F%E3%81%84%E3%82%92%E6%8C%81%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B\"\u003e良いRepositoryは「問い」を持っている\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#repository%E3%81%A8usecase%E3%81%AE%E5%81%A5%E5%85%A8%E3%81%AA%E8%B7%9D%E9%9B%A2\"\u003eRepositoryとUseCaseの健全な距離\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#repository%E3%82%92%E8%96%84%E3%81%8F%E3%81%97%E3%81%99%E3%81%8E%E3%81%AA%E3%81%84\"\u003eRepositoryを薄くしすぎない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"repositoryは永続化層ではない\"\u003eRepositoryは「永続化層」ではない\u003c/h2\u003e\n\u003cp\u003eRepositoryと聞いて、多くの人がまず思い浮かべるのは次のような役割です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eデータベースへのアクセスを隠蔽する\u003c/li\u003e\n\u003cli\u003eCRUD処理をまとめる\u003c/li\u003e\n\u003cli\u003eORMやSQLの詳細を隔離する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらはRepositoryの“効果”ではありますが、Repositoryそのものの本質ではありません。\u003c/p\u003e\n\u003cp\u003eRepositoryは、永続化のための仕組みではなく、\u003cstrong\u003e集約を扱うための抽象\u003c/strong\u003eです。もしRepositoryを「DB操作クラス」として設計してしまうと、DDDの重要な意図はほぼ失われます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"repositoryが扱うのは集約である\"\u003eRepositoryが扱うのは「集約」である\u003c/h2\u003e\n\u003cp\u003e前章で述べた通り、集約は「同時に守るべき判断とルールの単位」でした。\u003c/p\u003e\n\u003cp\u003eRepositoryは、その集約を\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e取得する\u003c/li\u003e\n\u003cli\u003e保存する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eための唯一の窓口です。\u003c/p\u003e\n\u003cp\u003e重要なのは、Repositoryが\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEntity単体\u003c/li\u003e\n\u003cli\u003eテーブル単位のレコード\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを扱う存在ではない、という点です。Repositoryが扱うのは、\u003cstrong\u003e常に意味を持った集約全体\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp\u003eこの制約があるからこそ、集約の不変条件は安全に保たれます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"なぜrepositoryを介さずに触ってはいけないのか\"\u003eなぜRepositoryを介さずに触ってはいけないのか\u003c/h2\u003e\n\u003cp\u003eもし集約の内部オブジェクトを、Repositoryを介さずに直接取得・更新できてしまうと、次のような問題が起こります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e不変条件を守らずに状態を書き換えられる\u003c/li\u003e\n\u003cli\u003e集約の境界が形骸化する\u003c/li\u003e\n\u003cli\u003e「正しい操作」が分からなくなる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれは、設計が破綻する典型的なパターンです。\u003c/p\u003e\n\u003cp\u003eRepositoryは、「この集約は、こういう単位でしか扱えない」というルールをシステム全体に強制する役割を持っています。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"interfaceを切ることが目的ではない\"\u003einterfaceを切ることが目的ではない\u003c/h2\u003e\n\u003cp\u003eRepositoryはしばしばinterfaceとして定義されます。そのため、「Repository = interface」という理解が広まりがちです。\u003c/p\u003e\n\u003cp\u003eしかし、interfaceを切ること自体は目的ではありません。\u003c/p\u003e\n\u003cp\u003eRepositoryを抽象として定義する理由は、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e集約の概念をインフラから切り離すため\u003c/li\u003e\n\u003cli\u003eモデルの言葉で取得・保存を表現するため\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003cp\u003eもしinterfaceを切ったにもかかわらず、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003efindById\u003c/li\u003e\n\u003cli\u003esave\u003c/li\u003e\n\u003cli\u003edelete\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった汎用的なCRUDメソッドしか存在しないのであれば、そのRepositoryはドメインの言葉をほとんど語っていません。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"良いrepositoryは問いを持っている\"\u003e良いRepositoryは「問い」を持っている\u003c/h2\u003e\n\u003cp\u003e良いRepositoryは、ドメインの問いをそのままメソッドとして表現します。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e有効な注文を取得する\u003c/li\u003e\n\u003cli\u003e処理待ちの支払いを探す\u003c/li\u003e\n\u003cli\u003e特定の条件を満たす集約を取得する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは、SQLやクエリの話ではありません。\u003cstrong\u003eドメインが何を知りたいか\u003c/strong\u003eという問いです。\u003c/p\u003e\n\u003cp\u003eこの形でRepositoryを設計すると、UseCaseのコードは自然言語に近づいていきます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"repositoryとusecaseの健全な距離\"\u003eRepositoryとUseCaseの健全な距離\u003c/h2\u003e\n\u003cp\u003eUseCaseは、Repositoryを使って集約を取得し、操作し、結果を保存します。\u003c/p\u003e\n\u003cp\u003eここで重要なのは、UseCaseが\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e集約の内部構造を知らない\u003c/li\u003e\n\u003cli\u003e永続化の詳細を知らない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという状態を保つことです。\u003c/p\u003e\n\u003cp\u003eUseCaseが知っているのは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどの集約を使うか\u003c/li\u003e\n\u003cli\u003eどの操作を呼ぶか\u003c/li\u003e\n\u003cli\u003e結果を保存する必要があるか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eだけで十分です。\u003c/p\u003e\n\u003cp\u003eこの距離感が保たれていると、UseCaseは「流れ」に集中でき、判断はモデルと集約に委ねられます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"repositoryを薄くしすぎない\"\u003eRepositoryを薄くしすぎない\u003c/h2\u003e\n\u003cp\u003e「Repositoryは薄く保つべきだ」という言葉も、誤解されやすい表現です。\u003c/p\u003e\n\u003cp\u003eRepositoryが薄いとは、ロジックを持たないことではありません。 \u003cstrong\u003eドメインの「判断」を持たないことです。\u003c/strong\u003e\u003c/p\u003e","title":"第5章：Repository は何を抽象化しているのか"},{"content":" Android における Entity の寿命は短い Android で言われる Entity の多くは UI Model である data class を恐れない Immutable にこだわりすぎない sealed class / value object の使いどころ UI Model と Domain Model を分ける意味・分けない意味 Model 変換はドメインの責務ではない この章のまとめ Android における Entity の寿命は短い DDD で語られる Entity は、長い時間を生き続け、同一性を保ち続ける存在として説明されます。しかし Android アプリでは、この前提がそのまま当てはまることは多くありません。\n画面仕様の変更で形がすぐに変わる API 仕様変更の影響を強く受ける UI の都合で一時的な形に変換される このような環境では、Entity を「長寿命で不変な存在」として扱おうとすると、設計が無理をし始めます。\n本書では、Android における Entity を 「ID による同一性を持つが、形は変わりやすい存在」 と捉えます。寿命が短いことを前提にすることで、過剰な抽象化を避けられます。\nAndroid で言われる Entity の多くは UI Model である Android 開発では、データベースのテーブルや API レスポンスを 「Entity」と呼ぶことがよくあります。\nこれらは id を持っており、一見すると DDD における Entity のように見えます。 しかし実際には、DDD が想定する Entity とは異なる役割を担っていることがほとんどです。\nAndroid で扱われるこれらのモデルは、\n画面の表示単位で生成される UI の都合で形が頻繁に変わる 状態を値として扱われる といった性質を持ちます。\nここで使われる id の多くは、\nRecyclerView や Jetpack Compose の key 差分更新のための識別子 であり、時間をまたいだ同一性を保証するためのものではありません。\nつまり、\nid を持っているからといって、 それが Domain Entity であるとは限らない、ということです。\ndata class を恐れない 前節で述べたように、Android で「Entity」と呼ばれているものの多くは、 実際には UI Model や DTO に近い存在です。\nこの文脈において、Entity や Model を data class で表現することは、 DDD 的に見て必ずしも問題ではありません。\nImmutable にこだわりすぎない 不変オブジェクト（Immutable）は、安全でテストしやすい設計として推奨されがちです。しかし Android では、Immutable にこだわりすぎることで、次のような弊害が出ることがあります。\ncopy の連鎖で意図が見えにくくなる 状態更新の責務が分散する パフォーマンスを過剰に気にする設計になる 重要なのは「不変であること」そのものではなく、どこで、誰が状態を変えてよいのかが明確であることです。\n限定された範囲での Mutable な設計は、必ずしも悪ではありません。\nsealed class / value object の使いどころ Android では、sealed class や value object が非常に相性よく使えます。ただし、使いどころを間違えると、逆に複雑さを生みます。\n状態の種類が明確で、分岐を網羅したい場合 → sealed class 単位や意味を値に持たせたい場合 → value object すべてを sealed class にすれば安全、というわけではありません。状態の増減が激しい場合や、UI 専用の一時状態であれば、シンプルな enum や nullable で十分なこともあります。\nUI Model と Domain Model を分ける意味・分けない意味 「UI Model と Domain Model は必ず分けるべきか」という問いには、明確な Yes / No はありません。\n分ける価値があるのは、\n同じドメインを複数の画面で異なる形で使う UI の都合で形が頻繁に変わる Domain の判断を UI から隔離したい といった場合です。\n一方で、単一画面専用のシンプルなモデルであれば、無理に分けることで変換コードだけが増えることもあります。\n本書では、「分けるかどうか」ではなく、なぜ分ける（分けない）のかを説明できるか を重視します。\nModel 変換はドメインの責務ではない Domain Model から UI Model への変換を、ドメイン層に置いてしまうケースがあります。しかし、これは責務の混同を招きやすい設計です。\nUI 表現のための変換は、あくまで UI 側の都合です。ドメインは「どう見せるか」を知る必要はありません。\n変換処理は、ViewModel や専用の Mapper に置くことで、ドメインの純度を保ちやすくなります。\nこの章のまとめ Android におけるエンティティやモデル設計では、\n厳密さよりも変更耐性を重視する data class や mutable を過度に恐れない 分離は目的ではなく手段である という姿勢が重要になります。\n次章では、これらのモデルが Jetpack Compose の状態管理とどう接続されるのか を見ていきます。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/06/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003eAndroid における Entity の寿命は短い\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eAndroid で言われる Entity の多くは UI Model である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#data-class-%E3%82%92%E6%81%90%E3%82%8C%E3%81%AA%E3%81%84\"\u003edata class を恐れない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eImmutable にこだわりすぎない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#sealed-class--value-object-%E3%81%AE%E4%BD%BF%E3%81%84%E3%81%A9%E3%81%93%E3%82%8D\"\u003esealed class / value object の使いどころ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eUI Model と Domain Model を分ける意味・分けない意味\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eModel 変換はドメインの責務ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"android-における-entity-の寿命は短い\"\u003eAndroid における Entity の寿命は短い\u003c/h3\u003e\n\u003cp\u003eDDD で語られる Entity は、長い時間を生き続け、同一性を保ち続ける存在として説明されます。しかし Android アプリでは、この前提がそのまま当てはまることは多くありません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e画面仕様の変更で形がすぐに変わる\u003c/li\u003e\n\u003cli\u003eAPI 仕様変更の影響を強く受ける\u003c/li\u003e\n\u003cli\u003eUI の都合で一時的な形に変換される\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこのような環境では、Entity を「長寿命で不変な存在」として扱おうとすると、設計が無理をし始めます。\u003c/p\u003e\n\u003cp\u003e本書では、Android における Entity を \u003cstrong\u003e「ID による同一性を持つが、形は変わりやすい存在」\u003c/strong\u003e と捉えます。寿命が短いことを前提にすることで、過剰な抽象化を避けられます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"android-で言われる-entity-の多くは-ui-model-である\"\u003eAndroid で言われる Entity の多くは UI Model である\u003c/h3\u003e\n\u003cp\u003eAndroid 開発では、データベースのテーブルや API レスポンスを\n「Entity」と呼ぶことがよくあります。\u003c/p\u003e\n\u003cp\u003eこれらは id を持っており、一見すると DDD における Entity のように見えます。\nしかし実際には、\u003cstrong\u003eDDD が想定する Entity とは異なる役割\u003c/strong\u003eを担っていることがほとんどです。\u003c/p\u003e","title":"第5章：エンティティとモデルのリアルな設計"},{"content":" Jetpack Compose が設計を強制するもの UI State は「ドメインの投影」である 非同期状態をドメインに持ち込まない StateHolder / Reducer パターンの現実的な使い方 ViewModel は「状態の翻訳者」 状態を持ちすぎないという選択 この章のまとめ Jetpack Compose が設計を強制するもの Jetpack Compose の登場によって、Android の設計は大きく変わりました。特に影響が大きいのが、「状態を中心に UI を組み立てる」という考え方です。\nCompose では、\nUI は状態の結果として描画される 状態が変われば UI が再描画される 状態を正しく持てないと UI が破綻する という前提が、半ば強制されます。\nこれは単なる UI フレームワークの違いではなく、設計の中心が状態管理に移った ことを意味します。\nUI State は「ドメインの投影」である UI State は、しばしば「画面表示のためのデータ」として扱われます。しかし、本書では UI State を次のように捉えます。\nUI State は、ドメイン上の判断結果を UI 用に投影したもの\nつまり、UI State 自体が判断を持つべきではありません。\n表示してよいかどうか 操作を許可するかどうか 次にどの状態へ遷移するか これらはドメイン側で決まり、その結果が UI State として表現されます。この関係を意識すると、状態管理の責務が明確になります。\n非同期状態をドメインに持ち込まない Loading / Error / Success といった非同期状態を、ドメインモデルに含めてしまう設計を見かけることがあります。しかし、これはドメインの関心事を曖昧にします。\n非同期状態は、\n通信や I/O の都合 UI 表示のための必要情報 であり、ドメインそのもののルールではありません。\nドメインは「成功した結果」や「失敗の意味」を扱い、Loading かどうかは UI 側で管理する方が、責務が分離されます。\nStateHolder / Reducer パターンの現実的な使い方 状態管理の手法として、StateHolder や Reducer パターンが紹介されることがあります。しかし、これらを厳密に適用しようとすると、コード量が一気に増えがちです。\n本書では、次のような使い方を推奨します。\n状態遷移が複雑な画面に限定して使う すべての画面に強制しない Reducer は「状態遷移のルール」を閉じ込める場所として使う あくまで 必要なところにだけ導入する道具 として扱うことで、設計と実装のバランスを保てます。\nReducer パターンの具体的な実装例は、別紙「参考：Reducer を使う場合・使わない場合のサンプル」を参考にしてください。\nViewModel は「状態の翻訳者」 Compose 時代の ViewModel は、単なるデータ保持クラスではありません。本書では、ViewModel を次のように位置づけます。\nドメインの判断を UI State に翻訳する存在\nDomain → UI State への変換 非同期処理の調停 (ドメイン側に非同期処理を実装しない) UI からのイベントをドメインに渡す ViewModel がこの役割に集中できていれば、UI は状態を表示することに専念できます。\n状態を持ちすぎないという選択 Compose では、すべてを State として持ちたくなりがちです。しかし、状態が増えすぎると、逆に全体像が見えなくなります。\n一時的な UI 状態は remember で閉じる 画面をまたがない状態は ViewModel に上げない 永続化が必要なものだけを状態として持つ 「どこに状態を持つか」は、設計判断そのものです。State を減らすことも、立派な設計です。\nこの章のまとめ Jetpack Compose 時代の Android 設計では、\n状態管理が設計の中心になる UI State はドメイン判断の結果である 非同期や表示都合をドメインに混ぜない という整理が重要になります。\n次章では、Repository の責務を Android 文脈で再定義し、どこまでを Repository に任せるべきかを見ていきます。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/07/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003eJetpack Compose が設計を強制するもの\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eUI State は「ドメインの投影」である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003e非同期状態をドメインに持ち込まない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eStateHolder / Reducer パターンの現実的な使い方\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#viewmodel-%E3%81%AF%E7%8A%B6%E6%85%8B%E3%81%AE%E7%BF%BB%E8%A8%B3%E8%80%85\"\u003eViewModel は「状態の翻訳者」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003e状態を持ちすぎないという選択\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"jetpack-compose-が設計を強制するもの\"\u003eJetpack Compose が設計を強制するもの\u003c/h3\u003e\n\u003cp\u003eJetpack Compose の登場によって、Android の設計は大きく変わりました。特に影響が大きいのが、「状態を中心に UI を組み立てる」という考え方です。\u003c/p\u003e\n\u003cp\u003eCompose では、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUI は状態の結果として描画される\u003c/li\u003e\n\u003cli\u003e状態が変われば UI が再描画される\u003c/li\u003e\n\u003cli\u003e状態を正しく持てないと UI が破綻する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという前提が、半ば強制されます。\u003c/p\u003e\n\u003cp\u003eこれは単なる UI フレームワークの違いではなく、\u003cstrong\u003e設計の中心が状態管理に移った\u003c/strong\u003e ことを意味します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"ui-state-はドメインの投影である\"\u003eUI State は「ドメインの投影」である\u003c/h3\u003e\n\u003cp\u003eUI State は、しばしば「画面表示のためのデータ」として扱われます。しかし、本書では UI State を次のように捉えます。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eUI State は、ドメイン上の判断結果を UI 用に投影したもの\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eつまり、UI State 自体が判断を持つべきではありません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e表示してよいかどうか\u003c/li\u003e\n\u003cli\u003e操作を許可するかどうか\u003c/li\u003e\n\u003cli\u003e次にどの状態へ遷移するか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらはドメイン側で決まり、その結果が UI State として表現されます。この関係を意識すると、状態管理の責務が明確になります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"非同期状態をドメインに持ち込まない\"\u003e非同期状態をドメインに持ち込まない\u003c/h3\u003e\n\u003cp\u003eLoading / Error / Success といった非同期状態を、ドメインモデルに含めてしまう設計を見かけることがあります。しかし、これはドメインの関心事を曖昧にします。\u003c/p\u003e","title":"第6章：状態管理と DDD の接点"},{"content":" 設計が壊れる瞬間は、コードが間違ったときではない 「正しい設計」を目指すと、なぜ苦しくなるのか DDDが一貫して嫌うもの 設計の良し悪しは「変更点の数」で測れる DDDは「慎重な楽観主義」である この章のまとめ この章では、DDDを「理論」や「美しさ」から一段引き離し、なぜDDDが現場で効くのかという実践的な理由を掘り下げます。\n結論を先に言うと、DDDは「正しい設計」を目指すものではありません。DDDが本当に守ろうとしているのは、設計の耐久性です。\n設計が壊れる瞬間は、コードが間違ったときではない 多くのエンジニアは、設計が壊れる原因を次のように考えがちです。\n初期設計が甘かった スキルの低いメンバーが実装した リファクタリングを怠った しかし、実務で設計が壊れる瞬間を振り返ると、少し違う景色が見えてきます。\n設計が壊れるのは、仕様が変わったときです。\n似ているけど微妙に違うルールが追加される 例外ケースが後から増える 「当初は想定していなかった」使われ方をされる コードが間違っていたからではありません。 コードが、変化に耐えられなかっただけです。\nDDDは、この「変化」を前提に設計を組み立てます。\n「正しい設計」を目指すと、なぜ苦しくなるのか 設計の議論でよく聞く言葉があります。\nこの設計はDDDとして正しいのか？ この責務分割はCleanなのか？ 原則に反していないか？ こうした問いは一見まっとうですが、DDDの本質からは少しズレています。\nなぜなら、DDDにおいて重要なのは\nこの設計が、将来の変更にどれだけ耐えられるか\nだからです。\n設計原則は「守るべきルール」ではありません。 設計が壊れにくくなる方向性を示すヒントに過ぎません。\nDDDは、正解集を与えてくれません。 代わりに、「どこが壊れやすいか」を教えてくれます。\nDDDが一貫して嫌うもの ここまでの章を通して、DDDが何度も避けようとしているものがありました。\nそれは、\n意味の混線\nです。\nドメインの意味と技術の都合が混ざる 複数のユースケースの意図が1つのクラスに混ざる 今の仕様と将来の仕様が同じif文に混ざる 混ざった瞬間、そのコードは「今は動くが、未来に弱い」状態になります。\nDDDは、\nレイヤーを分け 境界を引き 言葉を揃え 意味が混ざらないよう、徹底的に抵抗します。\nそれは美学ではありません。 変更時に壊れないための実務的な戦略です。\n設計の良し悪しは「変更点の数」で測れる DDD的な設計かどうかを見分ける、非常にシンプルな指標があります。\n仕様変更が入ったとき、直す場所はいくつあるか\n1か所で済むなら、良い設計 あちこちに影響が飛ぶなら、壊れやすい設計 DDDは、この「影響範囲」を小さくするための道具箱です。\nEntityに閉じた変更 UseCaseだけで完結する変更 Repositoryの差し替えで済む変更 こうした変更の仕方ができる設計は、結果として長生きします。\nDDDは「慎重な楽観主義」である DDDは、未来を完全に予測しようとはしません。\nどう変わるかは分からない でも、必ず変わる この前提に立っています。\nだからDDDは、\n早すぎる抽象化を避け 今わかっている境界だけを引き 変わり始めたところからモデルを育てる という、慎重な姿勢を取ります。\n楽観的すぎず、悲観的すぎない。 変化を信じて、備えすぎない。\nこのバランス感覚こそが、DDDの実践的な価値です。\nこの章のまとめ この章で伝えたかったことは、次の一点に集約されます。\nDDDは「正しさ」を証明するための理論ではない DDDは「壊れにくい設計」を作るための考え方である 設計は、いつか必ず変更されます。 そのときに、\nどこを直せばいいか分かる なぜそうなっているか説明できる 壊さずに手を入れられる そういうコードを残すこと。\nそれがDDDが目指しているゴールです。\n","permalink":"https://design.okuda-studio.com/books/004-ddd/06/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%8C%E5%A3%8A%E3%82%8C%E3%82%8B%E7%9E%AC%E9%96%93%E3%81%AF%E3%82%B3%E3%83%BC%E3%83%89%E3%81%8C%E9%96%93%E9%81%95%E3%81%A3%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e設計が壊れる瞬間は、コードが間違ったときではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%AD%A3%E3%81%97%E3%81%84%E8%A8%AD%E8%A8%88%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E3%81%A8%E3%81%AA%E3%81%9C%E8%8B%A6%E3%81%97%E3%81%8F%E3%81%AA%E3%82%8B%E3%81%AE%E3%81%8B\"\u003e「正しい設計」を目指すと、なぜ苦しくなるのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ddd%E3%81%8C%E4%B8%80%E8%B2%AB%E3%81%97%E3%81%A6%E5%AB%8C%E3%81%86%E3%82%82%E3%81%AE\"\u003eDDDが一貫して嫌うもの\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AE%E8%89%AF%E3%81%97%E6%82%AA%E3%81%97%E3%81%AF%E5%A4%89%E6%9B%B4%E7%82%B9%E3%81%AE%E6%95%B0%E3%81%A7%E6%B8%AC%E3%82%8C%E3%82%8B\"\u003e設計の良し悪しは「変更点の数」で測れる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ddd%E3%81%AF%E6%85%8E%E9%87%8D%E3%81%AA%E6%A5%BD%E8%A6%B3%E4%B8%BB%E7%BE%A9%E3%81%A7%E3%81%82%E3%82%8B\"\u003eDDDは「慎重な楽観主義」である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eこの章では、DDDを「理論」や「美しさ」から一段引き離し、\u003cstrong\u003eなぜDDDが現場で効くのか\u003c/strong\u003eという実践的な理由を掘り下げます。\u003c/p\u003e\n\u003cp\u003e結論を先に言うと、DDDは「正しい設計」を目指すものではありません。DDDが本当に守ろうとしているのは、\u003cstrong\u003e設計の耐久性\u003c/strong\u003eです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"設計が壊れる瞬間はコードが間違ったときではない\"\u003e設計が壊れる瞬間は、コードが間違ったときではない\u003c/h2\u003e\n\u003cp\u003e多くのエンジニアは、設計が壊れる原因を次のように考えがちです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e初期設計が甘かった\u003c/li\u003e\n\u003cli\u003eスキルの低いメンバーが実装した\u003c/li\u003e\n\u003cli\u003eリファクタリングを怠った\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eしかし、実務で設計が壊れる瞬間を振り返ると、少し違う景色が見えてきます。\u003c/p\u003e\n\u003cp\u003e設計が壊れるのは、\u003cstrong\u003e仕様が変わったとき\u003c/strong\u003eです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e似ているけど微妙に違うルールが追加される\u003c/li\u003e\n\u003cli\u003e例外ケースが後から増える\u003c/li\u003e\n\u003cli\u003e「当初は想定していなかった」使われ方をされる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eコードが間違っていたからではありません。\n\u003cstrong\u003eコードが、変化に耐えられなかった\u003c/strong\u003eだけです。\u003c/p\u003e\n\u003cp\u003eDDDは、この「変化」を前提に設計を組み立てます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"正しい設計を目指すとなぜ苦しくなるのか\"\u003e「正しい設計」を目指すと、なぜ苦しくなるのか\u003c/h2\u003e\n\u003cp\u003e設計の議論でよく聞く言葉があります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこの設計はDDDとして正しいのか？\u003c/li\u003e\n\u003cli\u003eこの責務分割はCleanなのか？\u003c/li\u003e\n\u003cli\u003e原則に反していないか？\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうした問いは一見まっとうですが、DDDの本質からは少しズレています。\u003c/p\u003e\n\u003cp\u003eなぜなら、DDDにおいて重要なのは\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eこの設計が、将来の変更にどれだけ耐えられるか\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eだからです。\u003c/p\u003e\n\u003cp\u003e設計原則は「守るべきルール」ではありません。\n\u003cstrong\u003e設計が壊れにくくなる方向性を示すヒント\u003c/strong\u003eに過ぎません。\u003c/p\u003e\n\u003cp\u003eDDDは、正解集を与えてくれません。\n代わりに、「どこが壊れやすいか」を教えてくれます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"dddが一貫して嫌うもの\"\u003eDDDが一貫して嫌うもの\u003c/h2\u003e\n\u003cp\u003eここまでの章を通して、DDDが何度も避けようとしているものがありました。\u003c/p\u003e\n\u003cp\u003eそれは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e意味の混線\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eドメインの意味と技術の都合が混ざる\u003c/li\u003e\n\u003cli\u003e複数のユースケースの意図が1つのクラスに混ざる\u003c/li\u003e\n\u003cli\u003e今の仕様と将来の仕様が同じif文に混ざる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e混ざった瞬間、そのコードは「今は動くが、未来に弱い」状態になります。\u003c/p\u003e\n\u003cp\u003eDDDは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eレイヤーを分け\u003c/li\u003e\n\u003cli\u003e境界を引き\u003c/li\u003e\n\u003cli\u003e言葉を揃え\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e意味が混ざらないよう、徹底的に抵抗します。\u003c/p\u003e\n\u003cp\u003eそれは美学ではありません。\n\u003cstrong\u003e変更時に壊れないための実務的な戦略\u003c/strong\u003eです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"設計の良し悪しは変更点の数で測れる\"\u003e設計の良し悪しは「変更点の数」で測れる\u003c/h2\u003e\n\u003cp\u003eDDD的な設計かどうかを見分ける、非常にシンプルな指標があります。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e仕様変更が入ったとき、直す場所はいくつあるか\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e1か所で済むなら、良い設計\u003c/li\u003e\n\u003cli\u003eあちこちに影響が飛ぶなら、壊れやすい設計\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eDDDは、この「影響範囲」を小さくするための道具箱です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEntityに閉じた変更\u003c/li\u003e\n\u003cli\u003eUseCaseだけで完結する変更\u003c/li\u003e\n\u003cli\u003eRepositoryの差し替えで済む変更\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうした変更の仕方ができる設計は、結果として長生きします。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"dddは慎重な楽観主義である\"\u003eDDDは「慎重な楽観主義」である\u003c/h2\u003e\n\u003cp\u003eDDDは、未来を完全に予測しようとはしません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどう変わるかは分からない\u003c/li\u003e\n\u003cli\u003eでも、必ず変わる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの前提に立っています。\u003c/p\u003e\n\u003cp\u003eだからDDDは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e早すぎる抽象化を避け\u003c/li\u003e\n\u003cli\u003e今わかっている境界だけを引き\u003c/li\u003e\n\u003cli\u003e変わり始めたところからモデルを育てる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという、慎重な姿勢を取ります。\u003c/p\u003e","title":"第6章：設計は「正しさ」ではなく「耐久性」で決まる"},{"content":" 想定する画面要件（共通） Reducer を使わない場合 UI State ViewModel 特徴 Reducer を使う場合 UI State（同じ） Event Reducer（状態遷移の定義） ViewModel（StateHolder） 特徴 どちらを選ぶべきか Reducer を使わない方がよい場合 Reducer を使う価値が出る場合 この章のまとめ この章では、同じ要件の画面を題材に、\nReducer パターンを 使わない場合 Reducer パターンを 使う場合 の 2 つの実装を比較します。\n目的は、 Reducer が「必要になる瞬間」がどこにあるのかを体感すること です。\n想定する画面要件（共通） 初期表示時にデータを読み込む 読み込み中はローディング表示 成功したら一覧を表示 失敗したらエラーメッセージを表示 よくある、シンプルだが 状態は 3 種類ある画面 です。\nReducer を使わない場合 UI State data class UiState( val isLoading: Boolean = false, val items: List\u0026lt;Item\u0026gt; = emptyList(), val error: String? = null ) ViewModel class SampleViewModel( private val repository: ItemRepository ) : ViewModel() { private val _state = MutableStateFlow(UiState()) val state: StateFlow\u0026lt;UiState\u0026gt; = _state fun load() { _state.update { it.copy(isLoading = true, error = null) } viewModelScope.launch { runCatching { repository.loadItems() }.onSuccess { items -\u0026gt; _state.update { it.copy( isLoading = false, items = items ) } }.onFailure { e -\u0026gt; _state.update { it.copy( isLoading = false, error = e.message ) } } } } } 特徴 コード量が少ない 処理の流れが直線的で追いやすい 小規模な画面では十分に読みやすい 一方で、\n状態更新ロジックが ViewModel に散らばる 状態が増えると if / copy が増殖しやすい という性質を持ちます。\nReducer を使う場合 UI State（同じ） data class UiState( val isLoading: Boolean = false, val items: List\u0026lt;Item\u0026gt; = emptyList(), val error: String? = null ) Event sealed interface UiEvent { object Load : UiEvent data class LoadSuccess(val items: List\u0026lt;Item\u0026gt;) : UiEvent data class LoadError(val message: String) : UiEvent } Reducer（状態遷移の定義） fun reduce(state: UiState, event: UiEvent): UiState = when (event) { UiEvent.Load -\u0026gt; state.copy(isLoading = true, error = null) is UiEvent.LoadSuccess -\u0026gt; state.copy( isLoading = false, items = event.items ) is UiEvent.LoadError -\u0026gt; state.copy( isLoading = false, error = event.message ) } Reducer は、小規模なものであれば、 ViewModel 内に定義しても問題ありません。\nただし、規模が大きくなり始めたら、 ViewModel と同じディレクトリ内の別ファイルに定義すると良い場合が多いです。\nViewModel（StateHolder） class SampleViewModel( private val repository: ItemRepository ) : ViewModel() { private val _state = MutableStateFlow(UiState()) val state: StateFlow\u0026lt;UiState\u0026gt; = _state fun dispatch(event: UiEvent) { _state.update { reduce(it, event) } } fun load() { dispatch(UiEvent.Load) viewModelScope.launch { runCatching { repository.loadItems() }.onSuccess { items -\u0026gt; dispatch(UiEvent.LoadSuccess(items)) }.onFailure { e -\u0026gt; dispatch(UiEvent.LoadError(e.message ?: \u0026#34;error\u0026#34;)) } } } } 特徴 状態遷移のルールが Reducer に集約される ViewModel から「状態変更の詳細」が消える 画面の状態遷移がコードとして可視化される 一方で、\nEvent / Reducer の定義が増える 単純な画面では冗長に感じやすい というコストがあります。\nどちらを選ぶべきか 判断基準はシンプルです。\nReducer を使わない方がよい場合 状態が少ない 状態遷移が直線的 ViewModel が十分に読みやすい Reducer を使う価値が出る場合 状態の組み合わせが増えてきた ローディング中・エラー中の挙動が複雑 ViewModel に状態更新ロジックが散り始めた この章のまとめ Reducer パターンは、\n設計を「正しくする」ためのものではありません 複雑になり始めた状態管理を、破綻させないための道具 です 最初から導入する必要はありません。 「つらくなったら導入する」くらいが、Android ではちょうどよい のです。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/07-01/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003e想定する画面要件（共通）\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#reducer-%E3%82%92%E4%BD%BF%E3%82%8F%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88\"\u003eReducer を使わない場合\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#ui-state\"\u003eUI State\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#viewmodel\"\u003eViewModel\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%89%B9%E5%BE%B4\"\u003e特徴\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#reducer-%E3%82%92%E4%BD%BF%E3%81%86%E5%A0%B4%E5%90%88\"\u003eReducer を使う場合\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#ui-state%E5%90%8C%E3%81%98\"\u003eUI State（同じ）\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#event\"\u003eEvent\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#reducer%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%E3%81%AE%E5%AE%9A%E7%BE%A9\"\u003eReducer（状態遷移の定義）\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#viewmodelstateholder\"\u003eViewModel（StateHolder）\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%89%B9%E5%BE%B4-1\"\u003e特徴\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eどちらを選ぶべきか\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003eReducer を使わない方がよい場合\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eReducer を使う価値が出る場合\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eこの章では、同じ要件の画面を題材に、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eReducer パターンを \u003cstrong\u003e使わない場合\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003eReducer パターンを \u003cstrong\u003e使う場合\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eの 2 つの実装を比較します。\u003c/p\u003e\n\u003cp\u003e目的は、\n\u003cstrong\u003eReducer が「必要になる瞬間」がどこにあるのかを体感すること\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"想定する画面要件共通\"\u003e想定する画面要件（共通）\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e初期表示時にデータを読み込む\u003c/li\u003e\n\u003cli\u003e読み込み中はローディング表示\u003c/li\u003e\n\u003cli\u003e成功したら一覧を表示\u003c/li\u003e\n\u003cli\u003e失敗したらエラーメッセージを表示\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eよくある、シンプルだが \u003cstrong\u003e状態は 3 種類ある画面\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"reducer-を使わない場合\"\u003eReducer を使わない場合\u003c/h2\u003e\n\u003ch3 id=\"ui-state\"\u003eUI State\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edata\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eUiState\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e isLoading: Boolean = \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e items: List\u0026lt;Item\u0026gt; = emptyList(),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e error: String? = \u003cspan style=\"color:#66d9ef\"\u003enull\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch3 id=\"viewmodel\"\u003eViewModel\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eSampleViewModel\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eprivate\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e repository: ItemRepository\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e) : ViewModel() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eprivate\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e _state = MutableStateFlow(UiState())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e state: StateFlow\u0026lt;UiState\u0026gt; = _state\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efun\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eload\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        _state.update { \u003cspan style=\"color:#66d9ef\"\u003eit\u003c/span\u003e.copy(isLoading = \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e, error = \u003cspan style=\"color:#66d9ef\"\u003enull\u003c/span\u003e) }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        viewModelScope.launch {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            runCatching {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                repository.loadItems()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }.onSuccess { items \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                _state.update {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#66d9ef\"\u003eit\u003c/span\u003e.copy(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        isLoading = \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        items = items\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }.onFailure { e \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                _state.update {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#66d9ef\"\u003eit\u003c/span\u003e.copy(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        isLoading = \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        error = e.message\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch3 id=\"特徴\"\u003e特徴\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eコード量が少ない\u003c/li\u003e\n\u003cli\u003e処理の流れが直線的で追いやすい\u003c/li\u003e\n\u003cli\u003e小規模な画面では十分に読みやすい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e一方で、\u003c/p\u003e","title":"参考：Reducer を使う場合・使わない場合のサンプル"},{"content":" パターン1：UseCase境界を「変更の防波堤」にする パターン2：モデルは「ルールが見え始めたところ」から導入する パターン3：Repositoryは「差し替えたい未来」が見えたら切る パターン4：DTO変換が苦しくなったら、境界が間違っている パターン5：「全部DDDにしない」という選択 この章のまとめ この章では、DDDを「思想」や「設計論」から一歩進めて、実務でどのように導入していくかを具体的なパターンとして整理します。\nここで扱うのは、理想形のDDDではありません。\n時間が足りない メンバー全員がDDDを理解しているわけではない 既存コードがすでに存在する そうした前提の中で、それでもDDDの考え方がどう役に立つのかを見ていきます。\nパターン1：UseCase境界を「変更の防波堤」にする 最も多くの現場で使われているDDDの形は、これです。\nDomainは完全ではない Entityも最小限 それでもUseCaseだけは守る UseCaseを「やりたいこと単位」で切り、\n入力 処理の流れ Repository呼び出し を閉じ込めます。\nこのとき重要なのは、UseCaseを肥大化させないことではありません。 重要なのは、\n変更理由が1つに収まっているか\nです。\n多少長くても、\nこのUseCaseは「〇〇を登録する」 このUseCaseは「〇〇を取り消す」 と説明できるなら、それは実務的には十分にDDDです。\nパターン2：モデルは「ルールが見え始めたところ」から導入する 実務でよくある失敗は、最初からモデル（EntityやValue Object）を作り込みすぎることです。\n状態遷移を全部入れる 不変条件を先回りして書く 将来使いそうなメソッドを生やす 結果として、\n使われないロジック 想定外の変更 消せない責務 がモデルに溜まっていきます。\n実務では、\nルールが増え始めてからEntityを育てる\nくらいが、ちょうど良いです。\n最初は単なるdata classでも構いません。この段階で、それがEntityなのかValue Objectなのかを厳密に判断する必要はありません。 「これはモデルに閉じ込めた方が安全だ」と感じた瞬間が、導入タイミングです。\nパターン3：Repositoryは「差し替えたい未来」が見えたら切る 理想論では、Repositoryは最初から切ります。\nしかし実務では、\n当分DBは変わらない APIも1種類しかない というケースも多い。\nその場合、無理にRepositoryを作る必要はありません。\nただし、次の兆候が見えたら要注意です。\nテストでモックしたくなった キャッシュを挟みたくなった 取得方法の都合がUseCaseに漏れ始めた この瞬間が、Repositoryを切るサインです。\nDDDは「最初から全部やる」設計ではなく、 分離が必要になった瞬間を逃さない設計です。\nパターン4：DTO変換が苦しくなったら、境界が間違っている 実務でDDDがつらくなるポイントの1つが、変換地獄です。\nAPI DTO → Domain → UI Model Entity → Domain → UseCase Input 変換コードが増えすぎると、\n何が本体なのか分からない 修正が怖い 状態になります。\nここで疑うべきは、Mapperの書き方ではありません。\nその境界、本当に必要か？\nです。\nDDDの境界は、\n技術が変わる 責務が変わる 意味が変わる ところにだけ引くものです。\n変換が苦しいのは、 意味がほとんど変わらない場所に境界を引いているサインかもしれません。\nパターン5：「全部DDDにしない」という選択 現場で最も健全なDDD導入は、これです。\n複雑な部分だけDDD CRUDは割り切る 重要でない画面はシンプルに書く DDDは、コストのかかる設計です。\n考える時間が必要 言葉を揃える必要がある 説明コストが発生する だからこそ、\n壊れたら困るところにだけ使う\nこの割り切りが、実務では非常に強い。\nDDDは「全体を支配する思想」ではなく、 要所を守るための武器です。\nこの章のまとめ この章で紹介したパターンに、共通点があります。\n完璧を目指していない 未来を言い当てようとしていない 今つらくなり始めた場所にだけ手を入れている これが、実務で生き残っているDDDの姿です。\nDDDは、\n厳密で 美しくて 教科書的 である必要はありません。\n変更が来たときに助けてくれるかどうか。 それだけが、実務における評価基準です。\n次の章では、ここまでの実務パターンを踏まえ、 DDDを導入して失敗する典型パターンを整理します。\n失敗例を知ることは、 成功例を知るよりも、ずっと役に立ちます。\n","permalink":"https://design.okuda-studio.com/books/004-ddd/07/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B31usecase%E5%A2%83%E7%95%8C%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%AE%E9%98%B2%E6%B3%A2%E5%A0%A4%E3%81%AB%E3%81%99%E3%82%8B\"\u003eパターン1：UseCase境界を「変更の防波堤」にする\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B32%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AF%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%8C%E8%A6%8B%E3%81%88%E5%A7%8B%E3%82%81%E3%81%9F%E3%81%A8%E3%81%93%E3%82%8D%E3%81%8B%E3%82%89%E5%B0%8E%E5%85%A5%E3%81%99%E3%82%8B\"\u003eパターン2：モデルは「ルールが見え始めたところ」から導入する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B33repository%E3%81%AF%E5%B7%AE%E3%81%97%E6%9B%BF%E3%81%88%E3%81%9F%E3%81%84%E6%9C%AA%E6%9D%A5%E3%81%8C%E8%A6%8B%E3%81%88%E3%81%9F%E3%82%89%E5%88%87%E3%82%8B\"\u003eパターン3：Repositoryは「差し替えたい未来」が見えたら切る\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B34dto%E5%A4%89%E6%8F%9B%E3%81%8C%E8%8B%A6%E3%81%97%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E5%A2%83%E7%95%8C%E3%81%8C%E9%96%93%E9%81%95%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B\"\u003eパターン4：DTO変換が苦しくなったら、境界が間違っている\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B35%E5%85%A8%E9%83%A8ddd%E3%81%AB%E3%81%97%E3%81%AA%E3%81%84%E3%81%A8%E3%81%84%E3%81%86%E9%81%B8%E6%8A%9E\"\u003eパターン5：「全部DDDにしない」という選択\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eこの章では、DDDを「思想」や「設計論」から一歩進めて、\u003cstrong\u003e実務でどのように導入していくか\u003c/strong\u003eを具体的なパターンとして整理します。\u003c/p\u003e\n\u003cp\u003eここで扱うのは、理想形のDDDではありません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e時間が足りない\u003c/li\u003e\n\u003cli\u003eメンバー全員がDDDを理解しているわけではない\u003c/li\u003e\n\u003cli\u003e既存コードがすでに存在する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eそうした前提の中で、それでもDDDの考え方が\u003cstrong\u003eどう役に立つのか\u003c/strong\u003eを見ていきます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"パターン1usecase境界を変更の防波堤にする\"\u003eパターン1：UseCase境界を「変更の防波堤」にする\u003c/h2\u003e\n\u003cp\u003e最も多くの現場で使われているDDDの形は、これです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDomainは完全ではない\u003c/li\u003e\n\u003cli\u003eEntityも最小限\u003c/li\u003e\n\u003cli\u003eそれでもUseCaseだけは守る\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eUseCaseを「やりたいこと単位」で切り、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e入力\u003c/li\u003e\n\u003cli\u003e処理の流れ\u003c/li\u003e\n\u003cli\u003eRepository呼び出し\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを閉じ込めます。\u003c/p\u003e\n\u003cp\u003eこのとき重要なのは、UseCaseを\u003cstrong\u003e肥大化させないこと\u003c/strong\u003eではありません。\n重要なのは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e変更理由が1つに収まっているか\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003cp\u003e多少長くても、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこのUseCaseは「〇〇を登録する」\u003c/li\u003e\n\u003cli\u003eこのUseCaseは「〇〇を取り消す」\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eと説明できるなら、それは実務的には十分にDDDです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"パターン2モデルはルールが見え始めたところから導入する\"\u003eパターン2：モデルは「ルールが見え始めたところ」から導入する\u003c/h2\u003e\n\u003cp\u003e実務でよくある失敗は、最初からモデル（EntityやValue Object）を作り込みすぎることです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e状態遷移を全部入れる\u003c/li\u003e\n\u003cli\u003e不変条件を先回りして書く\u003c/li\u003e\n\u003cli\u003e将来使いそうなメソッドを生やす\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e結果として、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e使われないロジック\u003c/li\u003e\n\u003cli\u003e想定外の変更\u003c/li\u003e\n\u003cli\u003e消せない責務\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eがモデルに溜まっていきます。\u003c/p\u003e\n\u003cp\u003e実務では、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eルールが増え始めてからEntityを育てる\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eくらいが、ちょうど良いです。\u003c/p\u003e\n\u003cp\u003e最初は単なるdata classでも構いません。この段階で、それがEntityなのかValue Objectなのかを厳密に判断する必要はありません。\n「これはモデルに閉じ込めた方が安全だ」と感じた瞬間が、導入タイミングです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"パターン3repositoryは差し替えたい未来が見えたら切る\"\u003eパターン3：Repositoryは「差し替えたい未来」が見えたら切る\u003c/h2\u003e\n\u003cp\u003e理想論では、Repositoryは最初から切ります。\u003c/p\u003e\n\u003cp\u003eしかし実務では、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e当分DBは変わらない\u003c/li\u003e\n\u003cli\u003eAPIも1種類しかない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eというケースも多い。\u003c/p\u003e\n\u003cp\u003eその場合、無理にRepositoryを作る必要はありません。\u003c/p\u003e\n\u003cp\u003eただし、次の兆候が見えたら要注意です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eテストでモックしたくなった\u003c/li\u003e\n\u003cli\u003eキャッシュを挟みたくなった\u003c/li\u003e\n\u003cli\u003e取得方法の都合がUseCaseに漏れ始めた\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの瞬間が、Repositoryを切るサインです。\u003c/p\u003e\n\u003cp\u003eDDDは「最初から全部やる」設計ではなく、\n\u003cstrong\u003e分離が必要になった瞬間を逃さない設計\u003c/strong\u003eです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"パターン4dto変換が苦しくなったら境界が間違っている\"\u003eパターン4：DTO変換が苦しくなったら、境界が間違っている\u003c/h2\u003e\n\u003cp\u003e実務でDDDがつらくなるポイントの1つが、変換地獄です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAPI DTO → Domain → UI Model\u003c/li\u003e\n\u003cli\u003eEntity → Domain → UseCase Input\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e変換コードが増えすぎると、\u003c/p\u003e","title":"第7章：DDD を現場でどのように導入していくか"},{"content":" Repository は「永続化の抽象」ではない Android における Repository の最適責務 Repository にロジックが集まりやすい理由 DataSource を分けすぎる問題 キャッシュ戦略とドメイン汚染 Repository は「薄くていい」が「雑であってはいけない」 この章のまとめ Repository は「永続化の抽象」ではない DDD の文脈では、Repository はしばしば「永続化の抽象」と説明されます。しかし、この説明を Android にそのまま当てはめると、Repository の責務は一気に分かりづらくなります。\nAndroid アプリの Repository が相手にしているのは、必ずしも「永続化」だけではありません。\nAPI 通信 ローカル DB キャッシュ インメモリ状態 これらをすべて「永続化」と呼ぶのは、少し無理があります。\n本書では、Android における Repository を次のように捉えます。\nRepository は、ドメインから見た「データ取得・保存の窓口」である\n重要なのは、「どこから取ってくるか」や「どう保存するか」をドメインが知らなくてよい状態を作ることです。\nAndroid における Repository の最適責務 Android の Repository が担うべき責務は、非常にシンプルです。\n必要なデータを取得する 必要なデータを保存する データ取得手段の違いを隠蔽する 逆に言えば、次のようなことは Repository の責務ではありません。\nビジネス判断 状態遷移の決定 UI 表示の都合による変換 Repository が「判断」を持ち始めた瞬間、設計は濁り始めます。\nたとえば、\nこの場合はキャッシュを返す／返さない この条件なら空リストにする エラーを成功として扱う といった判断が Repository に入り込むと、「なぜそうなるのか」を追うのが非常に難しくなります。\nRepository にロジックが集まりやすい理由 Repository は、設計が崩れ始めたときに、もっともロジックが集まりやすい場所です。その理由は単純です。\nViewModel から直接触られない UseCase の下に隠れている DataSource を束ねている つまり、「ここに書いておけば怒られにくい」場所になりやすいのです。\nしかし、その結果として Repository が次のような姿になることがあります。\nif 文だらけの巨大クラス 返り値の型が文脈ごとに変わる テストが書きづらい この状態は、Repository が責務を超えた仕事をしているサインです。\nDataSource を分けすぎる問題 Clean Architecture の影響で、次のような構成をよく見かけます。\nRepository RemoteDataSource LocalDataSource CacheDataSource 理論的には美しく見えますが、Android アプリでは分けすぎが問題になることも少なくありません。\nファイル数が増える 処理の流れが追いにくくなる 変更時に修正箇所が増える 重要なのは、「分けた理由を説明できるか」です。\n実装差分が本当に大きいのか 将来的に差し替える可能性が高いのか これらに Yes と答えられない場合、Repository 内に実装を閉じた方が、結果として分かりやすい構造になることも多いです。\nキャッシュ戦略とドメイン汚染 Android アプリでは、キャッシュ戦略が避けて通れません。\n常に最新を取りに行くのか キャッシュを優先するのか オフライン時はどう振る舞うのか これらの判断をどこに置くかは、非常に重要です。\n本書の立場は明確です。\nキャッシュ戦略は Repository の責務だが、その意味づけはドメインに置く\nキャッシュを使うかどうかの判断理由 古いデータを許容する条件 これらはドメイン側で定義されるべきです。一方で、\n実際にどのデータソースを使うか キャッシュの保存・取得方法 は Repository に閉じ込めます。\nこの分離ができていないと、ドメインモデルが Data 事情に引きずられ、設計が一気に崩れます。\nRepository は「薄くていい」が「雑であってはいけない」 Android における Repository は、結果として薄くなりがちです。それ自体は問題ありません。\n問題になるのは、\n責務が曖昧 判断基準が見えない 返り値の意味が説明できない 状態になることです。\nRepository は、\n何を返すのか どんな失敗が起こり得るのか を明確に定義しておく必要があります。ここが曖昧だと、UseCase や ViewModel 側に防御コードが増え、全体が汚れていきます。\nこの章のまとめ Repository は、\nデータ取得・保存の窓口であり 判断を持たない だが責務は明確であるべき という、少し難しい立ち位置にあります。\nAndroid × DDD において重要なのは、Repository を「なんでも屋」にしないことです。\n次章では、DI・Hilt と DDD をどう付き合せるかを見ていきます。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/08/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003eRepository は「永続化の抽象」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eAndroid における Repository の最適責務\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eRepository にロジックが集まりやすい理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eDataSource を分けすぎる問題\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eキャッシュ戦略とドメイン汚染\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eRepository は「薄くていい」が「雑であってはいけない」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"repository-は永続化の抽象ではない\"\u003eRepository は「永続化の抽象」ではない\u003c/h3\u003e\n\u003cp\u003eDDD の文脈では、Repository はしばしば「永続化の抽象」と説明されます。しかし、この説明を Android にそのまま当てはめると、Repository の責務は一気に分かりづらくなります。\u003c/p\u003e\n\u003cp\u003eAndroid アプリの Repository が相手にしているのは、必ずしも「永続化」だけではありません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAPI 通信\u003c/li\u003e\n\u003cli\u003eローカル DB\u003c/li\u003e\n\u003cli\u003eキャッシュ\u003c/li\u003e\n\u003cli\u003eインメモリ状態\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらをすべて「永続化」と呼ぶのは、少し無理があります。\u003c/p\u003e\n\u003cp\u003e本書では、Android における Repository を次のように捉えます。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eRepository は、ドメインから見た「データ取得・保存の窓口」である\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e重要なのは、「どこから取ってくるか」や「どう保存するか」をドメインが知らなくてよい状態を作ることです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"android-における-repository-の最適責務\"\u003eAndroid における Repository の最適責務\u003c/h3\u003e\n\u003cp\u003eAndroid の Repository が担うべき責務は、非常にシンプルです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e必要なデータを取得する\u003c/li\u003e\n\u003cli\u003e必要なデータを保存する\u003c/li\u003e\n\u003cli\u003eデータ取得手段の違いを隠蔽する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e逆に言えば、次のようなことは Repository の責務ではありません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eビジネス判断\u003c/li\u003e\n\u003cli\u003e状態遷移の決定\u003c/li\u003e\n\u003cli\u003eUI 表示の都合による変換\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eRepository が「判断」を持ち始めた瞬間、設計は濁り始めます。\u003c/p\u003e\n\u003cp\u003eたとえば、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこの場合はキャッシュを返す／返さない\u003c/li\u003e\n\u003cli\u003eこの条件なら空リストにする\u003c/li\u003e\n\u003cli\u003eエラーを成功として扱う\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった判断が Repository に入り込むと、「なぜそうなるのか」を追うのが非常に難しくなります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"repository-にロジックが集まりやすい理由\"\u003eRepository にロジックが集まりやすい理由\u003c/h3\u003e\n\u003cp\u003eRepository は、設計が崩れ始めたときに、もっともロジックが集まりやすい場所です。その理由は単純です。\u003c/p\u003e","title":"第7章：Repository はどこまで責務を持つべきか"},{"content":" Hilt は設計を良くもしないし悪くもしない DI 導入の本当の目的 モジュール分割による物理的制約 Module 地獄はなぜ起きるのか DI しなくていいものを見極める Repository と Hilt のちょうどいい距離感 BaseActivity / BaseViewModel を作らない理由 CompositionLocal を使った依存の渡し方 DI が設計を壊しているサイン この章のまとめ Hilt は設計を良くもしないし悪くもしない DI（Dependency Injection）や Hilt は、しばしば「設計を良くする魔法の道具」のように語られます。しかし、本書ではまずこの幻想をはっきり否定しておきます。\nHilt は、設計を良くもしないし、悪くもしない。\nHilt がやってくれるのは、\n依存関係の生成を肩代わりすること オブジェクトのライフサイクルを管理すること だけです。\n依存の向きが正しいか、責務が分離されているか、境界が妥当か──それらは Hilt では一切保証されません。むしろ、設計が曖昧なまま Hilt を使うと、その曖昧さがコード全体に固定されてしまいます。\nDI 導入の本当の目的 DI を導入する目的は、テスト容易性や疎結合化だと説明されることが多いですが、Android × DDD の文脈では、もう一つ重要な目的があります。\n「依存の方向」をコードとして固定すること\nViewModel は Domain に依存してよい Domain は Data に依存してはいけない Data は Domain を知らなくてよい この関係を、new ではなく DI によって表現することで、「間違った依存」を作りにくくなります。Hilt は、この構造を 楽に維持するための道具 です。\nモジュール分割による物理的制約 DI 導入するだけでは、間違った依存を制限することはできません。しかし、モジュール分割も合わせて導入することで、制限することができます。\nDDD × Android の構成では、多くの場合こうなっています。\ndomain/ - usecase - repository (interface) data/ - repository (implementation) - datasource このとき、\ndomain モジュールは data モジュールに 依存していない\nという Gradle 依存関係を組みます。\nその結果：\n// domain module class SomeUseCase { private val repo = RealRepository() // 参照できない } そもそもクラスが見えない import すらできない という構造になります。\nModule 地獄はなぜ起きるのか Hilt を使い始めると、多くのプロジェクトが Module 地獄に陥ります。\nRepository ごとに Module UseCase ごとに Module 実装クラス 1 つにつき @Binds 1 行 ファイルは増え、見通しは悪くなり、「DI のためのコード」が本体を侵食していきます。\nModule 地獄が起きる原因は、Hilt ではありません。\n責務の粒度が揃っていないまま、すべてを DI しようとすること\nが原因です。\nDI しなくていいものを見極める すべてを DI する必要はありません。むしろ、DI しない判断も重要な設計です。\nDI しなくてよい典型例は次のようなものです。\n純粋なデータ変換ロジック stateless な utility 画面専用で再利用されないクラス これらまで DI すると、依存関係の図は複雑になり、設計の意図が見えなくなります。\nDI は 境界を越える依存にだけ使う という意識を持つと、構造は一気にシンプルになります。\nRepository と Hilt のちょうどいい距離感 Repository は、Hilt と非常に相性がよい一方で、過剰に DI されがちな存在でもあります。\n本書が推奨するのは、次のような形です。\nRepository は interface として Domain 側に置く 実装は Data 側に置く Hilt Module は Data 側にまとめる こうすることで、\nDomain は実装を知らない DI 設定は Data に閉じる という境界が保たれます。\n逆に、Domain 側に Hilt のアノテーションや Module が入り込むと、その時点で境界は崩れ始めます。\nBaseActivity / BaseViewModel を作らない理由 DI や共通処理の導入をきっかけに、BaseActivity や BaseViewModel を作りたくなることがあります。\nしかし、この設計は次のような問題を引き起こしやすいです。\n継承ツリーが責務の混在を招く 「全部入り」ベースクラスが生まれる 差分実装がしづらくなる 本書では、継承ではなく 合成 を強く推奨します。\n共通処理はクラスとして切り出す 必要な画面だけがそれを保持する Hilt は、この合成を支えるための仕組みとして使うのが、最も健全です。\nCompositionLocal を使った依存の渡し方 Jetpack Compose では、Hilt 以外にも依存を渡す手段があります。その代表が CompositionLocal です。\nCompositionLocal は、\nUI ツリーに沿った依存の共有 画面スコープでの依存管理 に非常に向いています。\nすべてを Hilt で注入しようとするのではなく、\nアプリ全体の依存 → Hilt UI 階層に閉じた依存 → CompositionLocal と使い分けることで、依存構造はより自然になります。\nDI が設計を壊しているサイン 次のような状態になっていたら、DI が設計を壊し始めているサインです。\nModule を修正しないと何も追加できない 依存関係を追うだけで疲れる DI 設定が設計意図を説明できていない その場合は、一度立ち止まって「この依存は本当に境界を越える必要があるのか」を見直すべきです。\nこの章のまとめ DI・Hilt は、\n設計を表現するための道具であり 設計そのものではない という位置づけになります。\nAndroid × DDD においては、\n依存の方向を固定する 境界を壊さない DI しすぎない この 3 点を意識するだけで、Hilt は非常に心強い味方になります。\n次章では、実際の失敗例を通して、Android × DDD がどこで破綻しやすいのかを見ていきます。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/09/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003eHilt は設計を良くもしないし悪くもしない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eDI 導入の本当の目的\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eモジュール分割による物理的制約\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eModule 地獄はなぜ起きるのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eDI しなくていいものを見極める\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eRepository と Hilt のちょうどいい距離感\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#baseactivity--baseviewmodel-%E3%82%92%E4%BD%9C%E3%82%89%E3%81%AA%E3%81%84%E7%90%86%E7%94%B1\"\u003eBaseActivity / BaseViewModel を作らない理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eCompositionLocal を使った依存の渡し方\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eDI が設計を壊しているサイン\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"hilt-は設計を良くもしないし悪くもしない\"\u003eHilt は設計を良くもしないし悪くもしない\u003c/h3\u003e\n\u003cp\u003eDI（Dependency Injection）や Hilt は、しばしば「設計を良くする魔法の道具」のように語られます。しかし、本書ではまずこの幻想をはっきり否定しておきます。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHilt は、設計を良くもしないし、悪くもしない。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eHilt がやってくれるのは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e依存関係の生成を肩代わりすること\u003c/li\u003e\n\u003cli\u003eオブジェクトのライフサイクルを管理すること\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eだけです。\u003c/p\u003e\n\u003cp\u003e依存の向きが正しいか、責務が分離されているか、境界が妥当か──それらは Hilt では一切保証されません。むしろ、設計が曖昧なまま Hilt を使うと、その曖昧さがコード全体に固定されてしまいます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"di-導入の本当の目的\"\u003eDI 導入の本当の目的\u003c/h3\u003e\n\u003cp\u003eDI を導入する目的は、テスト容易性や疎結合化だと説明されることが多いですが、Android × DDD の文脈では、もう一つ重要な目的があります。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e「依存の方向」をコードとして固定すること\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eViewModel は Domain に依存してよい\u003c/li\u003e\n\u003cli\u003eDomain は Data に依存してはいけない\u003c/li\u003e\n\u003cli\u003eData は Domain を知らなくてよい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの関係を、new ではなく DI によって表現することで、「間違った依存」を作りにくくなります。Hilt は、この構造を \u003cem\u003e楽に維持するための道具\u003c/em\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"モジュール分割による物理的制約\"\u003eモジュール分割による物理的制約\u003c/h3\u003e\n\u003cp\u003eDI 導入するだけでは、間違った依存を制限することはできません。しかし、モジュール分割も合わせて導入することで、制限することができます。\u003c/p\u003e","title":"第8章：DI・Hilt と DDD の付き合い方"},{"content":" ルールとは「毎回同じ判断が必要になるもの」 UseCaseに書いてよいロジックとの違い UseCaseに置くべき判断 モデルに置くべきルール 「if文がある＝ルール」ではない ルールを閉じ込めると、何が楽になるのか ルールは「増え始めたら」閉じ込める この章のまとめ ここまでの章で、何度も「ルールをモデルに閉じ込める」という表現が出てきました。\nしかし実務では、ここが一番あいまいになりやすい部分でもあります。\n何をルールと呼ぶのか どこまでをモデルに入れるべきなのか UseCaseに書くのと何が違うのか この章では、それらを設計判断ができるレベルまで言語化します。\nルールとは「毎回同じ判断が必要になるもの」 DDDにおけるルールとは、難しいビジネスロジックのことではありません。\nもっと単純で、もっと地味なものです。\nどのユースケースから呼ばれても、同じ条件・同じ結果になる判断\nこれが、モデルに閉じ込めるべきルールです。\n例えば：\n金額は0円以上でなければならない 解約済みの契約は再度有効化できない この状態では次の操作に進めない これらは、\nどの画面から操作しても どのAPI経由で呼ばれても 常に守られていてほしい制約です。\nだからこそ、UseCaseに散らすのではなく、モデルに集約します。\nUseCaseに書いてよいロジックとの違い ここで、よくある疑問が出てきます。\nこの判断、UseCaseに書いてもよくない？\n答えは、場合によるです。\n判断の軸はシンプルです。\nその判断は「やりたいこと」に依存しているか それとも「概念そのもの」に依存しているか UseCaseに置くべき判断 A画面から来たときだけ許可する 今回は管理者なので例外的に通す この処理では警告だけ出して続行する これらは、\nユースケースの文脈に依存する判断\nです。\nモデルに入れると、かえって再利用性と可読性が下がります。\nモデルに置くべきルール 一方で、\n状態として成立しているか 概念として矛盾していないか を判断するロジックは、モデルの責務です。\nこのルールは、\n呼び出し元を知る必要がない 例外を作る理由がない という特徴を持ちます。\n「if文がある＝ルール」ではない ここで注意が必要です。\nモデルに if 文が増え始めると、\nこれは正しいDDDなのか？ モデルが太りすぎていないか？ と不安になることがあります。\nしかし、\nif 文があること自体は問題ではありません。\n問題なのは、その if 文が\nユースケースの都合 一時的な仕様 呼び出し元の事情 を知り始めたときです。\nモデル内の条件分岐は、\n概念の整合性を守るためのものか？\nこの一点で判断できます。\nルールを閉じ込めると、何が楽になるのか モデルにルールを集約すると、 次の変化が起きます。\nUseCaseが短くなる テストの粒度が自然に決まる 「なぜこの処理があるのか」を説明しやすくなる 特に大きいのは、\n仕様変更時に、直す場所が直感的に分かる\nことです。\n制約が変わった → モデル 流れが変わった → UseCase 技術が変わった → Repository この対応関係ができると、 設計は一気に壊れにくくなります。\nルールは「増え始めたら」閉じ込める ここでも、DDDは慎重です。\n最初から全部モデルに入れない 1回しか出てこない判断は様子を見る 同じ判断を2回書いたら、モデル化を検討する\nくらいの感覚が、実務ではちょうど良い。\nルールは、\n見え始め 繰り返され 変更され ながら育ちます。\nDDDは、それを後から安全に集約できる設計を目指します。\nこの章のまとめ この章で整理したことは、次の通りです。\nルールとは「毎回同じ判断が必要になるもの」 ユースケース依存の判断はモデルに入れない 概念の整合性を守る判断をモデルに閉じ込める モデルは、\n賢くある必要はありません 未来を予測する必要もありません ただ、\n同じことを何度も考えなくて済む場所\nであれば十分です。\n次の章では、ここまで積み上げてきた理解を踏まえ、 DDDを導入して失敗する典型パターンを整理していきます。\n失敗の構造が分かると、 設計の判断精度は一段上がります。\n","permalink":"https://design.okuda-studio.com/books/004-ddd/08/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%A8%E3%81%AF%E6%AF%8E%E5%9B%9E%E5%90%8C%E3%81%98%E5%88%A4%E6%96%AD%E3%81%8C%E5%BF%85%E8%A6%81%E3%81%AB%E3%81%AA%E3%82%8B%E3%82%82%E3%81%AE\"\u003eルールとは「毎回同じ判断が必要になるもの」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#usecase%E3%81%AB%E6%9B%B8%E3%81%84%E3%81%A6%E3%82%88%E3%81%84%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF%E3%81%A8%E3%81%AE%E9%81%95%E3%81%84\"\u003eUseCaseに書いてよいロジックとの違い\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#usecase%E3%81%AB%E7%BD%AE%E3%81%8F%E3%81%B9%E3%81%8D%E5%88%A4%E6%96%AD\"\u003eUseCaseに置くべき判断\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AB%E7%BD%AE%E3%81%8F%E3%81%B9%E3%81%8D%E3%83%AB%E3%83%BC%E3%83%AB\"\u003eモデルに置くべきルール\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#if%E6%96%87%E3%81%8C%E3%81%82%E3%82%8B%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003e「if文がある＝ルール」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%AB%E3%83%BC%E3%83%AB%E3%82%92%E9%96%89%E3%81%98%E8%BE%BC%E3%82%81%E3%82%8B%E3%81%A8%E4%BD%95%E3%81%8C%E6%A5%BD%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%AE%E3%81%8B\"\u003eルールを閉じ込めると、何が楽になるのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%AF%E5%A2%97%E3%81%88%E5%A7%8B%E3%82%81%E3%81%9F%E3%82%89%E9%96%89%E3%81%98%E8%BE%BC%E3%82%81%E3%82%8B\"\u003eルールは「増え始めたら」閉じ込める\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eここまでの章で、何度も「ルールをモデルに閉じ込める」という表現が出てきました。\u003c/p\u003e\n\u003cp\u003eしかし実務では、ここが一番あいまいになりやすい部分でもあります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e何をルールと呼ぶのか\u003c/li\u003e\n\u003cli\u003eどこまでをモデルに入れるべきなのか\u003c/li\u003e\n\u003cli\u003eUseCaseに書くのと何が違うのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの章では、それらを\u003cstrong\u003e設計判断ができるレベル\u003c/strong\u003eまで言語化します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"ルールとは毎回同じ判断が必要になるもの\"\u003eルールとは「毎回同じ判断が必要になるもの」\u003c/h2\u003e\n\u003cp\u003eDDDにおけるルールとは、難しいビジネスロジックのことではありません。\u003c/p\u003e\n\u003cp\u003eもっと単純で、もっと地味なものです。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eどのユースケースから呼ばれても、同じ条件・同じ結果になる判断\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eこれが、モデルに閉じ込めるべきルールです。\u003c/p\u003e\n\u003cp\u003e例えば：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e金額は0円以上でなければならない\u003c/li\u003e\n\u003cli\u003e解約済みの契約は再度有効化できない\u003c/li\u003e\n\u003cli\u003eこの状態では次の操作に進めない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどの画面から操作しても\u003c/li\u003e\n\u003cli\u003eどのAPI経由で呼ばれても\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e常に守られていてほしい制約\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp\u003eだからこそ、UseCaseに散らすのではなく、モデルに集約します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"usecaseに書いてよいロジックとの違い\"\u003eUseCaseに書いてよいロジックとの違い\u003c/h2\u003e\n\u003cp\u003eここで、よくある疑問が出てきます。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eこの判断、UseCaseに書いてもよくない？\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e答えは、\u003cstrong\u003e場合による\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp\u003e判断の軸はシンプルです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eその判断は「やりたいこと」に依存しているか\u003c/li\u003e\n\u003cli\u003eそれとも「概念そのもの」に依存しているか\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"usecaseに置くべき判断\"\u003eUseCaseに置くべき判断\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eA画面から来たときだけ許可する\u003c/li\u003e\n\u003cli\u003e今回は管理者なので例外的に通す\u003c/li\u003e\n\u003cli\u003eこの処理では警告だけ出して続行する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eユースケースの文脈に依存する判断\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003cp\u003eモデルに入れると、かえって再利用性と可読性が下がります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"モデルに置くべきルール\"\u003eモデルに置くべきルール\u003c/h3\u003e\n\u003cp\u003e一方で、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e状態として成立しているか\u003c/li\u003e\n\u003cli\u003e概念として矛盾していないか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを判断するロジックは、モデルの責務です。\u003c/p\u003e\n\u003cp\u003eこのルールは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e呼び出し元を知る必要がない\u003c/li\u003e\n\u003cli\u003e例外を作る理由がない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという特徴を持ちます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"if文があるルールではない\"\u003e「if文がある＝ルール」ではない\u003c/h2\u003e\n\u003cp\u003eここで注意が必要です。\u003c/p\u003e\n\u003cp\u003eモデルに if 文が増え始めると、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこれは正しいDDDなのか？\u003c/li\u003e\n\u003cli\u003eモデルが太りすぎていないか？\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eと不安になることがあります。\u003c/p\u003e\n\u003cp\u003eしかし、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eif 文があること自体は問題ではありません。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e問題なのは、その if 文が\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eユースケースの都合\u003c/li\u003e\n\u003cli\u003e一時的な仕様\u003c/li\u003e\n\u003cli\u003e呼び出し元の事情\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを知り始めたときです。\u003c/p\u003e","title":"第8章：モデルに閉じ込める「ルール」とは何か"},{"content":" Clean Architecture をそのまま持ち込んだ例 何が起きたか なぜ失敗したのか 何を学ぶべきか UseCase が 100 個を超えたプロジェクト 何が起きたか なぜ失敗したのか 何を学ぶべきか ドメイン層が util 層になった話 何が起きたか なぜ失敗したのか 何を学ぶべきか テストしやすいはずが、誰もテストを書かない構造 何が起きたか なぜ失敗したのか 何を学ぶべきか この章では、Android アプリに DDD の考え方を真面目に適用しようとしたときに、構造上起こりやすい失敗例を取り上げる。\nいずれも「考え方としては間違っていない」からこそ起きるものであり、設計を真剣に考えた結果として現れる。\nClean Architecture をそのまま持ち込んだ例 何が起きたか Web や書籍で学んだ Clean Architecture を、そのまま Android アプリに適用したプロジェクトでは、\npresentation / domain / data が厳密に分離され すべての依存は内側に向き あらゆる処理が UseCase を経由する という構造が作られた。\n構造としては美しく、レビューでも「設計は正しい」と評価されていた。しかし、実装が進むにつれて次のような問題が顕在化した。\nちょっとした画面修正でも複数レイヤーに修正が必要 UI 変更のたびに Domain 側の調整が発生 実装コストが高く、改善のスピードが落ちる なぜ失敗したのか Clean Architecture 自体が悪いのではない。問題は、Android アプリの特性を考慮せずに、そのまま当てはめたことにある。\nAndroid アプリでは、\nUI の変更頻度が高い 画面単位のロジックが多い 永続的な業務ルールが存在しないケースも多い にもかかわらず、すべてを「安定した Domain がある前提」で設計してしまったことで、構造が過剰になった。\n何を学ぶべきか Clean Architecture は 思想であって、実装テンプレートではない Android では「守りたい業務ルールがあるか」を先に見極める UseCase が 100 個を超えたプロジェクト 何が起きたか DDD を意識して「1 ユースケース = 1 クラス」を徹底した結果、UseCase クラスが 100 個を超えたプロジェクトがあった。\n画面ごとに UseCase ボタン操作ごとに UseCase 初期表示・更新・削除で別 UseCase 結果として、\nパッケージを見ても全体像が分からない 似たような UseCase が大量に存在する 新しい実装時にどこに追加すべきか迷う という状態に陥った。\nなぜ失敗したのか UseCase を「処理の単位」ではなく「クラスを作るルール」として扱ってしまったことが原因である。\n本来 UseCase は、\nアプリケーションとして意味のある操作 業務的な判断を伴う処理 を表現するための概念だ。単なる CRUD や画面操作まで UseCase 化したことで、構造がノイズに埋もれてしまった。\n何を学ぶべきか UseCase は 増やすものではなく、選ぶもの 「これは本当に業務的な判断か？」を問い続ける ドメイン層が util 層になった話 何が起きたか Domain 層を Android 非依存に保とうとした結果、\nフォーマット変換 バリデーション 並び替えロジック といった処理がすべて Domain に集約された。\n一見すると Domain は純粋でテストもしやすい。しかし実態は、\nどの処理が業務ルールなのか分からない 画面都合のロジックも Domain に存在する という 巨大な util 層 になっていた。\nなぜ失敗したのか 「Android に依存していない = Domain」という短絡的な判断が原因である。\nDomain 層は、\n業務上の意味 ルール 制約 を表現する場所であって、「置き場所に困ったロジック置き場」ではない。\n何を学ぶべきか Domain に置く基準は 技術ではなく意味 業務的な意味を説明できない処理は、Domain 以外に置く テストしやすいはずが、誰もテストを書かない構造 何が起きたか DI と DDD を導入し、\n依存はすべて interface 経由 Domain は純 Kotlin モックも簡単 という「テストしやすい構造」が完成した。\nしかし現実には、\nテストコードはほとんど書かれない 書かれてもメンテされない という状態だった。\nなぜ失敗したのか 構造としてテスト可能であることと、テストを書く動機があることは別であるためだ。\nUseCase が細かすぎてテストの価値が低い テストを書いても仕様変更ですぐ壊れる 何を守るテストなのか分からない こうした状況では、誰もテストを書き続けられない。\n何を学ぶべきか テストしやすさは 目的ではなく手段 「何を守りたいのか」を先に決めないと、テストは定着しない 本章で紹介した失敗例は、どれも「設計を良くしよう」とした結果として起きている。だからこそ重要なのは、\n型や構造を整えることよりも 判断基準を共有すること である。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/10/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003eClean Architecture をそのまま持ち込んだ例\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BD%95%E3%81%8C%E8%B5%B7%E3%81%8D%E3%81%9F%E3%81%8B\"\u003e何が起きたか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eなぜ失敗したのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BD%95%E3%82%92%E5%AD%A6%E3%81%B6%E3%81%B9%E3%81%8D%E3%81%8B\"\u003e何を学ぶべきか\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eUseCase が 100 個を超えたプロジェクト\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BD%95%E3%81%8C%E8%B5%B7%E3%81%8D%E3%81%9F%E3%81%8B-1\"\u003e何が起きたか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eなぜ失敗したのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BD%95%E3%82%92%E5%AD%A6%E3%81%B6%E3%81%B9%E3%81%8D%E3%81%8B-1\"\u003e何を学ぶべきか\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eドメイン層が util 層になった話\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BD%95%E3%81%8C%E8%B5%B7%E3%81%8D%E3%81%9F%E3%81%8B-2\"\u003e何が起きたか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eなぜ失敗したのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BD%95%E3%82%92%E5%AD%A6%E3%81%B6%E3%81%B9%E3%81%8D%E3%81%8B-2\"\u003e何を学ぶべきか\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eテストしやすいはずが、誰もテストを書かない構造\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BD%95%E3%81%8C%E8%B5%B7%E3%81%8D%E3%81%9F%E3%81%8B-3\"\u003e何が起きたか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eなぜ失敗したのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BD%95%E3%82%92%E5%AD%A6%E3%81%B6%E3%81%B9%E3%81%8D%E3%81%8B-3\"\u003e何を学ぶべきか\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eこの章では、Android アプリに DDD の考え方を真面目に適用しようとしたときに、構造上起こりやすい失敗例を取り上げる。\u003c/p\u003e\n\u003cp\u003eいずれも「考え方としては間違っていない」からこそ起きるものであり、設計を真剣に考えた結果として現れる。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"clean-architecture-をそのまま持ち込んだ例\"\u003eClean Architecture をそのまま持ち込んだ例\u003c/h2\u003e\n\u003ch3 id=\"何が起きたか\"\u003e何が起きたか\u003c/h3\u003e\n\u003cp\u003eWeb や書籍で学んだ Clean Architecture を、そのまま Android アプリに適用したプロジェクトでは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003epresentation / domain / data が厳密に分離され\u003c/li\u003e\n\u003cli\u003eすべての依存は内側に向き\u003c/li\u003e\n\u003cli\u003eあらゆる処理が UseCase を経由する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという構造が作られた。\u003c/p\u003e\n\u003cp\u003e構造としては美しく、レビューでも「設計は正しい」と評価されていた。しかし、実装が進むにつれて次のような問題が顕在化した。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eちょっとした画面修正でも複数レイヤーに修正が必要\u003c/li\u003e\n\u003cli\u003eUI 変更のたびに Domain 側の調整が発生\u003c/li\u003e\n\u003cli\u003e実装コストが高く、改善のスピードが落ちる\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"なぜ失敗したのか\"\u003eなぜ失敗したのか\u003c/h3\u003e\n\u003cp\u003eClean Architecture 自体が悪いのではない。問題は、\u003cstrong\u003eAndroid アプリの特性を考慮せずに、そのまま当てはめたこと\u003c/strong\u003eにある。\u003c/p\u003e\n\u003cp\u003eAndroid アプリでは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUI の変更頻度が高い\u003c/li\u003e\n\u003cli\u003e画面単位のロジックが多い\u003c/li\u003e\n\u003cli\u003e永続的な業務ルールが存在しないケースも多い\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eにもかかわらず、すべてを「安定した Domain がある前提」で設計してしまったことで、構造が過剰になった。\u003c/p\u003e","title":"第9章：Android × DDD で起こりやすい設計の落とし穴"},{"content":" 失敗パターン1：最初から「正しいDDD」をやろうとする 失敗パターン2：用語を揃えずにコードだけDDDにする 失敗パターン3：UseCaseを薄くしすぎる 失敗パターン4：モデルにルールを閉じ込めすぎる 失敗パターン5：DDDを全体に一律適用する 失敗パターン6：「DDDっぽさ」を評価軸にする この章のまとめ ここまでの章で、DDDが「何を大切にしているか」はかなり明確になってきたはずです。\nそれでもなお、DDDは失敗します。 しかもその多くは、\n理解不足 技術力不足 ではありません。\n「DDDをやろうとしたから」失敗する\nこの章では、実務で本当によく見かけるDDDの失敗パターンを整理します。\n失敗例を知ることは、 正解例を増やすよりも、ずっと設計判断の精度を上げてくれます。\n失敗パターン1：最初から「正しいDDD」をやろうとする 最も多く、最も破壊力のある失敗です。\nEntity / Value Object を最初から作り込む Aggregate を先に決める Repository をすべて interface に切る 設計としては「教科書的」に見えます。\nしかし実務では、\nルールがまだ分からない 境界もまだ曖昧 将来の変更も見えていない この状態で完成形を目指すと、\n想定外の変更に耐えられない設計\nが出来上がります。\nDDDは「完成形から逆算する設計」ではありません。 変化し始めたところに追従する設計です。\n失敗パターン2：用語を揃えずにコードだけDDDにする DDDの中核にあるのは、コードではなく言葉です。\nそれにもかかわらず、\nクラス名だけDDDっぽい メソッド名がユースケースとズレている チーム内で同じ概念を別の言葉で呼んでいる こうした状態でDDDを導入すると、\n見た目はDDD、中身はカオス\nになります。\n言葉が揃っていない設計は、\nレビューで揉める 仕様変更の議論が噛み合わない という形で、確実に破綻します。\n失敗パターン3：UseCaseを薄くしすぎる 「UseCaseは薄くあるべき」という言葉が、 誤って伝わると起きる失敗です。\nUseCaseがRepositoryを呼ぶだけ 判断はすべてモデルに押し込む 一見きれいですが、\n処理の流れが追えない どこで何が起きているか分からない 状態になります。\nUseCaseは、\nやりたいことの物語を書く場所\nです。\n薄くする対象は「責務」であって、 存在感そのものではありません。\n失敗パターン4：モデルにルールを閉じ込めすぎる 第8章で述べた内容の裏返しです。\n画面固有の判断 一時的な仕様 今回だけの例外 こうしたロジックまでモデルに入れると、\nモデルが巨大化する 変更が怖くなる 結果として、\n「触れないモデル」\nが生まれます。\nモデルは、\n概念の整合性を守る場所 であって、\nすべての判断を引き受ける場所 ではありません。\n失敗パターン5：DDDを全体に一律適用する これも非常によくある失敗です。\nすべての画面 すべての機能 すべてのCRUD にDDDを適用しようとする。\n結果として、\n開発速度が落ちる 学習コストが爆発する チームが疲弊する DDDは、\n壊れたら困るところにだけ使う設計\nです。\n割り切りのないDDDは、 プロジェクトを壊します。\n失敗パターン6：「DDDっぽさ」を評価軸にする レビューで、こんな言葉が出始めたら危険信号です。\nそれDDDっぽくないよね もっとドメイン寄りにすべきでは？ この評価軸は、\n設計を宗教に変える\n力を持っています。\nDDDの評価軸は、ただ一つです。\n変更が入ったときに助けてくれるか それ以外の指標は、 すべて二次的です。\nこの章のまとめ DDDの失敗は、\n技術が足りないから 知識が足りないから 起きるのではありません。\n多くの場合、\n真面目にやりすぎた結果\nとして起きます。\nDDDは、\n厳密である必要はありません 完璧である必要もありません ただ、\n変化に備えるための考え方\nであり続けること。\nそれを忘れなければ、 DDDは必ず実務の味方になります。\n次の章では、 ここまでの理解を踏まえたうえで、 「ではDDDをどう学び、どう付き合っていくか」 という、より長期的な視点に進みます。\n","permalink":"https://design.okuda-studio.com/books/004-ddd/09/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A4%B1%E6%95%97%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B31%E6%9C%80%E5%88%9D%E3%81%8B%E3%82%89%E6%AD%A3%E3%81%97%E3%81%84ddd%E3%82%92%E3%82%84%E3%82%8D%E3%81%86%E3%81%A8%E3%81%99%E3%82%8B\"\u003e失敗パターン1：最初から「正しいDDD」をやろうとする\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A4%B1%E6%95%97%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B32%E7%94%A8%E8%AA%9E%E3%82%92%E6%8F%83%E3%81%88%E3%81%9A%E3%81%AB%E3%82%B3%E3%83%BC%E3%83%89%E3%81%A0%E3%81%91ddd%E3%81%AB%E3%81%99%E3%82%8B\"\u003e失敗パターン2：用語を揃えずにコードだけDDDにする\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A4%B1%E6%95%97%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B33usecase%E3%82%92%E8%96%84%E3%81%8F%E3%81%97%E3%81%99%E3%81%8E%E3%82%8B\"\u003e失敗パターン3：UseCaseを薄くしすぎる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A4%B1%E6%95%97%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B34%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AB%E3%83%AB%E3%83%BC%E3%83%AB%E3%82%92%E9%96%89%E3%81%98%E8%BE%BC%E3%82%81%E3%81%99%E3%81%8E%E3%82%8B\"\u003e失敗パターン4：モデルにルールを閉じ込めすぎる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A4%B1%E6%95%97%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B35ddd%E3%82%92%E5%85%A8%E4%BD%93%E3%81%AB%E4%B8%80%E5%BE%8B%E9%81%A9%E7%94%A8%E3%81%99%E3%82%8B\"\u003e失敗パターン5：DDDを全体に一律適用する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A4%B1%E6%95%97%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B36ddd%E3%81%A3%E3%81%BD%E3%81%95%E3%82%92%E8%A9%95%E4%BE%A1%E8%BB%B8%E3%81%AB%E3%81%99%E3%82%8B\"\u003e失敗パターン6：「DDDっぽさ」を評価軸にする\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eここまでの章で、DDDが「何を大切にしているか」はかなり明確になってきたはずです。\u003c/p\u003e\n\u003cp\u003eそれでもなお、DDDは失敗します。\nしかもその多くは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e理解不足\u003c/li\u003e\n\u003cli\u003e技術力不足\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eではありません。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e「DDDをやろうとしたから」失敗する\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eこの章では、実務で本当によく見かけるDDDの失敗パターンを整理します。\u003c/p\u003e\n\u003cp\u003e失敗例を知ることは、\n正解例を増やすよりも、ずっと設計判断の精度を上げてくれます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"失敗パターン1最初から正しいdddをやろうとする\"\u003e失敗パターン1：最初から「正しいDDD」をやろうとする\u003c/h2\u003e\n\u003cp\u003e最も多く、最も破壊力のある失敗です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEntity / Value Object を最初から作り込む\u003c/li\u003e\n\u003cli\u003eAggregate を先に決める\u003c/li\u003e\n\u003cli\u003eRepository をすべて interface に切る\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e設計としては「教科書的」に見えます。\u003c/p\u003e\n\u003cp\u003eしかし実務では、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eルールがまだ分からない\u003c/li\u003e\n\u003cli\u003e境界もまだ曖昧\u003c/li\u003e\n\u003cli\u003e将来の変更も見えていない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの状態で完成形を目指すと、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e想定外の変更に耐えられない設計\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eが出来上がります。\u003c/p\u003e\n\u003cp\u003eDDDは「完成形から逆算する設計」ではありません。\n\u003cstrong\u003e変化し始めたところに追従する設計\u003c/strong\u003eです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"失敗パターン2用語を揃えずにコードだけdddにする\"\u003e失敗パターン2：用語を揃えずにコードだけDDDにする\u003c/h2\u003e\n\u003cp\u003eDDDの中核にあるのは、コードではなく言葉です。\u003c/p\u003e\n\u003cp\u003eそれにもかかわらず、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eクラス名だけDDDっぽい\u003c/li\u003e\n\u003cli\u003eメソッド名がユースケースとズレている\u003c/li\u003e\n\u003cli\u003eチーム内で同じ概念を別の言葉で呼んでいる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうした状態でDDDを導入すると、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e見た目はDDD、中身はカオス\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eになります。\u003c/p\u003e\n\u003cp\u003e言葉が揃っていない設計は、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eレビューで揉める\u003c/li\u003e\n\u003cli\u003e仕様変更の議論が噛み合わない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという形で、確実に破綻します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"失敗パターン3usecaseを薄くしすぎる\"\u003e失敗パターン3：UseCaseを薄くしすぎる\u003c/h2\u003e\n\u003cp\u003e「UseCaseは薄くあるべき」という言葉が、\n誤って伝わると起きる失敗です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUseCaseがRepositoryを呼ぶだけ\u003c/li\u003e\n\u003cli\u003e判断はすべてモデルに押し込む\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e一見きれいですが、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e処理の流れが追えない\u003c/li\u003e\n\u003cli\u003eどこで何が起きているか分からない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e状態になります。\u003c/p\u003e\n\u003cp\u003eUseCaseは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eやりたいことの物語を書く場所\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003cp\u003e薄くする対象は「責務」であって、\n\u003cstrong\u003e存在感そのものではありません\u003c/strong\u003e。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"失敗パターン4モデルにルールを閉じ込めすぎる\"\u003e失敗パターン4：モデルにルールを閉じ込めすぎる\u003c/h2\u003e\n\u003cp\u003e第8章で述べた内容の裏返しです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e画面固有の判断\u003c/li\u003e\n\u003cli\u003e一時的な仕様\u003c/li\u003e\n\u003cli\u003e今回だけの例外\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうしたロジックまでモデルに入れると、\u003c/p\u003e","title":"第9章：DDD を導入して失敗する典型パターン"},{"content":" DDDは「分かった瞬間」より「ズレに気づく瞬間」に伸びる 本を読むときは「答え」を探さない 現場は「DDDの教材」である チームでDDDを使うときの距離感 「困りごとを一緒に解決するための共通言語」とは DDDから離れる勇気も必要 この章のまとめ ここまで読み進めてきた読者は、もう気づいているはずです。\nDDDは、\n手法ではない フレームワークでもない チェックリストでもない ということに。\nDDDは、設計との向き合い方そのものです。\nだからこそ、\n一度学んで終わり\nという関係にはなりません。\nこの章では、DDDを\nどう学び続けるのか どう距離感を保つのか どうやって実務に持ち込むのか という、長期的な付き合い方を整理します。\nDDDは「分かった瞬間」より「ズレに気づく瞬間」に伸びる DDDを学び始めたとき、多くの人は\nEntityとValue Objectの違い Repositoryの役割 Aggregateの境界 といった概念理解に力を注ぎます。\nそれ自体は必要です。\nしかし、本当に設計力が伸びるのは、\n「あれ？この設計、どこかおかしいぞ」\nと感じた瞬間です。\n修正が怖い 変更の影響範囲が読めない なぜこうなっているのか説明できない こうした違和感を\n見過ごさない 言語化しようとする ことが、DDDの学習そのものです。\n本を読むときは「答え」を探さない DDD関連の書籍や記事は、\n厳密で 理論的で 完成度が高い ものが多くあります。\nしかし、それを\nそのまま現場に当てはめよう\nとすると、ほぼ確実に失敗します。\n本から得るべきなのは、\n設計の完成形 ではなく、\nなぜその判断に至ったのか\nという思考の軌跡です。\n設計書ではなく、 設計者の思考を読む。\nこれがDDD本との正しい付き合い方です。\n現場は「DDDの教材」である DDDを学ぶ上で、 最も優れた教材は何か。\nそれは、\n自分たちのコード\nです。\nなぜこのクラスは太ったのか なぜこのUseCaseは触りにくいのか なぜこの変更はこんなに大変だったのか これらはすべて、\n境界の引き方 ルールの置き場所 言葉の選び方 についてのヒントを含んでいます。\nDDDは、\n新しいコードを書くための理論 だけではなく、\n既存コードを読み解くためのレンズ でもあります。\nチームでDDDを使うときの距離感 DDDは、\n個人で完結しない チームで共有されて初めて効く という特徴があります。\nだからこそ、\n用語を強制しない いきなり全体に適用しない 「DDDだから正しい」と言わない この姿勢が重要です。\nDDDは自分の主張を押し通すための道具ではありません。\n困りごとを一緒に解決するための共通言語\nとして使われるとき、最も力を発揮します。\n「困りごとを一緒に解決するための共通言語」とは DDD の解説本では、 DDD を「困りごとを一緒に解決するための共通言語」であると表現されることが多いです。これは、\n正しさを主張するための言葉 設計を押し通すための用語 ではなく、\nいま何が困っていて、なぜそれがつらいのかを共有するための言葉\nを指しています。\n「この処理、どこにルールを置けばいいかわからない」 「この変更、どこまで影響するのか誰も説明できない」\nこうした困りごとを、\nドメインの言葉 モデル 境界 といった概念を使って整理できるようになる。\nそして、思考のプロセスを言語化して共有できる。\nその結果として、\n「じゃあ、ここに閉じ込めよう」 「これはまだUseCaseでいいね」\nという会話が自然に生まれます。\nDDDが共通言語になるとは、\n結論を揃えることではなく、 悩み方のプロセスを揃えること\nなのです。\nDDDから離れる勇気も必要 少し意外かもしれませんが、 DDDをうまく使っている人ほど、\nDDDをやめる判断 あえて単純に書く選択 を自然に行っています。\nルールが増えなかった 変更も少なかった 重要度が低かった そう判断したなら、\nそれ以上DDDを深めない\nという選択は、 設計として正しい。\nDDDは目的ではありません。\n楽に変更できる状態を作るための手段\nです。\nこの章のまとめ DDDとの良い付き合い方は、\n完璧を目指さない 信仰しない 疑い続ける ことです。\nなぜこの設計にしたのか どこが壊れやすそうか 次に変わるとしたらどこか こうした問いを、\nコードに対して投げ続ける\nそれがDDDの学習であり、 DDDの実践です。\nここまで読み進めたあなたは、 もう「DDDを学び始める準備」ができています。\nこの本が、\n設計と長く、健全に付き合っていくための 一つの視点\nとして役に立てば幸いです。\n","permalink":"https://design.okuda-studio.com/books/004-ddd/10/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#ddd%E3%81%AF%E5%88%86%E3%81%8B%E3%81%A3%E3%81%9F%E7%9E%AC%E9%96%93%E3%82%88%E3%82%8A%E3%82%BA%E3%83%AC%E3%81%AB%E6%B0%97%E3%81%A5%E3%81%8F%E7%9E%AC%E9%96%93%E3%81%AB%E4%BC%B8%E3%81%B3%E3%82%8B\"\u003eDDDは「分かった瞬間」より「ズレに気づく瞬間」に伸びる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9C%AC%E3%82%92%E8%AA%AD%E3%82%80%E3%81%A8%E3%81%8D%E3%81%AF%E7%AD%94%E3%81%88%E3%82%92%E6%8E%A2%E3%81%95%E3%81%AA%E3%81%84\"\u003e本を読むときは「答え」を探さない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8F%BE%E5%A0%B4%E3%81%AFddd%E3%81%AE%E6%95%99%E6%9D%90%E3%81%A7%E3%81%82%E3%82%8B\"\u003e現場は「DDDの教材」である\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%81%E3%83%BC%E3%83%A0%E3%81%A7ddd%E3%82%92%E4%BD%BF%E3%81%86%E3%81%A8%E3%81%8D%E3%81%AE%E8%B7%9D%E9%9B%A2%E6%84%9F\"\u003eチームでDDDを使うときの距離感\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%9B%B0%E3%82%8A%E3%81%94%E3%81%A8%E3%82%92%E4%B8%80%E7%B7%92%E3%81%AB%E8%A7%A3%E6%B1%BA%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E5%85%B1%E9%80%9A%E8%A8%80%E8%AA%9E%E3%81%A8%E3%81%AF\"\u003e「困りごとを一緒に解決するための共通言語」とは\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ddd%E3%81%8B%E3%82%89%E9%9B%A2%E3%82%8C%E3%82%8B%E5%8B%87%E6%B0%97%E3%82%82%E5%BF%85%E8%A6%81\"\u003eDDDから離れる勇気も必要\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eここまで読み進めてきた読者は、もう気づいているはずです。\u003c/p\u003e\n\u003cp\u003eDDDは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e手法ではない\u003c/li\u003e\n\u003cli\u003eフレームワークでもない\u003c/li\u003e\n\u003cli\u003eチェックリストでもない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eということに。\u003c/p\u003e\n\u003cp\u003eDDDは、\u003cstrong\u003e設計との向き合い方そのもの\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp\u003eだからこそ、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e一度学んで終わり\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eという関係にはなりません。\u003c/p\u003e\n\u003cp\u003eこの章では、DDDを\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどう学び続けるのか\u003c/li\u003e\n\u003cli\u003eどう距離感を保つのか\u003c/li\u003e\n\u003cli\u003eどうやって実務に持ち込むのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという、\u003cstrong\u003e長期的な付き合い方\u003c/strong\u003eを整理します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"dddは分かった瞬間よりズレに気づく瞬間に伸びる\"\u003eDDDは「分かった瞬間」より「ズレに気づく瞬間」に伸びる\u003c/h2\u003e\n\u003cp\u003eDDDを学び始めたとき、多くの人は\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEntityとValue Objectの違い\u003c/li\u003e\n\u003cli\u003eRepositoryの役割\u003c/li\u003e\n\u003cli\u003eAggregateの境界\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった概念理解に力を注ぎます。\u003c/p\u003e\n\u003cp\u003eそれ自体は必要です。\u003c/p\u003e\n\u003cp\u003eしかし、本当に設計力が伸びるのは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e「あれ？この設計、どこかおかしいぞ」\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eと感じた瞬間です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e修正が怖い\u003c/li\u003e\n\u003cli\u003e変更の影響範囲が読めない\u003c/li\u003e\n\u003cli\u003eなぜこうなっているのか説明できない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうした違和感を\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e見過ごさない\u003c/li\u003e\n\u003cli\u003e言語化しようとする\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eことが、DDDの学習そのものです。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"本を読むときは答えを探さない\"\u003e本を読むときは「答え」を探さない\u003c/h2\u003e\n\u003cp\u003eDDD関連の書籍や記事は、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e厳密で\u003c/li\u003e\n\u003cli\u003e理論的で\u003c/li\u003e\n\u003cli\u003e完成度が高い\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eものが多くあります。\u003c/p\u003e\n\u003cp\u003eしかし、それを\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eそのまま現場に当てはめよう\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eとすると、ほぼ確実に失敗します。\u003c/p\u003e\n\u003cp\u003e本から得るべきなのは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e設計の完成形\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eではなく、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eなぜその判断に至ったのか\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eという思考の軌跡です。\u003c/p\u003e\n\u003cp\u003e設計書ではなく、\n\u003cstrong\u003e設計者の思考を読む\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003eこれがDDD本との正しい付き合い方です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"現場はdddの教材である\"\u003e現場は「DDDの教材」である\u003c/h2\u003e\n\u003cp\u003eDDDを学ぶ上で、\n最も優れた教材は何か。\u003c/p\u003e\n\u003cp\u003eそれは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e自分たちのコード\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eなぜこのクラスは太ったのか\u003c/li\u003e\n\u003cli\u003eなぜこのUseCaseは触りにくいのか\u003c/li\u003e\n\u003cli\u003eなぜこの変更はこんなに大変だったのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらはすべて、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e境界の引き方\u003c/li\u003e\n\u003cli\u003eルールの置き場所\u003c/li\u003e\n\u003cli\u003e言葉の選び方\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eについてのヒントを含んでいます。\u003c/p\u003e","title":"第10章：DDD をどう学び、どう付き合っていくか"},{"content":" DDD は「最初から完成させるもの」ではない いきなりドメイン層を作らない 境界を 1 箇所だけ決める 言葉を揃えるところから始める リファクタリング前提の設計 小さく始めた DDD は、あとから育てられる この章のまとめ DDD は「最初から完成させるもの」ではない DDD という言葉には、どうしても「最初にきれいな構造を作らなければならない」という印象がつきまといます。\nドメイン層を用意する UseCase を定義する Repository を抽象化する Entity を厳密に設計する これらを 一気に やろうとした瞬間、設計は重くなります。 そして多くの場合、その重さに耐えきれず、DDD は「途中で放置される構造」になります。\n本書が提案する DDD の始め方は、その逆です。\n最初から正解を作らない。 あとで壊す前提で、小さく置く。\nいきなりドメイン層を作らない DDD を始めようとすると、真っ先にやりたくなるのが「domain パッケージを作ること」です。 しかし、これはもっとも失敗しやすい第一歩でもあります。\n理由は単純です。\n何がドメインなのか、まだ分かっていない どこが変わりやすいか、まだ見えていない 判断とロジックがどこに集まるか、まだ確信がない この状態でドメイン層を作ると、そこはすぐに “よく分からないコード置き場” になります。\n本書では、次のような始め方を推奨します。\nまずは ViewModel と Repository だけで作る 判断ロジックを「ここ怪しいな」と思う場所に集める それが固まり始めたら、初めて「ここがドメインだ」と名付ける ドメインは作るものではなく、浮かび上がってくるもの です。\n境界を 1 箇所だけ決める DDD を導入しようとすると、つい「すべての境界を正しく引こう」としてしまいます。\nUI と Domain Domain と Data UseCase と Repository Entity と Model しかし、最初から全部やる必要はありません。\n最初にやるべきことは、たった一つです。\n「ここだけは守る」という境界を 1 箇所だけ決めること\nたとえば、\nRepository に判断を書かない ViewModel にビジネスルールを書かない UI から DataSource を直接触らない どれでも構いません。\n重要なのは、境界の数ではなく、理由が説明できるかどうか です。\n1 箇所でも「ここを越えない」と決められると、設計は自然と整理され始めます。\n言葉を揃えるところから始める DDD というと、クラス設計やパッケージ構成に意識が向きがちですが、もっと簡単で、もっと効果的な入り口があります。\nそれが 言葉を揃えること です。\nこの「状態」は何を指しているのか 「有効」と「利用可能」は同じ意味か 「未設定」と「空」はどう違うのか これらが曖昧なまま実装が進むと、どんなに構造を整えても設計は崩れます。\n逆に言えば、\n仕様書 会話 コメント 変数名 ここで使われる言葉が揃ってくると、設計は勝手にそれっぽい形になります。\nDDD はコードを書く前から始まっています。 そして、言葉を揃えるのは、もっともコストが低く、効果が高い第一歩です。\nリファクタリング前提の設計 本書で一貫している前提があります。\nAndroid アプリの設計は、必ず後から壊される。\n仕様は変わる UI は変わる API は変わる 優先度も変わる この現実を無視して「完成形」を目指すと、設計はすぐに破綻します。\nだからこそ、本書では次の姿勢を強く推奨します。\n最初は雑でもいい でも、意図は残す 壊すときに理由を説明できる構造にする リファクタリング前提で設計するというのは、「いい加減に作る」ことではありません。\n「どこを壊すかが分かるように作る」 ということです。\n小さく始めた DDD は、あとから育てられる DDD は、一度導入に失敗すると「もう二度とやりたくないもの」になりがちです。 その多くは、最初からやりすぎたことが原因です。\n型を揃えすぎた 層を作りすぎた 将来を考えすぎた 本書が勧めるのは、その真逆です。\nまず 1 箇所だけ守る 言葉を揃える 判断が集まったら名前をつける この順序で始めた DDD は、途中で投げたくならない し、 必要になったときにだけ、自然に拡張できます。\nこの章のまとめ DDD を Android に持ち込むときに、もっとも重要なのは、\n小さく始めること 最初から正解を求めないこと 壊す前提で作ること です。\nDDD は、導入した瞬間に価値を生むものではありません。 変更が起きたときに、初めて差が出る設計思想 です。\n次章では、ここまでの考え方を踏まえた上で、 「DDD を 採用していると言える状態 とは何か」 を実例を通して確認していきます。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/11/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003eDDD は「最初から完成させるもの」ではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eいきなりドメイン層を作らない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003e境界を 1 箇所だけ決める\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003e言葉を揃えるところから始める\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eリファクタリング前提の設計\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003e小さく始めた DDD は、あとから育てられる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"ddd-は最初から完成させるものではない\"\u003eDDD は「最初から完成させるもの」ではない\u003c/h3\u003e\n\u003cp\u003eDDD という言葉には、どうしても「最初にきれいな構造を作らなければならない」という印象がつきまといます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eドメイン層を用意する\u003c/li\u003e\n\u003cli\u003eUseCase を定義する\u003c/li\u003e\n\u003cli\u003eRepository を抽象化する\u003c/li\u003e\n\u003cli\u003eEntity を厳密に設計する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらを \u003cem\u003e一気に\u003c/em\u003e やろうとした瞬間、設計は重くなります。\nそして多くの場合、その重さに耐えきれず、DDD は「途中で放置される構造」になります。\u003c/p\u003e\n\u003cp\u003e本書が提案する DDD の始め方は、その逆です。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e最初から正解を作らない。\nあとで壊す前提で、小さく置く。\u003c/strong\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"いきなりドメイン層を作らない\"\u003eいきなりドメイン層を作らない\u003c/h3\u003e\n\u003cp\u003eDDD を始めようとすると、真っ先にやりたくなるのが「domain パッケージを作ること」です。\nしかし、これはもっとも失敗しやすい第一歩でもあります。\u003c/p\u003e\n\u003cp\u003e理由は単純です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e何がドメインなのか、まだ分かっていない\u003c/li\u003e\n\u003cli\u003eどこが変わりやすいか、まだ見えていない\u003c/li\u003e\n\u003cli\u003e判断とロジックがどこに集まるか、まだ確信がない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの状態でドメイン層を作ると、そこはすぐに \u003cstrong\u003e“よく分からないコード置き場”\u003c/strong\u003e になります。\u003c/p\u003e\n\u003cp\u003e本書では、次のような始め方を推奨します。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eまずは ViewModel と Repository だけで作る\u003c/li\u003e\n\u003cli\u003e判断ロジックを「ここ怪しいな」と思う場所に集める\u003c/li\u003e\n\u003cli\u003eそれが固まり始めたら、初めて「ここがドメインだ」と名付ける\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eドメインは作るものではなく、浮かび上がってくるもの\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"境界を-1-箇所だけ決める\"\u003e境界を 1 箇所だけ決める\u003c/h3\u003e\n\u003cp\u003eDDD を導入しようとすると、つい「すべての境界を正しく引こう」としてしまいます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUI と Domain\u003c/li\u003e\n\u003cli\u003eDomain と Data\u003c/li\u003e\n\u003cli\u003eUseCase と Repository\u003c/li\u003e\n\u003cli\u003eEntity と Model\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eしかし、最初から全部やる必要はありません。\u003c/p\u003e","title":"第10章：小さく始める DDD"},{"content":" DDDは「正解集」ではなかった モデルとは「ルールを閉じ込める場所」だった Repositoryは「境界の翻訳者」だった DDDは「チームで悩むための言語」だった DDDは「使わない判断」も含んでいる おわりに この本を通して、DDDについて多くの言葉が登場しました。\nEntity Value Object Repository UseCase 境界 モデル 共通言語 しかし、ここで一度立ち止まって確認したいことがあります。\nこの本が本当に伝えたかったのは、\nこれらの言葉そのものではない\nという点です。\n最終章では、これまでの内容を振り返りながら、 DDDとどう付き合っていくとよいのかを、改めて整理します。\nDDDは「正解集」ではなかった 第一章から一貫して述べてきた通り、DDDは\n正解を与える設計論 そのまま使える設計テンプレート ではありません。\nむしろDDDは、\n設計について考え続けるための視点の集合\nです。\nなぜここに置いたのか なぜこの責務は重く感じるのか なぜこの変更が怖いのか そうした問いを、 曖昧な感覚のままにせず、 言葉として扱えるようにする。\nそれがDDDの本質でした。\nモデルとは「ルールを閉じ込める場所」だった 本書では何度も、\nEntityかVOか どこからモデルにするか という話題が出てきました。\nしかし、結論はとてもシンプルです。\nモデルとは、守りたいルールを閉じ込めるための器\nです。\n変わってほしくない振る舞い 破られると困る制約 他の場所に漏れると危険な判断 それらが見え始めたとき、 初めてモデルは意味を持ちます。\n最初から立派なモデルを作る必要はありません。\n必要になったときに、必要な分だけ導入する\nそれが、実務に耐えるDDDでした。\nRepositoryは「境界の翻訳者」だった Repositoryについても、\n薄くするべきか ロジックを持つべきか といった議論を扱いました。\nここで大切なのは、\nRepositoryはドメインと技術の境界に立つ存在\nだという点です。\nUseCase側にはドメインの言葉がある 実装側にはDBやAPIの都合がある Repositoryは、その両者を\nお互いに汚染させないための翻訳層\nとして機能します。\n「薄い／厚い」という言葉に引きずられるよりも、\nどこまでをドメインとして守りたいか どこからを技術的詳細として隔離したいか を考えることの方が重要でした。\nDDDは「チームで悩むための言語」だった DDDは、 個人の設計力を高めるだけのものではありません。\nむしろ、\nチームで設計について悩むための言語\nとして使われたとき、 最も効果を発揮します。\n何がつらいのか どこが壊れやすいのか なぜこの変更が怖いのか こうした感覚を、\n境界 責務 モデル といった言葉で共有できるようになる。\nDDDが提供する価値は、\n結論を揃えることではなく、 悩み方を揃えること\nでした。\nDDDは「使わない判断」も含んでいる この本では、 あえて次のことも強調してきました。\nすべてにDDDを適用しない 単純なものは単純に書く 途中でやめる判断を恐れない DDDは、\n設計を複雑にするための理論ではありません\n変更を楽にするための手段です。\nもしDDDを使った結果、\n読みにくくなった 触りにくくなった 説明が難しくなった のであれば、 それは立ち止まるサインです。\nDDDから離れる勇気もまた、 DDDを理解した結果なのです。\nおわりに ここまで、DDDという言葉を手がかりに、 設計について考えてきました。\nこの文章は何かを結論づけるために 書いたものではありません。\n設計に向き合う中で感じた違和感や迷いを、 そのままにせず、 一度立ち止まって言葉にしてみる。\nDDDは、そのための 一つの枠組みとして存在すると考えています。\n設計は、 時間とともに変わります。\nコードも、 要求も、 チームも変わり続けます。\nその中で、\n何を守ろうとしたのか なぜこの形を選んだのか を思い出せる手がかりが、 どこかに残っていることは、 きっと無駄にはなりません。\nこの文章もまた、 そうした手がかりの一つとして残します。\n","permalink":"https://design.okuda-studio.com/books/004-ddd/11/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#ddd%E3%81%AF%E6%AD%A3%E8%A7%A3%E9%9B%86%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F\"\u003eDDDは「正解集」ではなかった\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A2%E3%83%87%E3%83%AB%E3%81%A8%E3%81%AF%E3%83%AB%E3%83%BC%E3%83%AB%E3%82%92%E9%96%89%E3%81%98%E8%BE%BC%E3%82%81%E3%82%8B%E5%A0%B4%E6%89%80%E3%81%A0%E3%81%A3%E3%81%9F\"\u003eモデルとは「ルールを閉じ込める場所」だった\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#repository%E3%81%AF%E5%A2%83%E7%95%8C%E3%81%AE%E7%BF%BB%E8%A8%B3%E8%80%85%E3%81%A0%E3%81%A3%E3%81%9F\"\u003eRepositoryは「境界の翻訳者」だった\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ddd%E3%81%AF%E3%83%81%E3%83%BC%E3%83%A0%E3%81%A7%E6%82%A9%E3%82%80%E3%81%9F%E3%82%81%E3%81%AE%E8%A8%80%E8%AA%9E%E3%81%A0%E3%81%A3%E3%81%9F\"\u003eDDDは「チームで悩むための言語」だった\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ddd%E3%81%AF%E4%BD%BF%E3%82%8F%E3%81%AA%E3%81%84%E5%88%A4%E6%96%AD%E3%82%82%E5%90%AB%E3%82%93%E3%81%A7%E3%81%84%E3%82%8B\"\u003eDDDは「使わない判断」も含んでいる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB\"\u003eおわりに\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eこの本を通して、DDDについて多くの言葉が登場しました。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEntity\u003c/li\u003e\n\u003cli\u003eValue Object\u003c/li\u003e\n\u003cli\u003eRepository\u003c/li\u003e\n\u003cli\u003eUseCase\u003c/li\u003e\n\u003cli\u003e境界\u003c/li\u003e\n\u003cli\u003eモデル\u003c/li\u003e\n\u003cli\u003e共通言語\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eしかし、ここで一度立ち止まって確認したいことがあります。\u003c/p\u003e\n\u003cp\u003eこの本が本当に伝えたかったのは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eこれらの言葉そのものではない\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eという点です。\u003c/p\u003e\n\u003cp\u003e最終章では、これまでの内容を振り返りながら、\nDDDとどう付き合っていくとよいのかを、改めて整理します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"dddは正解集ではなかった\"\u003eDDDは「正解集」ではなかった\u003c/h2\u003e\n\u003cp\u003e第一章から一貫して述べてきた通り、DDDは\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e正解を与える設計論\u003c/li\u003e\n\u003cli\u003eそのまま使える設計テンプレート\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eではありません。\u003c/p\u003e\n\u003cp\u003eむしろDDDは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e設計について考え続けるための視点の集合\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eなぜここに置いたのか\u003c/li\u003e\n\u003cli\u003eなぜこの責務は重く感じるのか\u003c/li\u003e\n\u003cli\u003eなぜこの変更が怖いのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eそうした問いを、\n曖昧な感覚のままにせず、\n\u003cstrong\u003e言葉として扱えるようにする\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003eそれがDDDの本質でした。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"モデルとはルールを閉じ込める場所だった\"\u003eモデルとは「ルールを閉じ込める場所」だった\u003c/h2\u003e\n\u003cp\u003e本書では何度も、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEntityかVOか\u003c/li\u003e\n\u003cli\u003eどこからモデルにするか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという話題が出てきました。\u003c/p\u003e\n\u003cp\u003eしかし、結論はとてもシンプルです。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eモデルとは、守りたいルールを閉じ込めるための器\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e変わってほしくない振る舞い\u003c/li\u003e\n\u003cli\u003e破られると困る制約\u003c/li\u003e\n\u003cli\u003e他の場所に漏れると危険な判断\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eそれらが見え始めたとき、\n初めてモデルは意味を持ちます。\u003c/p\u003e\n\u003cp\u003e最初から立派なモデルを作る必要はありません。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e必要になったときに、必要な分だけ導入する\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eそれが、実務に耐えるDDDでした。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"repositoryは境界の翻訳者だった\"\u003eRepositoryは「境界の翻訳者」だった\u003c/h2\u003e\n\u003cp\u003eRepositoryについても、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e薄くするべきか\u003c/li\u003e\n\u003cli\u003eロジックを持つべきか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった議論を扱いました。\u003c/p\u003e\n\u003cp\u003eここで大切なのは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eRepositoryはドメインと技術の境界に立つ存在\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eだという点です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUseCase側にはドメインの言葉がある\u003c/li\u003e\n\u003cli\u003e実装側にはDBやAPIの都合がある\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eRepositoryは、その両者を\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eお互いに汚染させないための翻訳層\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eとして機能します。\u003c/p\u003e\n\u003cp\u003e「薄い／厚い」という言葉に引きずられるよりも、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどこまでをドメインとして守りたいか\u003c/li\u003e\n\u003cli\u003eどこからを技術的詳細として隔離したいか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを考えることの方が重要でした。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"dddはチームで悩むための言語だった\"\u003eDDDは「チームで悩むための言語」だった\u003c/h2\u003e\n\u003cp\u003eDDDは、\n個人の設計力を高めるだけのものではありません。\u003c/p\u003e","title":"第11章：まとめ"},{"content":" 要件整理と言葉の定義 境界の決定 データ → ドメイン → UI の流れ 実装スケッチ 実例から分かること この章のまとめ この章では、本書で扱ってきた考え方を、 実在する小さな Android アプリに当てはめてみます。\n題材は「口座振替メモアプリ」です。\n電気料金 クレジットカード サブスクリプション といった 引き落とし元 と 引き落とし先 を記録し、 「どこから、何が、どう引き落とされているのか」を把握するためのアプリです。\nDDD の用語を説明する章ではありません。 どう判断し、どこに線を引いたか を追う章です。\n要件整理と言葉の定義 最初にやったのは、クラス設計ではありません。 言葉を揃えること でした。\nこのアプリでは、次のような言葉が登場します。\n口座 引き落とし 引き落とし元 引き落とし先 メモ ここで重要なのは、「それぞれが何を指すのか」を明確にすることです。\nたとえば、\n「口座」は銀行口座だけを指すのか クレジットカードは口座なのか 引き落とし元と引き落とし先は対等な存在か この時点で、次のように定義しました。\n引き落とし元 実際にお金が減る側（銀行口座やクレジットカード） 引き落とし先 電気料金やサブスクなど、支払いの理由となるもの 口座振替 「引き落とし元」と「引き落とし先」を結びつける関係 この定義は、コードより先に決まっています。 そして、この言葉がそのままクラス名や変数名になります。\n境界の決定 このアプリで最初に決めた境界は、たった一つです。\n「UI は、引き落としの判断をしない」\n有効かどうか 表示すべきかどうか どちらが元で、どちらが先か こういった判断は、UI に書かないと決めました。\nその結果、\nUI は「表示するだけ」 判断は ViewModel より下に集まる という自然な流れが生まれます。\nこの時点では、\nDomain 層という名前のパッケージ UseCase クラス は、まだ存在していません。\n境界だけを先に決める ことで、 構造は後から追いついてきます。\nデータ → ドメイン → UI の流れ 実装が進むにつれて、次の流れが安定してきました。\nData 永続化や取得の責務 Domain 「これは何か」「どう扱うか」の判断 UI 表示とイベント通知 重要なのは、この流れを 最初から意識して作っていない ことです。\nRepository から取得したデータを ViewModel でそのまま使うのが苦しくなり 「ここで判断したい」という塊が見え そこに名前をつけた 結果として、\n「口座振替」という概念 「引き落とし元」「引き落とし先」という役割 が、ドメインとして浮かび上がりました。\nDDD 的に言えば「ドメインモデルが見えた」状態ですが、 実際には 困りごとに名前をつけただけ です。\n実装スケッチ ここでは、雰囲気が伝わる程度のスケッチだけを示します。\nRepository は、データの取得に専念します。\n条件付きの SQL フィルタリング 並び替え こういった処理は持ちますが、 「それが何を意味するか」は知りません。\n次に、判断が集まり始めた場所に、小さなクラスを置きます。\n引き落とし元かどうかを判定する 表示用の名前を決める UI が迷わなくて済む形に整える この時点で、初めて「これはドメインだ」と呼べるものになります。\nUI 側は、\n状態を受け取る 表示する ユーザー操作を通知する だけになります。\nコード量は減っていません。 しかし、迷う場所は確実に減ります。\n実例から分かること このアプリでは、\n最初から DDD をやろうとしなかった 境界を 1 箇所だけ決めた 言葉を揃えた 困ってから名前をつけた という順序で設計が進みました。\n結果として、\n仕様追加に耐えやすい UI がシンプル 判断の置き場所に迷いにくい 構造になっています。\nこの章のまとめ 実例を通して伝えたかったのは、次の一点です。\nDDD は「設計手法」ではなく、「どの判断を先に固定し、どの判断を後で変えるかを意識する姿勢」だということ\nどこで判断するのか なぜそこに置いたのか 後で壊せるか これらを説明できるなら、それは十分に DDD です。\nクラス構成や層の名前は、後からいくらでも変えられる。 しかし、「どこで判断するか」という境界だけは、早い段階で決めておく必要があります。\n大きな理論も、立派な用語も必要ありません。 自分たちのアプリにとって、意味のある境界を引けているか それだけが重要です。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/12/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003e要件整理と言葉の定義\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A2%83%E7%95%8C%E3%81%AE%E6%B1%BA%E5%AE%9A\"\u003e境界の決定\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eデータ → ドメイン → UI の流れ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E3%82%B9%E3%82%B1%E3%83%83%E3%83%81\"\u003e実装スケッチ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003e実例から分かること\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%AB%A0%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81\"\u003eこの章のまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eこの章では、本書で扱ってきた考え方を、\n\u003cstrong\u003e実在する小さな Android アプリ\u003c/strong\u003eに当てはめてみます。\u003c/p\u003e\n\u003cp\u003e題材は「口座振替メモアプリ」です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e電気料金\u003c/li\u003e\n\u003cli\u003eクレジットカード\u003c/li\u003e\n\u003cli\u003eサブスクリプション\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった \u003cem\u003e引き落とし元\u003c/em\u003e と \u003cem\u003e引き落とし先\u003c/em\u003e を記録し、\n「どこから、何が、どう引き落とされているのか」を把握するためのアプリです。\u003c/p\u003e\n\u003cp\u003eDDD の用語を説明する章ではありません。\n\u003cstrong\u003eどう判断し、どこに線を引いたか\u003c/strong\u003e を追う章です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"要件整理と言葉の定義\"\u003e要件整理と言葉の定義\u003c/h3\u003e\n\u003cp\u003e最初にやったのは、クラス設計ではありません。\n\u003cstrong\u003e言葉を揃えること\u003c/strong\u003e でした。\u003c/p\u003e\n\u003cp\u003eこのアプリでは、次のような言葉が登場します。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e口座\u003c/li\u003e\n\u003cli\u003e引き落とし\u003c/li\u003e\n\u003cli\u003e引き落とし元\u003c/li\u003e\n\u003cli\u003e引き落とし先\u003c/li\u003e\n\u003cli\u003eメモ\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eここで重要なのは、「それぞれが何を指すのか」を明確にすることです。\u003c/p\u003e\n\u003cp\u003eたとえば、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e「口座」は銀行口座だけを指すのか\u003c/li\u003e\n\u003cli\u003eクレジットカードは口座なのか\u003c/li\u003e\n\u003cli\u003e引き落とし元と引き落とし先は対等な存在か\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの時点で、次のように定義しました。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e引き落とし元\n\u003cul\u003e\n\u003cli\u003e実際にお金が減る側（銀行口座やクレジットカード）\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e引き落とし先\n\u003cul\u003e\n\u003cli\u003e電気料金やサブスクなど、支払いの理由となるもの\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e口座振替\n\u003cul\u003e\n\u003cli\u003e「引き落とし元」と「引き落とし先」を結びつける関係\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの定義は、\u003cstrong\u003eコードより先に決まっています\u003c/strong\u003e。\nそして、この言葉がそのままクラス名や変数名になります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"境界の決定\"\u003e境界の決定\u003c/h3\u003e\n\u003cp\u003eこのアプリで最初に決めた境界は、たった一つです。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e「UI は、引き落としの判断をしない」\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e有効かどうか\u003c/li\u003e\n\u003cli\u003e表示すべきかどうか\u003c/li\u003e\n\u003cli\u003eどちらが元で、どちらが先か\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこういった判断は、UI に書かないと決めました。\u003c/p\u003e\n\u003cp\u003eその結果、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUI は「表示するだけ」\u003c/li\u003e\n\u003cli\u003e判断は ViewModel より下に集まる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという自然な流れが生まれます。\u003c/p\u003e\n\u003cp\u003eこの時点では、\u003c/p\u003e","title":"第11章：口座振替メモアプリの設計"},{"content":" DDD は目的ではなく手段 Android 開発で一番大事なのは「壊しやすさ」 設計はチームとプロダクトの文脈で変わる 本書では、ドメイン駆動設計（DDD）を Android 開発の文脈で、できるだけ現実的に扱ってきました。 理論を網羅することや、正統派の実装を示すことが目的ではありません。 ここで伝えたかったのは、DDD をどう「使うか」 という視点です。\nDDD は目的ではなく手段 DDD を採用すること自体に価値があるわけではありません。 価値があるのは、DDD が 判断を助けてくれること、会話を整理してくれること、そして 設計の迷いを減らしてくれること です。\nもし DDD を導入した結果、\nクラスが増えすぎて全体が見えなくなった 抽象が先行して実装が進まなくなった チーム内で言葉が通じなくなった のであれば、それは設計が目的化してしまっています。\n設計は、プロダクトを前に進めるための道具です。 DDD もまた、そのための選択肢のひとつに過ぎません。\nAndroid 開発で一番大事なのは「壊しやすさ」 Android アプリは、要件が変わります。 画面が増え、仕様が揺れ、API が変わり、ビジネスの都合も介入します。\nその現実の中で重要なのは、 「最初から正しい設計」ではなく「あとから直せる設計」 です。\n境界があるから、影響範囲が読める 言葉が揃っているから、変更点を議論できる 責務が分かれているから、壊す勇気を持てる 本書で扱ってきた DDD の要素は、すべてこの 壊しやすさ に収束します。 堅牢さのためではなく、柔らかさのための設計です。\n設計はチームとプロダクトの文脈で変わる 最後に、強調しておきたいことがあります。\n設計に「唯一の正解」はありません。 あなたがいるチーム、扱っているプロダクト、求められるスピードや品質によって、 最適な設計は必ず変わります。\n1 人開発なら、境界は最小でいい 小さなアプリなら、ドメインは薄くていい チームが育ってきたら、言葉と責務を強く意識すればいい DDD はフルセットで導入するものではありません。 必要な部分だけを、必要なタイミングで取り入れていく。 それで十分です。\nもし本書を読み終えて、\n設計について少し考える余裕が生まれた 「これはドメインの話だな」と立ち止まれるようになった 設計を言葉で説明できる感覚が掴めた のであれば、この本の役割は果たせています。\nDDD は、あなたの開発を縛るものではありません。 あなたの判断を、少しだけ楽にしてくれる存在であってほしい。\nここまで読み進めてくださり、ありがとうございました。 この本が、あなたの Android 開発の現場で、静かに役に立つことを願っています。\n","permalink":"https://design.okuda-studio.com/books/005-android-with-ddd/13/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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\"\u003eDDD は目的ではなく手段\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003eAndroid 開発で一番大事なのは「壊しやすさ」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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\"\u003e設計はチームとプロダクトの文脈で変わる\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003e本書では、ドメイン駆動設計（DDD）を Android 開発の文脈で、できるだけ現実的に扱ってきました。\n理論を網羅することや、正統派の実装を示すことが目的ではありません。\nここで伝えたかったのは、\u003cstrong\u003eDDD をどう「使うか」\u003c/strong\u003e という視点です。\u003c/p\u003e\n\u003ch3 id=\"ddd-は目的ではなく手段\"\u003eDDD は目的ではなく手段\u003c/h3\u003e\n\u003cp\u003eDDD を採用すること自体に価値があるわけではありません。\n価値があるのは、DDD が \u003cstrong\u003e判断を助けてくれること\u003c/strong\u003e、\u003cstrong\u003e会話を整理してくれること\u003c/strong\u003e、そして \u003cstrong\u003e設計の迷いを減らしてくれること\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003eもし DDD を導入した結果、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eクラスが増えすぎて全体が見えなくなった\u003c/li\u003e\n\u003cli\u003e抽象が先行して実装が進まなくなった\u003c/li\u003e\n\u003cli\u003eチーム内で言葉が通じなくなった\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eのであれば、それは設計が目的化してしまっています。\u003c/p\u003e\n\u003cp\u003e設計は、プロダクトを前に進めるための道具です。\nDDD もまた、そのための選択肢のひとつに過ぎません。\u003c/p\u003e\n\u003ch3 id=\"android-開発で一番大事なのは壊しやすさ\"\u003eAndroid 開発で一番大事なのは「壊しやすさ」\u003c/h3\u003e\n\u003cp\u003eAndroid アプリは、要件が変わります。\n画面が増え、仕様が揺れ、API が変わり、ビジネスの都合も介入します。\u003c/p\u003e\n\u003cp\u003eその現実の中で重要なのは、\n\u003cstrong\u003e「最初から正しい設計」ではなく「あとから直せる設計」\u003c/strong\u003e です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e境界があるから、影響範囲が読める\u003c/li\u003e\n\u003cli\u003e言葉が揃っているから、変更点を議論できる\u003c/li\u003e\n\u003cli\u003e責務が分かれているから、壊す勇気を持てる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e本書で扱ってきた DDD の要素は、すべてこの \u003cstrong\u003e壊しやすさ\u003c/strong\u003e に収束します。\n堅牢さのためではなく、柔らかさのための設計です。\u003c/p\u003e\n\u003ch3 id=\"設計はチームとプロダクトの文脈で変わる\"\u003e設計はチームとプロダクトの文脈で変わる\u003c/h3\u003e\n\u003cp\u003e最後に、強調しておきたいことがあります。\u003c/p\u003e\n\u003cp\u003e設計に「唯一の正解」はありません。\nあなたがいるチーム、扱っているプロダクト、求められるスピードや品質によって、\n最適な設計は必ず変わります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e1 人開発なら、境界は最小でいい\u003c/li\u003e\n\u003cli\u003e小さなアプリなら、ドメインは薄くていい\u003c/li\u003e\n\u003cli\u003eチームが育ってきたら、言葉と責務を強く意識すればいい\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eDDD はフルセットで導入するものではありません。\n必要な部分だけを、必要なタイミングで取り入れていく。\nそれで十分です。\u003c/p\u003e\n\u003cp\u003eもし本書を読み終えて、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e設計について少し考える余裕が生まれた\u003c/li\u003e\n\u003cli\u003e「これはドメインの話だな」と立ち止まれるようになった\u003c/li\u003e\n\u003cli\u003e設計を言葉で説明できる感覚が掴めた\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eのであれば、この本の役割は果たせています。\u003c/p\u003e\n\u003cp\u003eDDD は、あなたの開発を縛るものではありません。\nあなたの判断を、少しだけ楽にしてくれる存在であってほしい。\u003c/p\u003e","title":"おわりに"},{"content":" 題材 リポジトリがドメインに依存するのはありか？ ドメインを知りすぎた実装 ドメインを知りすぎない実装 今回は、リポジトリがドメインに依存しすぎた話を書きたいと思います。\n題材 題材は、口座振替管理アプリで、ローカルの DB にデータを保存する場合の話です。\n支払情報編集画面という画面があり、この画面では、データの新規登録と既存データの更新が可能になっています。\nこの「新規登録」処理と「更新」処理を行う際に、リポジトリはどこまでドメインを知っていていいのか？という話になります。\nリポジトリがドメインに依存するのはありか？ まず、クリーンアーキテクチャ的には、リポジトリがドメインに依存することは間違ってはいません。\nただし、どこまで知っていてよいのかは検討の余地があるというのが今回の学びです。\nドメインを知りすぎた実装 まずは、ドメインを知りすぎた良くない実装を紹介します。\n以下は、支払情報を表す Payment オブジェクトです。\nsealed interface Payment { val name: PaymentName val payerId: PayerId data class Persisted( val id: PaymentId, override val name: PaymentName, override val payerId: PayerId = PayerId.NONE, ) : Payment data class InMemory( override val name: PaymentName, override val payerId: PayerId = PayerId.NONE, ) : Payment } 編集の場合は、すでにデータが永続化されているため、 Persisted オブジェクトで表現します。永続化済みのデータは ID を持っています。\n新規登録の場合は、 ID を持っていないため InMemory オブジェクトで表現します。\nリポジトリ側には、この Payment オブジェクトが渡され、このオブジェクトの実態が Persisted なのか、 InMemory なのかによって、新規作成か、更新かを分けています。\nsuspend fun save(payment: Payment) { when (payment) { is Payment.InMemory -\u0026gt; create(...) is Payment.Persisted -\u0026gt; update(...) } } この実装の問題点は、もし、今後、 Payment の定義が以下のように変わった場合、リポジトリ側に影響が及ぶという点です。\nPayment.Draft Payment.Archived クリーンアーキテクチャ的には、ドメインが変わった場合は、 UI レイヤーやデータレイヤーに影響が出るのは仕方のないことなのですが、できれば影響は避けたいところです。\nドメインを知りすぎない実装 では、ドメインを知りすぎない実装とは、どのようになるでしょうか？\n以下のように ID が null かどうかだけに依存するのが最小限の依存だと、私は考えます。\nsuspend fun save(payment: Payment) { if (payment.id == null) { create(...) } else { update(...) } } こうすることで、先ほどの問題点は解消されます。\nまた、リポジトリの責務は、データの保存方法を管理することです。\nデータの保存方法を判断するのに、 Payment オブジェクトが Persisted なのか InMemory なのかは知る必要がありません。\n知りたいのは、 ID が null なのかどうかだけです。\nこうすることで、データの保存の判断に必要な最低限の情報にだけ依存する実装になりました。\nよって、保存方法の判断に関係のない変更に影響を受けることがなくなりました。\nまた、 ID の有無は、データの保存方法を判断するための本質的なデータです。そのため、データ保存上、なくなったり変わったりしにくいデータです。\n一方で、 Payment オブジェクトの Persisted や InMemory はドメインの捉え方の問題なので、 ID に比べると変わりやすいモデリングです。\n今回学んだことは、将来変わりにくい本質的なデータに依存することが重要だという点です。\n","permalink":"https://design.okuda-studio.com/posts/0022-repository-depends-on-domain/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E9%A1%8C%E6%9D%90\"\u003e題材\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%8C%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AB%E4%BE%9D%E5%AD%98%E3%81%99%E3%82%8B%E3%81%AE%E3%81%AF%E3%81%82%E3%82%8A%E3%81%8B\"\u003eリポジトリがドメインに依存するのはありか？\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92%E7%9F%A5%E3%82%8A%E3%81%99%E3%81%8E%E3%81%9F%E5%AE%9F%E8%A3%85\"\u003eドメインを知りすぎた実装\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92%E7%9F%A5%E3%82%8A%E3%81%99%E3%81%8E%E3%81%AA%E3%81%84%E5%AE%9F%E8%A3%85\"\u003eドメインを知りすぎない実装\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003e今回は、リポジトリがドメインに依存しすぎた話を書きたいと思います。\u003c/p\u003e\n\u003ch2 id=\"題材\"\u003e題材\u003c/h2\u003e\n\u003cp\u003e題材は、口座振替管理アプリで、ローカルの DB にデータを保存する場合の話です。\u003c/p\u003e\n\u003cp\u003e支払情報編集画面という画面があり、この画面では、データの新規登録と既存データの更新が可能になっています。\u003c/p\u003e\n\u003cp\u003eこの「新規登録」処理と「更新」処理を行う際に、リポジトリはどこまでドメインを知っていていいのか？という話になります。\u003c/p\u003e\n\u003ch2 id=\"リポジトリがドメインに依存するのはありか\"\u003eリポジトリがドメインに依存するのはありか？\u003c/h2\u003e\n\u003cp\u003eまず、クリーンアーキテクチャ的には、リポジトリがドメインに依存することは間違ってはいません。\u003c/p\u003e\n\u003cp\u003eただし、どこまで知っていてよいのかは検討の余地があるというのが今回の学びです。\u003c/p\u003e\n\u003ch2 id=\"ドメインを知りすぎた実装\"\u003eドメインを知りすぎた実装\u003c/h2\u003e\n\u003cp\u003eまずは、ドメインを知りすぎた良くない実装を紹介します。\u003c/p\u003e\n\u003cp\u003e以下は、支払情報を表す \u003ccode\u003ePayment\u003c/code\u003e オブジェクトです。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003esealed\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003einterface\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePayment\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e name: PaymentName\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e payerId: PayerId\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edata\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePersisted\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e id: PaymentId,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eoverride\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e name: PaymentName,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eoverride\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e payerId: PayerId = \u003cspan style=\"color:#a6e22e\"\u003ePayerId\u003c/span\u003e.NONE,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ) : Payment\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edata\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eInMemory\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eoverride\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e name: PaymentName,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eoverride\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e payerId: PayerId = \u003cspan style=\"color:#a6e22e\"\u003ePayerId\u003c/span\u003e.NONE,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ) : Payment\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e編集の場合は、すでにデータが永続化されているため、 \u003ccode\u003ePersisted\u003c/code\u003e オブジェクトで表現します。永続化済みのデータは ID を持っています。\u003c/p\u003e\n\u003cp\u003e新規登録の場合は、 ID を持っていないため \u003ccode\u003eInMemory\u003c/code\u003e オブジェクトで表現します。\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eリポジトリ側には、この \u003ccode\u003ePayment\u003c/code\u003e オブジェクトが渡され、このオブジェクトの実態が \u003ccode\u003ePersisted\u003c/code\u003e なのか、 \u003ccode\u003eInMemory\u003c/code\u003e なのかによって、新規作成か、更新かを分けています。\u003c/p\u003e","title":"リポジトリがドメインに依存しすぎた話"},{"content":" すぐに思いつく実装 「新規作成 or 編集」を型で表現する なぜエラーになるのか 正しい設計：Navigation はプリミティブ型を渡す 重要なポイント Navigationの責務 UI の責務 一覧画面から「新規作成」と「編集」の両方に遷移するケースは、アプリ開発でよくあります。\n例えば以下のような仕様です：\nリストのアイテムをタップ → 編集画面へ 「追加」ボタンをタップ → 新規作成画面へ 画面UIは同じ（内部の動作だけ異なる） すぐに思いつく実装 すぐに思いつく実装方法は以下ではないでしょうか？\nNavigation の定義は以下の通り\nNavHost( navController = navController, startDestination = startDestination, modifier = modifier, ) { // リスト画面 composable\u0026lt;ItemList\u0026gt; { PayeeListScreen( onClickAdd = { navController.navigate(RegisterItem(null)) }, onClickItem = { itemId -\u0026gt; navController.navigate(RegisterItem(itemId)) } ) } // 登録・編集画面 composable\u0026lt;RegisterItem\u0026gt; { backStackEntry -\u0026gt; val registerItem: RegisterItem = backStackEntry.toRoute() RegisterItemScreen( onClickNavigateUp = { navController.navigateUp() }, itemId = registerItem.id ) } Destination の定義は以下の通り\n@Serializable data class RegisterItem( val id: Int? ) idあり → 編集 idなし（null） → 新規作成 最終的に、この実装方法が最適だという結果になるのですが、この時の私は、もっと良い設計が可能だと考えていました。\nなぜなら、「 null が新規作成を意味する」状態だからです。\nこのコードは、属人化につながります。\n私は null を型で排除しようと試みました。\n「新規作成 or 編集」を型で表現する 私は、型で意味を表現しようとして、以下のように実装しました。\n@Serializable data class RegisterItem( val mode: ItemEditMode ) sealed interface ItemEditMode { data object Add : ItemEditMode data class Edit(val id: Int) : ItemEditMode } これにより NavHost 内が\nonClickAdd = { navController.navigate(RegisterItem(Add)) }, onClickItem = { itemId -\u0026gt; navController.navigate(RegisterItem(Edit(itemId))) } となり、コードの意図が明確になり、 null が排除できると考えました。\nしかし、この実装ではエラーになります。\nなぜエラーになるのか 理由はシンプルで、\nNavigationは「完全にシリアライズ可能なデータ」しか扱えないためです。\nsealed interface はそのままだと扱いが難しい data object を含むとさらに不安定 polymorphic serialization が必要になる つまり、 Navigationにドメイン的な型をそのまま渡すのは難しい\nAndroid Developers の公式ドキュメントでも、画面遷移時のパラメータ渡しは、基本的にはプリミティブを渡すように書かれていた気がします。\n「苦肉の策として、シリアライズ化すれば、クラスも渡せるよ」程度の書き方がされたいた印象があります。\n正しい設計：Navigation はプリミティブ型を渡す Navigationでは、プリミティブな値だけを扱います。\n結局のところ、最適解は すぐに思いつく実装 セクションで紹介した方法になります。\n重要なポイント Navigationの責務 Navigation の責務は「画面遷移」であり、「画面のモード」まで知っているのは、責務を負いすぎている。と私は感じました。\n画面が、今は「新規登録モード」なのか「編集モード」なのかは、ドメインに近い情報であると考えます。\nそのため、「プリミティブ型」しか扱わないような Navigation に、モードまで扱わせるのは 荷が重い と感じました。\nUI の責務 一方で、 UI 側は、プリミティブ型のデータを Navigation 経由で受け取り、その値に基づいて、画面側でモードの判定を行うことが可能です。\nよく考えれば、画面のモードを判定する責務が、その画面自体に存在していることはかなり自然な状態だと思います。\nNavigation に「基本的にプリミティブ型のみ扱うべき」という制約がなければ、 Navigation 側でモードを判定してもおかしくはないとは思いますが。\n","permalink":"https://design.okuda-studio.com/posts/0021-navigation-should-have-primitive/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%99%E3%81%90%E3%81%AB%E6%80%9D%E3%81%84%E3%81%A4%E3%81%8F%E5%AE%9F%E8%A3%85\"\u003eすぐに思いつく実装\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%96%B0%E8%A6%8F%E4%BD%9C%E6%88%90-or-%E7%B7%A8%E9%9B%86%E3%82%92%E5%9E%8B%E3%81%A7%E8%A1%A8%E7%8F%BE%E3%81%99%E3%82%8B\"\u003e「新規作成 or 編集」を型で表現する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%AE%E3%81%8B\"\u003eなぜエラーになるのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%AD%A3%E3%81%97%E3%81%84%E8%A8%AD%E8%A8%88navigation-%E3%81%AF%E3%83%97%E3%83%AA%E3%83%9F%E3%83%86%E3%82%A3%E3%83%96%E5%9E%8B%E3%82%92%E6%B8%A1%E3%81%99\"\u003e正しい設計：Navigation はプリミティブ型を渡す\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%87%8D%E8%A6%81%E3%81%AA%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88\"\u003e重要なポイント\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#navigation%E3%81%AE%E8%B2%AC%E5%8B%99\"\u003eNavigationの責務\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ui-%E3%81%AE%E8%B2%AC%E5%8B%99\"\u003eUI の責務\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003e一覧画面から「新規作成」と「編集」の両方に遷移するケースは、アプリ開発でよくあります。\u003c/p\u003e\n\u003cp\u003e例えば以下のような仕様です：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eリストのアイテムをタップ → 編集画面へ\u003c/li\u003e\n\u003cli\u003e「追加」ボタンをタップ → 新規作成画面へ\u003c/li\u003e\n\u003cli\u003e画面UIは同じ（内部の動作だけ異なる）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"すぐに思いつく実装\"\u003eすぐに思いつく実装\u003c/h2\u003e\n\u003cp\u003eすぐに思いつく実装方法は以下ではないでしょうか？\u003c/p\u003e\n\u003cp\u003eNavigation の定義は以下の通り\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    NavHost(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        navController = navController,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        startDestination = startDestination,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        modifier = modifier,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// リスト画面\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        composable\u0026lt;ItemList\u0026gt; {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            PayeeListScreen(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                onClickAdd = {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    navController.navigate(RegisterItem(\u003cspan style=\"color:#66d9ef\"\u003enull\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                onClickItem = { itemId \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    navController.navigate(RegisterItem(itemId))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// 登録・編集画面\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        composable\u0026lt;RegisterItem\u0026gt; { backStackEntry \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e registerItem: RegisterItem = backStackEntry.toRoute()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            RegisterItemScreen(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                onClickNavigateUp = { navController.navigateUp() },\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                itemId = registerItem.id\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eDestination の定義は以下の通り\u003c/p\u003e","title":"Jetpack Compose Navigation のパラメータ指定の罠"},{"content":" はじめに ドメイン設計だけでは埋まらない違和感 ワイヤーフレームを作って起きた変化 1. ユーザーの行動が具体化される 2. 必要なデータと制約が見えてくる 3. ドメイン設計の「抜け」が露出する ワイヤーフレームは見た目のためではない まとめ おわりに はじめに 最近、アプリ開発の中で「ワイヤーフレーム」を使い始めたところ、思いがけずドメイン設計が大きく前進しました。\nワイヤーフレームとは、 Figma などを使って作る UI デザインの一種です。\nただし、色やフォントサイズなどの細かい UI にはこだわりません。\nボタンや入力欄であることがわかれば良いという程度のラフな UI デザインのことを言います。\nもともとドメイン駆動で設計を進めていたのですが、どうしても「抜け」や「曖昧さ」が残る感覚があり、手応えが弱い状態が続いていました。\nしかし、ワイヤーフレームを作り始めたことで、その状況が一変しました。\nこの記事では、 ワイヤーフレームがどのようにドメイン設計を補完し、加速させたのかを整理してみます。\nドメイン設計だけでは埋まらない違和感 ドメイン設計を進めていると、以下のような状態に陥ることがありました。\nユースケースはある程度整理されている エンティティや値オブジェクトも定義できている しかし「本当にこれで使えるのか？」という違和感がある つまり、構造はあるが、実感がない状態です。\nこのとき不足していたのは、「ユーザーがどう操作するか」という視点でした。\nワイヤーフレームを作って起きた変化 試しにワイヤーフレームを作り始めたところ、明確な変化がありました。\n1. ユーザーの行動が具体化される ワイヤーフレームでは「画面上で何をするか」を考える必要があります。\nどこで入力するのか どの順番で操作するのか 何を確定とみなすのか これにより、ユースケースが単なる文章ではなく、操作として具体化されました。\n2. 必要なデータと制約が見えてくる 操作を具体的にすると、自然と以下が見えてきます。\nこの画面では何のデータが必要か この操作はどんな条件で許されるのか ここで重要なのが、 不変条件（インバリアント） です。\n例えば、口座振替管理アプリなら、\n支払い元は必ず 1 つである 振替は「元 → 先」の関係を持つ 不正な組み合わせは作れない など、これらはドメイン設計だけでも定義できますが、 ワイヤーフレーム上で「操作」として考えることで、一気に現実味を帯びます。\n3. ドメイン設計の「抜け」が露出する ワイヤーフレームを作る中で、次のような気づきが頻発しました。\nこの状態、どうやって作る？ この操作、どのユースケースに対応する？ このデータ、どこに属する？ つまり、ドメイン設計で曖昧だった部分が強制的に表に出てくるのです。\nこれはかなり大きなメリットでした。\nワイヤーフレームは見た目のためではない 今回一番の発見はここです。\nワイヤーフレームは、\nUIの見た目を決めるためのものではなく 制約と構造を発見するためのツール でした。\nワイヤーフレームを通すことで、\nUI からドメインが洗練され ドメインが洗練されることで、さらに UI が洗練される という相乗効果が得られます。\n作業を進めるたびに「UI とドメインがつながる」感覚があります。\nこの「つながる感覚」は、設計がうまくいっているサインだと感じています。\nまとめ ワイヤーフレームを取り入れたことで、以下の効果がありました。\nユースケースが操作として具体化される 不変条件が自然に見えてくる ドメイン設計の抜けが露出する 設計全体に一貫性が生まれる 結果として、 UI設計とドメイン設計が分離されたものではなく、相互に補完し合って、プロダクトが良くなっていく と実感しました。\nおわりに もしドメイン設計を進めていて、\nなんとなく手応えが弱い 抜けがある気がする と感じている場合は、 一度ワイヤーフレームを作ってみることをおすすめします。\n見た目を整える必要はありません。 むしろラフであるほど、本質が見えてきます。\n設計が「つながる」感覚を得られるはずです。\n","permalink":"https://design.okuda-studio.com/posts/0020-wireframe-with-ddd/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\"\u003eはじめに\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E8%A8%AD%E8%A8%88%E3%81%A0%E3%81%91%E3%81%A7%E3%81%AF%E5%9F%8B%E3%81%BE%E3%82%89%E3%81%AA%E3%81%84%E9%81%95%E5%92%8C%E6%84%9F\"\u003eドメイン設計だけでは埋まらない違和感\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%AF%E3%82%A4%E3%83%A4%E3%83%BC%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E8%B5%B7%E3%81%8D%E3%81%9F%E5%A4%89%E5%8C%96\"\u003eワイヤーフレームを作って起きた変化\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#1-%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E8%A1%8C%E5%8B%95%E3%81%8C%E5%85%B7%E4%BD%93%E5%8C%96%E3%81%95%E3%82%8C%E3%82%8B\"\u003e1. ユーザーの行動が具体化される\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#2-%E5%BF%85%E8%A6%81%E3%81%AA%E3%83%87%E3%83%BC%E3%82%BF%E3%81%A8%E5%88%B6%E7%B4%84%E3%81%8C%E8%A6%8B%E3%81%88%E3%81%A6%E3%81%8F%E3%82%8B\"\u003e2. 必要なデータと制約が見えてくる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#3-%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E8%A8%AD%E8%A8%88%E3%81%AE%E6%8A%9C%E3%81%91%E3%81%8C%E9%9C%B2%E5%87%BA%E3%81%99%E3%82%8B\"\u003e3. ドメイン設計の「抜け」が露出する\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%AF%E3%82%A4%E3%83%A4%E3%83%BC%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%81%AF%E8%A6%8B%E3%81%9F%E7%9B%AE%E3%81%AE%E3%81%9F%E3%82%81%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003eワイヤーフレームは見た目のためではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB\"\u003eおわりに\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"はじめに\"\u003eはじめに\u003c/h2\u003e\n\u003cp\u003e最近、アプリ開発の中で「ワイヤーフレーム」を使い始めたところ、思いがけずドメイン設計が大きく前進しました。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eワイヤーフレームとは、 Figma などを使って作る UI デザインの一種です。\u003cbr\u003e\nただし、色やフォントサイズなどの細かい UI にはこだわりません。\u003cbr\u003e\nボタンや入力欄であることがわかれば良いという程度のラフな UI デザインのことを言います。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eもともとドメイン駆動で設計を進めていたのですが、どうしても「抜け」や「曖昧さ」が残る感覚があり、手応えが弱い状態が続いていました。\u003c/p\u003e\n\u003cp\u003eしかし、ワイヤーフレームを作り始めたことで、その状況が一変しました。\u003c/p\u003e\n\u003cp\u003eこの記事では、\n\u003cstrong\u003eワイヤーフレームがどのようにドメイン設計を補完し、加速させたのか\u003c/strong\u003eを整理してみます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"ドメイン設計だけでは埋まらない違和感\"\u003eドメイン設計だけでは埋まらない違和感\u003c/h2\u003e\n\u003cp\u003eドメイン設計を進めていると、以下のような状態に陥ることがありました。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eユースケースはある程度整理されている\u003c/li\u003e\n\u003cli\u003eエンティティや値オブジェクトも定義できている\u003c/li\u003e\n\u003cli\u003eしかし「本当にこれで使えるのか？」という違和感がある\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eつまり、\u003cstrong\u003e構造はあるが、実感がない状態\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp\u003eこのとき不足していたのは、「ユーザーがどう操作するか」という視点でした。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"ワイヤーフレームを作って起きた変化\"\u003eワイヤーフレームを作って起きた変化\u003c/h2\u003e\n\u003cp\u003e試しにワイヤーフレームを作り始めたところ、明確な変化がありました。\u003c/p\u003e\n\u003ch3 id=\"1-ユーザーの行動が具体化される\"\u003e1. ユーザーの行動が具体化される\u003c/h3\u003e\n\u003cp\u003eワイヤーフレームでは「画面上で何をするか」を考える必要があります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどこで入力するのか\u003c/li\u003e\n\u003cli\u003eどの順番で操作するのか\u003c/li\u003e\n\u003cli\u003e何を確定とみなすのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれにより、ユースケースが単なる文章ではなく、\u003cstrong\u003e操作として具体化\u003c/strong\u003eされました。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"2-必要なデータと制約が見えてくる\"\u003e2. 必要なデータと制約が見えてくる\u003c/h3\u003e\n\u003cp\u003e操作を具体的にすると、自然と以下が見えてきます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこの画面では何のデータが必要か\u003c/li\u003e\n\u003cli\u003eこの操作はどんな条件で許されるのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eここで重要なのが、 \u003cstrong\u003e不変条件（インバリアント）\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003e例えば、口座振替管理アプリなら、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e支払い元は必ず 1 つである\u003c/li\u003e\n\u003cli\u003e振替は「元 → 先」の関係を持つ\u003c/li\u003e\n\u003cli\u003e不正な組み合わせは作れない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eなど、これらはドメイン設計だけでも定義できますが、\nワイヤーフレーム上で「操作」として考えることで、一気に現実味を帯びます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"3-ドメイン設計の抜けが露出する\"\u003e3. ドメイン設計の「抜け」が露出する\u003c/h3\u003e\n\u003cp\u003eワイヤーフレームを作る中で、次のような気づきが頻発しました。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこの状態、どうやって作る？\u003c/li\u003e\n\u003cli\u003eこの操作、どのユースケースに対応する？\u003c/li\u003e\n\u003cli\u003eこのデータ、どこに属する？\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eつまり、\u003cstrong\u003eドメイン設計で曖昧だった部分が強制的に表に出てくる\u003c/strong\u003eのです。\u003c/p\u003e","title":"ワイヤーフレームからドメイン設計が進んだ話"},{"content":" オブジェクト参照の場合 Order User アプリケーションサービス ID参照の場合 Order User アプリケーションサービス 違いを整理 オブジェクト参照 ID参照 もう一つ重要な違い：イベント駆動に拡張できる Application Service イベントの定義 EventBusの簡易実装 イベントハンドラ ハンドラ登録 イベントの流れ まとめ ドメイン駆動設計（DDD）では、次のようなルールをよく目にします。\n集約は他の集約を IDで参照する\nしかし、初めてこのルールを見たときに疑問が浮かびます。\nID参照にしても結局 Repository.find(id) で取得できるのでは？ それなら普通のオブジェクト参照とあまり変わらないのでは？ この記事では、このルールの意味を 実際のコードで比較しながら説明します。\nオブジェクト参照の場合 まず、他の集約を オブジェクトとして直接持つ設計を見てみます。\nOrder class Order( val id: OrderId, val user: User ) { fun place() { // 注文処理 user.upgradeToPremium() } } tips : place という単語には、 注文を出す / 発注する という意味があります。\nUser class User( val id: UserId, var plan: Plan ) { fun upgradeToPremium() { plan = Plan.PREMIUM } } アプリケーションサービス fun placeOrder(orderId: OrderId) { val order = orderRepository.find(orderId) order.place() orderRepository.save(order) } ここで起きていることを図にすると次のようになります。\nOrder.place() ↓ User.upgradeToPremium() つまり\nOrder更新 User更新 が 同じトランザクションの中で行われます。\nそして問題は、開発者が 無意識に別集約を更新できてしまうことです。\norder.user.upgradeToPremium() このコードを書いた時点では、\nOrderを更新しているのか Userを更新しているのか という 集約の境界が見えにくくなります。\nID参照の場合 次に、DDDで推奨される ID参照の設計を見てみます。\nOrder class Order( val id: OrderId, val userId: UserId ) { fun place() { // 注文のドメインロジックのみ。 // User の関数が呼び出されることはない。 } } User class User( val id: UserId, var plan: Plan ) { fun upgradeToPremium() { plan = Plan.PREMIUM } } アプリケーションサービス fun placeOrder(orderId: OrderId) { val order = orderRepository.find(orderId) order.place() val user = userRepository.find(order.userId) user.upgradeToPremium() orderRepository.save(order) userRepository.save(user) } ここで重要なのは次のコードです。\nval user = userRepository.find(order.userId) この処理を書くことで、開発者は\n別集約を操作している ことを 明確に意識します。\n違いを整理 オブジェクト参照 Order └ User コード\norder.user.upgrade() 問題\nどの集約を更新しているか分かりにくい ID参照 Order └ userId コード\nval user = userRepository.find(order.userId) 特徴\n別集約を操作していることが明確 つまり、DDDのルールは\n更新できないようにする のではなく\n無意識に更新できないようにする ことが目的です。\nもう一つ重要な違い：イベント駆動に拡張できる ID参照にすると、もう一つ大きなメリットがあります。\nイベント駆動設計に拡張できることです。\n例として、注文が確定したらユーザーをアップグレードする処理を考えます。\nApplication Service fun placeOrder(orderId: OrderId) { val order = orderRepository.find(orderId) order.place() orderRepository.save(order) eventBus.publish(OrderPlaced(order.userId)) } ここでは OrderPlaced というドメインイベントを発行しています。\nイベントの定義 data class OrderPlaced( val userId: UserId ) これは、「注文が確定した」という事実ベースのイベントです。\nDDD のイベント設計では、「～を実行せよ」という命令を書くのではなく、「～が起きた」という事実で設計することが重要です。\nなぜなら、一つのイベントが発生した際に、複数の処理が実行される可能性が高く、命令では、正しく表現できないためです。\n例えば、注文が確定した際に、以下の処理が実行されることがあります。\n在庫の変更 ユーザーのアップグレード セールの終了 EventBusの簡易実装 イベントを配送する仕組みを簡単に実装すると次のようになります。\nclass EventBus { // Map のキーがイベントの種類 // Map の値が、イベント発生時に実行する処理のリストです。 // 値がリストになっているのは、一つのイベントに対して // 複数の処理が必要になる可能性が高いためです。 private val handlers = mutableMapOf\u0026lt;Class\u0026lt;*\u0026gt;, MutableList\u0026lt;(Any) -\u0026gt; Unit\u0026gt;\u0026gt;() fun \u0026lt;T : Any\u0026gt; subscribe( eventType: Class\u0026lt;T\u0026gt;, handler: (T) -\u0026gt; Unit ) { handlers .getOrPut(eventType) { mutableListOf() } .add(handler as (Any) -\u0026gt; Unit) } // 渡されてきたイベントの型に応じて、 // そのイベントに紐づく処理を順番に実行します。 fun publish(event: Any) { handlers[event::class.java]?.forEach { handler -\u0026gt; // イベントに紐づく処理を一つずつ実行する。 handler(event) // handler は関数型なので、 // handler.invoke(event) // でも同じです。 } } } イベントハンドラ class UpgradeUserHandler( private val userRepository: UserRepository ) { fun handle(event: OrderPlaced) { val user = userRepository.find(event.userId) user.upgradeToPremium() userRepository.save(user) } } ハンドラ登録 アプリ起動時にイベントハンドラを登録します。\nval eventBus = EventBus() val handler = UpgradeUserHandler(userRepository) eventBus.subscribe(OrderPlaced::class.java) { event -\u0026gt; // event は OrderPlaced のインスタンスです。 // EventBus クラスの publish 関数の引数で渡されます。 handler.handle(event) } イベントの流れ 全体の流れは次のようになります。\n注文確定 ↓ OrderPlacedイベント発行 ↓ EventBusがハンドラに通知 ↓ User集約を更新 つまり\nOrderトランザクション ↓ イベント ↓ User更新 という構造にできます。\nこのようにすると\nトランザクションを分離できる 非同期処理に拡張できる マイクロサービスにも対応しやすい というメリットがあります。\nまとめ オブジェクト参照\norder.user.upgrade() 問題\n集約境界が見えにくい 無意識に複数集約を更新してしまう ID参照\nval user = userRepository.find(order.userId) メリット\n集約境界が明確 別集約操作を意識できる イベント駆動設計に拡張できる DDDの重要な考え方は次の一文にまとめられます。\n集約 = トランザクション境界 つまり\n1トランザクション ↓ 1集約 この境界を守るために、\n集約ルート ID参照 ドメインイベント といった設計ルールが使われています。\n","permalink":"https://design.okuda-studio.com/posts/0019-reference-by-id/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E5%8F%82%E7%85%A7%E3%81%AE%E5%A0%B4%E5%90%88\"\u003eオブジェクト参照の場合\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#order\"\u003eOrder\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#user\"\u003eUser\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9\"\u003eアプリケーションサービス\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#id%E5%8F%82%E7%85%A7%E3%81%AE%E5%A0%B4%E5%90%88\"\u003eID参照の場合\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#order-1\"\u003eOrder\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#user-1\"\u003eUser\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9-1\"\u003eアプリケーションサービス\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%81%95%E3%81%84%E3%82%92%E6%95%B4%E7%90%86\"\u003e違いを整理\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E5%8F%82%E7%85%A7\"\u003eオブジェクト参照\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#id%E5%8F%82%E7%85%A7\"\u003eID参照\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%82%E3%81%86%E4%B8%80%E3%81%A4%E9%87%8D%E8%A6%81%E3%81%AA%E9%81%95%E3%81%84%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E9%A7%86%E5%8B%95%E3%81%AB%E6%8B%A1%E5%BC%B5%E3%81%A7%E3%81%8D%E3%82%8B\"\u003eもう一つ重要な違い：イベント駆動に拡張できる\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#application-service\"\u003eApplication Service\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AE%E5%AE%9A%E7%BE%A9\"\u003eイベントの定義\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#eventbus%E3%81%AE%E7%B0%A1%E6%98%93%E5%AE%9F%E8%A3%85\"\u003eEventBusの簡易実装\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%83%8F%E3%83%B3%E3%83%89%E3%83%A9\"\u003eイベントハンドラ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%8F%E3%83%B3%E3%83%89%E3%83%A9%E7%99%BB%E9%8C%B2\"\u003eハンドラ登録\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AE%E6%B5%81%E3%82%8C\"\u003eイベントの流れ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eドメイン駆動設計（DDD）では、次のようなルールをよく目にします。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e集約は他の集約を \u003cstrong\u003eIDで参照する\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eしかし、初めてこのルールを見たときに疑問が浮かびます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eID参照にしても結局 \u003ccode\u003eRepository.find(id)\u003c/code\u003e で取得できるのでは？\u003c/li\u003e\n\u003cli\u003eそれなら普通のオブジェクト参照とあまり変わらないのでは？\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの記事では、このルールの意味を \u003cstrong\u003e実際のコードで比較しながら\u003c/strong\u003e説明します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"オブジェクト参照の場合\"\u003eオブジェクト参照の場合\u003c/h1\u003e\n\u003cp\u003eまず、他の集約を \u003cstrong\u003eオブジェクトとして直接持つ設計\u003c/strong\u003eを見てみます。\u003c/p\u003e\n\u003ch2 id=\"order\"\u003eOrder\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eOrder\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e id: OrderId,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e user: User\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efun\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eplace\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// 注文処理\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        user.upgradeToPremium()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003etips : place という単語には、 注文を出す / 発注する という意味があります。\u003c/p\u003e\n\u003ch2 id=\"user\"\u003eUser\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eUser\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e id: UserId,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e plan: Plan\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efun\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eupgradeToPremium\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        plan = \u003cspan style=\"color:#a6e22e\"\u003ePlan\u003c/span\u003e.PREMIUM\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"アプリケーションサービス\"\u003eアプリケーションサービス\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efun\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eplaceOrder\u003c/span\u003e(orderId: OrderId) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e order = orderRepository.find(orderId)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    order.place()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    orderRepository.save(order)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eここで起きていることを図にすると次のようになります。\u003c/p\u003e","title":"DDDで「集約はIDで参照する」とはどういう意味か"},{"content":" 1. 不変条件を同時に守る必要があるか（最重要） 例 別集約になる例 2. ライフサイクルが一緒か 例 別集約の例 3. 集約は他の集約をIDで参照する 4. 同時に更新されるか 例 5. 集約は小さく保つ まとめ ドメイン駆動設計（DDD）で設計をしていると、次のような疑問に必ずぶつかります。\nこのエンティティは同じ集約に入れるべきか？ それとも別の集約として切り離すべきか？ 集約の境界は、DDDにおいて非常に重要な設計判断です。 この記事では、実務でよく使われる判断基準を整理します。\n1. 不変条件を同時に守る必要があるか（最重要） 最も重要な基準は 不変条件（Invariant） です。\n「このルールは常に同時に成立している必要があるか？」\nYESなら 同じ集約 NOなら 別集約 例 注文と注文明細\nOrder └ OrderItem 不変条件\n注文の合計金額 = 各注文金額の合計 注文明細の数量 ≥ 1 数量が変われば、注文全体の合計金額は変わります。 つまり、これらは 常に同時に成立している必要があります。 そのため Order と OrderItem は 同じ集約になります。\n別集約になる例 Order Inventory (在庫) ルール\n注文が確定したら在庫を減らす この処理は\n注文確定 在庫更新 の2つの処理に分かれます。\nこれらは 同時トランザクションでなくても問題ないため\nOrder集約 Inventory集約 と分けます。\n2. ライフサイクルが一緒か 次に考えるのは ライフサイクルです。\n「一緒に生まれて一緒に消えるか？」\nYES → 同じ集約 NO → 別集約 例 Order └ OrderItem OrderItem は\nOrder が作られるときに作られる Order が削除されるときに削除される つまり 独立した存在ではないため、同じ集約に含まれます。\n別集約の例 User Order Order は\nUser が削除されても履歴として残る このように ライフサイクルが独立しているため、別集約になります。\n3. 集約は他の集約をIDで参照する DDDでは次のルールがよく使われます。\n集約は他の集約をIDで参照する\nOK\nOrder └ userId NG\nOrder └ Userオブジェクト 集約間はオブジェクト参照ではなく ID 参照にします。 これは「IDで参照できるなら別集約」という意味ではなく、 「別集約である場合は ID で参照する」というルールです。\nこのルールを守ることで、集約間の結合度を下げることができます。\n具体例は別の記事 (DDDで「集約はIDで参照する」とはどういう意味か) を参照してください。\n4. 同時に更新されるか もう一つの判断基準は 更新タイミングです。\n「この2つはいつも一緒に更新されるか？」\nYES → 同じ集約の可能性 NO → 別集約 例 Order Payment 多くのシステムでは\n注文作成 決済 は別タイミングで行われます。\nそのため\nOrder集約 Payment集約 のように分けることが多いです。\n5. 集約は小さく保つ DDDではよく次の原則が言われます。\n集約は小さく保つ\n巨大な集約を作ると\nトランザクションが重くなる ロック競合が増える スケールしにくくなる といった問題が起きます。\nそのため、迷った場合は 小さく分ける方向で設計することが多いです。\nまとめ 集約を設計する際は、次の質問を自分に投げかけると整理しやすくなります。\nこの不変条件は同時に守る必要があるか？ 一緒に生まれて一緒に消えるか？ 片方だけ更新されるケースはあるか？ トランザクションを分けても問題ないか？ 特に重要なのは次の考え方です。\n「どの不変条件をトランザクションで守るか」\nこれが、そのまま 集約の境界になります。\n集約設計はDDDの中でも難しい部分ですが、この視点を持つと設計の判断がしやすくなります。\n","permalink":"https://design.okuda-studio.com/posts/0018-aggregation-separation/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#1-%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6%E3%82%92%E5%90%8C%E6%99%82%E3%81%AB%E5%AE%88%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8B%E3%81%8B%E6%9C%80%E9%87%8D%E8%A6%81\"\u003e1. 不変条件を同時に守る必要があるか（最重要）\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8B\"\u003e例\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A5%E9%9B%86%E7%B4%84%E3%81%AB%E3%81%AA%E3%82%8B%E4%BE%8B\"\u003e別集約になる例\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#2-%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B5%E3%82%A4%E3%82%AF%E3%83%AB%E3%81%8C%E4%B8%80%E7%B7%92%E3%81%8B\"\u003e2. ライフサイクルが一緒か\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8B-1\"\u003e例\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A5%E9%9B%86%E7%B4%84%E3%81%AE%E4%BE%8B\"\u003e別集約の例\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#3-%E9%9B%86%E7%B4%84%E3%81%AF%E4%BB%96%E3%81%AE%E9%9B%86%E7%B4%84%E3%82%92id%E3%81%A7%E5%8F%82%E7%85%A7%E3%81%99%E3%82%8B\"\u003e3. 集約は他の集約をIDで参照する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#4-%E5%90%8C%E6%99%82%E3%81%AB%E6%9B%B4%E6%96%B0%E3%81%95%E3%82%8C%E3%82%8B%E3%81%8B\"\u003e4. 同時に更新されるか\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8B-2\"\u003e例\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#5-%E9%9B%86%E7%B4%84%E3%81%AF%E5%B0%8F%E3%81%95%E3%81%8F%E4%BF%9D%E3%81%A4\"\u003e5. 集約は小さく保つ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eドメイン駆動設計（DDD）で設計をしていると、次のような疑問に必ずぶつかります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこのエンティティは同じ集約に入れるべきか？\u003c/li\u003e\n\u003cli\u003eそれとも別の集約として切り離すべきか？\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e集約の境界は、DDDにおいて非常に重要な設計判断です。\nこの記事では、実務でよく使われる判断基準を整理します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"1-不変条件を同時に守る必要があるか最重要\"\u003e1. 不変条件を同時に守る必要があるか（最重要）\u003c/h2\u003e\n\u003cp\u003e最も重要な基準は \u003cstrong\u003e不変条件（Invariant）\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e「このルールは常に同時に成立している必要があるか？」\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eYESなら \u003cstrong\u003e同じ集約\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003eNOなら \u003cstrong\u003e別集約\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"例\"\u003e例\u003c/h3\u003e\n\u003cp\u003e注文と注文明細\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eOrder\n └ OrderItem\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e不変条件\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e注文の合計金額 = 各注文金額の合計\u003c/li\u003e\n\u003cli\u003e注文明細の数量 ≥ 1\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e数量が変われば、注文全体の合計金額は変わります。\nつまり、これらは \u003cstrong\u003e常に同時に成立している必要\u003c/strong\u003eがあります。\nそのため \u003ccode\u003eOrder\u003c/code\u003e と \u003ccode\u003eOrderItem\u003c/code\u003e は \u003cstrong\u003e同じ集約\u003c/strong\u003eになります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"別集約になる例\"\u003e別集約になる例\u003c/h3\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eOrder\nInventory (在庫)\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eルール\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e注文が確定したら在庫を減らす\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eこの処理は\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e注文確定\u003c/li\u003e\n\u003cli\u003e在庫更新\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eの2つの処理に分かれます。\u003c/p\u003e\n\u003cp\u003eこれらは \u003cstrong\u003e同時トランザクションでなくても問題ない\u003c/strong\u003eため\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eOrder集約\nInventory集約\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eと分けます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"2-ライフサイクルが一緒か\"\u003e2. ライフサイクルが一緒か\u003c/h2\u003e\n\u003cp\u003e次に考えるのは \u003cstrong\u003eライフサイクル\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e「一緒に生まれて一緒に消えるか？」\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eYES → 同じ集約\u003c/li\u003e\n\u003cli\u003eNO → 別集約\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"例-1\"\u003e例\u003c/h3\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eOrder\n └ OrderItem\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ccode\u003eOrderItem\u003c/code\u003e は\u003c/p\u003e","title":"一つの集約にまとめるべきか、別の集約に分けるべきかの判断基準（DDD）"},{"content":"このドキュメントは、DDD（ドメイン駆動設計）に基づいて、ソフトウェアを設計するためのテンプレートです。\n上から順番にテンプレートを埋めていくことで、 DDD に基づいたドメイン周りの設計がスムーズに行えるように作っています。\n1. システム概要 システムの目的 対象ユーザー 解決したい課題 2. ユースケース ユースケース一覧 ユースケース詳細 【例】振替関係を作成する 入力 処理概要 出力 3. ユビキタス言語 概念 候補とその言葉のイメージ 賛否の意見 言葉の決定とその採用理由 ユビキタス言語辞書 4. エンティティ候補 5. 不変条件（Invariant） 6. 状態遷移 【例】TransferRelation 状態 状態遷移 7. 集約設計 集約一覧 集約詳細 【例】TransferRelation 属性 不変条件 ドメインメソッド 8. ドメインサービス サービス一覧 サービス詳細 【例】TransferService 9. リポジトリ 10. ユースケース設計 UseCase一覧 UseCase詳細 【例】CreateTransferRelationUseCase 処理 1. システム概要 システムの目的 このシステムは何を解決するものか。\n【例】\nフリーランスの固定費を管理する 口座振替の関係を可視化する 対象ユーザー このシステムのユーザー。\n【例】\n個人 フリーランス 企業 解決したい課題 【例】\n固定費の支払い関係が分かりにくい 口座振替の全体構造を把握できない 2. ユースケース ユーザーがシステムで行う操作を列挙する。\nユースケース一覧 【例】\n○○を作成する ○○を変更する ○○を削除する ○○を確認する ユースケース詳細 【例】振替関係を作成する 入力 【例】\naccountId serviceId paymentDay 処理概要 【例】\n口座を取得 サービスを取得 振替関係を作成 保存 出力 【例】\n振替関係ID 3. ユビキタス言語 ドメインで使う用語を定義する。\n概念は何度か練り直すと、よい概念に落ち着きやすい。\n日本語だけではなく、英語でも定義する。\n英語は実装時に使用する。\n過不足なく正確に伝わる英単語が存在するかどうかも、日本語選定の基準となります。\n概念 【例】\nお金を支払う対象となるサービス。\n候補とその言葉のイメージ 【例】\n振替先 口座からお金が引き落とされる対象 支払い先 ユーザーがお金を支払う相手 請求元 請求を発行する会社 引き落とし先 銀行口座から自動的にお金が引き落とされる相手 賛否の意見 【例】\n振替先 銀行用語っぽい 一般ユーザーが使う言葉ではない 支払い先 手動支払いも含みそう 請求元 請求書前提 引き落とし先 意味は近いが長い 言葉の決定とその採用理由 【例】\n採用 支払い先 理由 一般ユーザーが理解しやすい サービスにも会社にも使える ユビキタス言語辞書 【例】\n用語(日本語) 用語(英語) 意味 支払元 Payer 発生した支払いに対して、お金が出ていくところ 支払先 Payee お金を支払う対象となるサービス 支払関係 PaymentRelation 支払先と支払元の紐づけ 4. エンティティ候補 ドメインの中心となる概念。\n【例】\nAccount Service TransferRelation TransferSchedule 5. 不変条件（Invariant） 絶対に破ってはいけないルール。\n【例】\n振替関係は必ず1つの口座を持つ 振替関係は必ず1つのサービスを持つ 振替日は1〜31 同じ口座 + サービスの振替関係は1つだけ 6. 状態遷移 状態を持つエンティティについて整理する。\n【例】TransferRelation 状態 【例】\nCreated Active Stopped Deleted 状態遷移 【例】\nCreated → Active Active → Stopped Stopped → Active Active → Deleted 7. 集約設計 集約一覧 【例】\nTransferRelation Account 集約詳細 【例】TransferRelation 属性 【例】\naccountId serviceId paymentDay status 不変条件 【例】\n振替日は1〜31 同じ口座 + サービスの振替関係は1つだけ ドメインメソッド 【例】\nchangePaymentDay() stop() resume() 8. ドメインサービス エンティティに属さないドメインロジック。\nサービス一覧 【例】\nTransferService サービス詳細 【例】TransferService 責務 【例】 口座Aから口座Bへの送金 メソッド 【例】 transfer(fromAccount, toAccount, amount) 9. リポジトリ 集約の永続化を担当。\n【例】\nAccountRepository TransferRelationRepository 10. ユースケース設計 UseCase一覧 【例】\nCreateTransferRelationUseCase StopTransferRelationUseCase UseCase詳細 【例】CreateTransferRelationUseCase 処理 【例】\n振替関係の作成 account取得 service取得 TransferRelation生成 保存 ","permalink":"https://design.okuda-studio.com/posts/0016-ddd-practice-template/","summary":"\u003cp\u003eこのドキュメントは、DDD（ドメイン駆動設計）に基づいて、ソフトウェアを設計するためのテンプレートです。\u003c/p\u003e\n\u003cp\u003e上から順番にテンプレートを埋めていくことで、 DDD に基づいたドメイン周りの設計がスムーズに行えるように作っています。\u003c/p\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#1-%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E6%A6%82%E8%A6%81\"\u003e1. システム概要\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AE%E7%9B%AE%E7%9A%84\"\u003eシステムの目的\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%AF%BE%E8%B1%A1%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC\"\u003e対象ユーザー\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A7%A3%E6%B1%BA%E3%81%97%E3%81%9F%E3%81%84%E8%AA%B2%E9%A1%8C\"\u003e解決したい課題\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#2-%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9\"\u003e2. ユースケース\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9%E4%B8%80%E8%A6%A7\"\u003eユースケース一覧\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9%E8%A9%B3%E7%B4%B0\"\u003eユースケース詳細\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8B%E6%8C%AF%E6%9B%BF%E9%96%A2%E4%BF%82%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B\"\u003e【例】振替関係を作成する\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%85%A5%E5%8A%9B\"\u003e入力\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%87%A6%E7%90%86%E6%A6%82%E8%A6%81\"\u003e処理概要\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%87%BA%E5%8A%9B\"\u003e出力\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#3-%E3%83%A6%E3%83%93%E3%82%AD%E3%82%BF%E3%82%B9%E8%A8%80%E8%AA%9E\"\u003e3. ユビキタス言語\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E6%A6%82%E5%BF%B5\"\u003e概念\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%80%99%E8%A3%9C%E3%81%A8%E3%81%9D%E3%81%AE%E8%A8%80%E8%91%89%E3%81%AE%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8\"\u003e候補とその言葉のイメージ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%B3%9B%E5%90%A6%E3%81%AE%E6%84%8F%E8%A6%8B\"\u003e賛否の意見\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%80%E8%91%89%E3%81%AE%E6%B1%BA%E5%AE%9A%E3%81%A8%E3%81%9D%E3%81%AE%E6%8E%A1%E7%94%A8%E7%90%86%E7%94%B1\"\u003e言葉の決定とその採用理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A6%E3%83%93%E3%82%AD%E3%82%BF%E3%82%B9%E8%A8%80%E8%AA%9E%E8%BE%9E%E6%9B%B8\"\u003eユビキタス言語辞書\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#4-%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%83%86%E3%82%A3%E5%80%99%E8%A3%9C\"\u003e4. エンティティ候補\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#5-%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6invariant\"\u003e5. 不変条件（Invariant）\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#6-%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB\"\u003e6. 状態遷移\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8Btransferrelation\"\u003e【例】TransferRelation\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B\"\u003e状態\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB\"\u003e状態遷移\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#7-%E9%9B%86%E7%B4%84%E8%A8%AD%E8%A8%88\"\u003e7. 集約設計\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E9%9B%86%E7%B4%84%E4%B8%80%E8%A6%A7\"\u003e集約一覧\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%9B%86%E7%B4%84%E8%A9%B3%E7%B4%B0\"\u003e集約詳細\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8Btransferrelation-1\"\u003e【例】TransferRelation\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%B1%9E%E6%80%A7\"\u003e属性\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6\"\u003e不変条件\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89\"\u003eドメインメソッド\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#8-%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9\"\u003e8. ドメインサービス\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E4%B8%80%E8%A6%A7\"\u003eサービス一覧\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E8%A9%B3%E7%B4%B0\"\u003eサービス詳細\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8Btransferservice\"\u003e【例】TransferService\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#9-%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA\"\u003e9. リポジトリ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#10-%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9%E8%A8%AD%E8%A8%88\"\u003e10. ユースケース設計\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#usecase%E4%B8%80%E8%A6%A7\"\u003eUseCase一覧\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#usecase%E8%A9%B3%E7%B4%B0\"\u003eUseCase詳細\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8Bcreatetransferrelationusecase\"\u003e【例】CreateTransferRelationUseCase\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%87%A6%E7%90%86\"\u003e処理\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"1-システム概要\"\u003e1. システム概要\u003c/h1\u003e\n\u003ch2 id=\"システムの目的\"\u003eシステムの目的\u003c/h2\u003e\n\u003cp\u003eこのシステムは何を解決するものか。\u003c/p\u003e\n\u003cp\u003e【例】\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eフリーランスの固定費を管理する\u003c/li\u003e\n\u003cli\u003e口座振替の関係を可視化する\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"対象ユーザー\"\u003e対象ユーザー\u003c/h2\u003e\n\u003cp\u003eこのシステムのユーザー。\u003c/p\u003e\n\u003cp\u003e【例】\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e個人\u003c/li\u003e\n\u003cli\u003eフリーランス\u003c/li\u003e\n\u003cli\u003e企業\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"解決したい課題\"\u003e解決したい課題\u003c/h2\u003e\n\u003cp\u003e【例】\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e固定費の支払い関係が分かりにくい\u003c/li\u003e\n\u003cli\u003e口座振替の全体構造を把握できない\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch1 id=\"2-ユースケース\"\u003e2. ユースケース\u003c/h1\u003e\n\u003cp\u003eユーザーがシステムで行う操作を列挙する。\u003c/p\u003e","title":"ドメイン設計テンプレート"},{"content":"このドキュメントは、 ドメイン設計テンプレート に以下の項目を加えた補強版となっています。\n4.境界コンテキスト 5.コンテキストマップ 7.値オブジェクト 12.ドメインイベント 15.集約境界図 16.不変条件の責任 1. システム概要 システムの目的 対象ユーザー 解決したい課題 2. ユースケース ユースケース一覧 ユースケース詳細 【例】振替関係を作成する 入力 処理概要 出力 3. ユビキタス言語 概念 候補とその言葉のイメージ 賛否の意見 言葉の決定とその採用理由 ユビキタス言語辞書 4. 境界コンテキスト 5. コンテキストマップ 6. エンティティ候補 7. 値オブジェクト 8. 不変条件（Invariant） 9. 状態遷移 【例】TransferRelation 状態 状態遷移 10. 集約設計 集約一覧 集約詳細 【例】TransferRelation 属性 不変条件 ドメインメソッド 11. ドメインサービス サービス一覧 サービス詳細 【例】TransferService 12. ドメインイベント イベント詳細 【例】TransferRelationCreated 発生タイミング ペイロード 13. リポジトリ 14. ユースケース設計 UseCase一覧 UseCase詳細 【例】CreateTransferRelationUseCase 処理 15. 集約境界図（Aggregate Boundary） 【例】TransferRelation 集約名 / Aggregate Root 内部エンティティ 値オブジェクト 集約境界 外部参照 集約ルール 16. 不変条件の責任（Invariant Responsibility） 不変条件一覧 不変条件の責任 振替日は1〜31 同じ口座 + サービスの振替関係は1つだけ 振替関係は必ず口座を持つ 振替関係は必ずサービスを持つ 不変条件の配置ルール 例 1. システム概要 システムの目的 このシステムは何を解決するものか。\n【例】\nフリーランスの固定費を管理する 口座振替の関係を可視化する 対象ユーザー このシステムのユーザー。\n【例】\n個人 フリーランス 企業 解決したい課題 【例】\n固定費の支払い関係が分かりにくい 口座振替の全体構造を把握できない 2. ユースケース ユーザーがシステムで行う操作を列挙する。\nユースケース一覧 【例】\n○○を作成する ○○を変更する ○○を削除する ○○を確認する ユースケース詳細 【例】振替関係を作成する 入力 【例】\naccountId serviceId paymentDay 処理概要 【例】\n口座を取得 サービスを取得 振替関係を作成 保存 出力 【例】\n振替関係ID 3. ユビキタス言語 ドメインで使う用語を定義する。\n概念は何度か練り直すと、よい概念に落ち着きやすい。\n日本語だけではなく、英語でも定義する。\n英語は実装時に使用する。\n過不足なく正確に伝わる英単語が存在するかどうかも、日本語選定の基準となります。\n概念 【例】\nお金を支払う対象となるサービス。\n候補とその言葉のイメージ 【例】\n振替先 口座からお金が引き落とされる対象 支払い先 ユーザーがお金を支払う相手 請求元 請求を発行する会社 引き落とし先 銀行口座から自動的にお金が引き落とされる相手 賛否の意見 【例】\n振替先 銀行用語っぽい 一般ユーザーが使う言葉ではない 支払い先 手動支払いも含みそう 請求元 請求書前提 引き落とし先 意味は近いが長い 言葉の決定とその採用理由 【例】\n採用 支払い先 理由 一般ユーザーが理解しやすい サービスにも会社にも使える ユビキタス言語辞書 【例】\n用語(日本語) 用語(英語) 意味 支払元 Payer 発生した支払いに対して、お金が出ていくところ 支払先 Payee お金を支払う対象となるサービス 支払関係 PaymentRelation 支払先と支払元の紐づけ 4. 境界コンテキスト ドメインをコンテキストに分割する。\n【例】\nPaymentContext AccountContext ServiceContext 5. コンテキストマップ コンテキスト間の関係。\nAccountContext ↓ PaymentContext ↓ ServiceContext 関係タイプ\nCustomer/Supplier Shared Kernel Conformist 6. エンティティ候補 ドメインの中心となる概念。\n【例】\nAccount Service TransferRelation TransferSchedule 7. 値オブジェクト 値として扱う概念。\n【例】\nPaymentDay Money AccountId ServiceId 8. 不変条件（Invariant） 絶対に破ってはいけないルール。\n【例】\n振替関係は必ず1つの口座を持つ 振替関係は必ず1つのサービスを持つ 振替日は1〜31 同じ口座 + サービスの振替関係は1つだけ 9. 状態遷移 状態を持つエンティティについて整理する。\n【例】TransferRelation 状態 【例】\nCreated Active Stopped Deleted 状態遷移 【例】\nCreated → Active Active → Stopped Stopped → Active Active → Deleted 10. 集約設計 集約一覧 【例】\nTransferRelation Account 集約詳細 【例】TransferRelation 属性 【例】\naccountId serviceId paymentDay status 不変条件 【例】\n振替日は1〜31 同じ口座 + サービスの振替関係は1つだけ ドメインメソッド 【例】\nchangePaymentDay() stop() resume() 11. ドメインサービス エンティティに属さないドメインロジック。\nサービス一覧 【例】\nTransferService サービス詳細 【例】TransferService 責務 【例】 口座Aから口座Bへの送金 メソッド 【例】 transfer(fromAccount, toAccount, amount) 12. ドメインイベント 重要なドメインの出来事。\n【例】\nTransferRelationCreated PaymentDayChanged TransferStopped イベント詳細 【例】TransferRelationCreated 発生タイミング 振替関係作成時\nペイロード transferRelationId accountId serviceId 13. リポジトリ 集約の永続化を担当。\n【例】\nAccountRepository TransferRelationRepository 14. ユースケース設計 UseCase一覧 【例】\nCreateTransferRelationUseCase StopTransferRelationUseCase UseCase詳細 【例】CreateTransferRelationUseCase 処理 【例】\n振替関係の作成 account取得 service取得 TransferRelation生成 保存 15. 集約境界図（Aggregate Boundary） 集約の内部構造と境界を明確にする。 「どこまでが1つの整合性の単位なのか」を定義する。 【例】TransferRelation 集約名 / Aggregate Root TransferRelation\n内部エンティティ 【例】\nTransferSchedule 値オブジェクト PaymentDay TransferRelationId AccountId ServiceId 集約境界 TransferRelation (Aggregate Root) ├ transferRelationId ├ accountId ├ serviceId ├ paymentDay └ status 外部参照 この集約が参照する他集約\nAccountId ServiceId ※ 集約間は ID参照のみ とする\n集約ルール 外部からは Aggregate Root を通してのみ操作可能 集約内部の整合性は トランザクションで保証 16. 不変条件の責任（Invariant Responsibility） 不変条件を「どこで守るのか」を明確にする。\nDDDではこれが非常に重要。\n不変条件一覧 【例】\n振替日は1〜31 同じ口座 + サービスの振替関係は1つだけ 振替関係は必ず口座を持つ 振替関係は必ずサービスを持つ 不変条件の責任 振替日は1〜31 責任 PaymentDay（ValueObject） 理由 値として常に正しい状態を保証する。 同じ口座 + サービスの振替関係は1つだけ 責任 TransferRelationRepository 理由 既存データを確認する必要があるため。 振替関係は必ず口座を持つ 責任 TransferRelation（Aggregate） 理由 生成時に保証する。 振替関係は必ずサービスを持つ 責任 TransferRelation（Aggregate） 理由 生成時に保証する。 不変条件の配置ルール 不変条件は次の順序で配置する。\nValueObject Aggregate DomainService Repository できるだけ 内側に置く。\n例 PaymentDay └ 1〜31 TransferRelation └ 必ずAccountを持つ TransferRelationRepository └ 重複禁止 ","permalink":"https://design.okuda-studio.com/posts/0017-ddd-practice-template2/","summary":"\u003cp\u003eこのドキュメントは、 \u003ca href=\"https://design.okuda-studio.com/posts/0016-ddd-practice-template/\"\u003eドメイン設計テンプレート\u003c/a\u003e に以下の項目を加えた補強版となっています。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e4.境界コンテキスト\u003c/li\u003e\n\u003cli\u003e5.コンテキストマップ\u003c/li\u003e\n\u003cli\u003e7.値オブジェクト\u003c/li\u003e\n\u003cli\u003e12.ドメインイベント\u003c/li\u003e\n\u003cli\u003e15.集約境界図\u003c/li\u003e\n\u003cli\u003e16.不変条件の責任\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#1-%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E6%A6%82%E8%A6%81\"\u003e1. システム概要\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AE%E7%9B%AE%E7%9A%84\"\u003eシステムの目的\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%AF%BE%E8%B1%A1%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC\"\u003e対象ユーザー\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A7%A3%E6%B1%BA%E3%81%97%E3%81%9F%E3%81%84%E8%AA%B2%E9%A1%8C\"\u003e解決したい課題\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#2-%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9\"\u003e2. ユースケース\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9%E4%B8%80%E8%A6%A7\"\u003eユースケース一覧\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9%E8%A9%B3%E7%B4%B0\"\u003eユースケース詳細\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8B%E6%8C%AF%E6%9B%BF%E9%96%A2%E4%BF%82%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B\"\u003e【例】振替関係を作成する\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%85%A5%E5%8A%9B\"\u003e入力\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%87%A6%E7%90%86%E6%A6%82%E8%A6%81\"\u003e処理概要\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%87%BA%E5%8A%9B\"\u003e出力\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#3-%E3%83%A6%E3%83%93%E3%82%AD%E3%82%BF%E3%82%B9%E8%A8%80%E8%AA%9E\"\u003e3. ユビキタス言語\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E6%A6%82%E5%BF%B5\"\u003e概念\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%80%99%E8%A3%9C%E3%81%A8%E3%81%9D%E3%81%AE%E8%A8%80%E8%91%89%E3%81%AE%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8\"\u003e候補とその言葉のイメージ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%B3%9B%E5%90%A6%E3%81%AE%E6%84%8F%E8%A6%8B\"\u003e賛否の意見\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%80%E8%91%89%E3%81%AE%E6%B1%BA%E5%AE%9A%E3%81%A8%E3%81%9D%E3%81%AE%E6%8E%A1%E7%94%A8%E7%90%86%E7%94%B1\"\u003e言葉の決定とその採用理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A6%E3%83%93%E3%82%AD%E3%82%BF%E3%82%B9%E8%A8%80%E8%AA%9E%E8%BE%9E%E6%9B%B8\"\u003eユビキタス言語辞書\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#4-%E5%A2%83%E7%95%8C%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88\"\u003e4. 境界コンテキスト\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#5-%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%83%9E%E3%83%83%E3%83%97\"\u003e5. コンテキストマップ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#6-%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%83%86%E3%82%A3%E5%80%99%E8%A3%9C\"\u003e6. エンティティ候補\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#7-%E5%80%A4%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88\"\u003e7. 値オブジェクト\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#8-%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6invariant\"\u003e8. 不変条件（Invariant）\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#9-%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB\"\u003e9. 状態遷移\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8Btransferrelation\"\u003e【例】TransferRelation\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B\"\u003e状態\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB\"\u003e状態遷移\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#10-%E9%9B%86%E7%B4%84%E8%A8%AD%E8%A8%88\"\u003e10. 集約設計\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E9%9B%86%E7%B4%84%E4%B8%80%E8%A6%A7\"\u003e集約一覧\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%9B%86%E7%B4%84%E8%A9%B3%E7%B4%B0\"\u003e集約詳細\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8Btransferrelation-1\"\u003e【例】TransferRelation\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%B1%9E%E6%80%A7\"\u003e属性\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6\"\u003e不変条件\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89\"\u003eドメインメソッド\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#11-%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9\"\u003e11. ドメインサービス\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E4%B8%80%E8%A6%A7\"\u003eサービス一覧\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E8%A9%B3%E7%B4%B0\"\u003eサービス詳細\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8Btransferservice\"\u003e【例】TransferService\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#12-%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88\"\u003e12. ドメインイベント\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E8%A9%B3%E7%B4%B0\"\u003eイベント詳細\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8Btransferrelationcreated\"\u003e【例】TransferRelationCreated\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E7%99%BA%E7%94%9F%E3%82%BF%E3%82%A4%E3%83%9F%E3%83%B3%E3%82%B0\"\u003e発生タイミング\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%9A%E3%82%A4%E3%83%AD%E3%83%BC%E3%83%89\"\u003eペイロード\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#13-%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA\"\u003e13. リポジトリ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#14-%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9%E8%A8%AD%E8%A8%88\"\u003e14. ユースケース設計\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#usecase%E4%B8%80%E8%A6%A7\"\u003eUseCase一覧\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#usecase%E8%A9%B3%E7%B4%B0\"\u003eUseCase詳細\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8Bcreatetransferrelationusecase\"\u003e【例】CreateTransferRelationUseCase\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%87%A6%E7%90%86\"\u003e処理\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#15-%E9%9B%86%E7%B4%84%E5%A2%83%E7%95%8C%E5%9B%B3aggregate-boundary\"\u003e15. 集約境界図（Aggregate Boundary）\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8Btransferrelation-2\"\u003e【例】TransferRelation\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E9%9B%86%E7%B4%84%E5%90%8D--aggregate-root\"\u003e集約名 / Aggregate Root\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%86%85%E9%83%A8%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%83%86%E3%82%A3\"\u003e内部エンティティ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%80%A4%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88\"\u003e値オブジェクト\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%9B%86%E7%B4%84%E5%A2%83%E7%95%8C\"\u003e集約境界\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%A4%96%E9%83%A8%E5%8F%82%E7%85%A7\"\u003e外部参照\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%9B%86%E7%B4%84%E3%83%AB%E3%83%BC%E3%83%AB\"\u003e集約ルール\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#16-%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6%E3%81%AE%E8%B2%AC%E4%BB%BBinvariant-responsibility\"\u003e16. 不変条件の責任（Invariant Responsibility）\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6%E4%B8%80%E8%A6%A7\"\u003e不変条件一覧\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6%E3%81%AE%E8%B2%AC%E4%BB%BB\"\u003e不変条件の責任\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E6%8C%AF%E6%9B%BF%E6%97%A5%E3%81%AF131\"\u003e振替日は1〜31\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%90%8C%E3%81%98%E5%8F%A3%E5%BA%A7--%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AE%E6%8C%AF%E6%9B%BF%E9%96%A2%E4%BF%82%E3%81%AF1%E3%81%A4%E3%81%A0%E3%81%91\"\u003e同じ口座 + サービスの振替関係は1つだけ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%8C%AF%E6%9B%BF%E9%96%A2%E4%BF%82%E3%81%AF%E5%BF%85%E3%81%9A%E5%8F%A3%E5%BA%A7%E3%82%92%E6%8C%81%E3%81%A4\"\u003e振替関係は必ず口座を持つ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%8C%AF%E6%9B%BF%E9%96%A2%E4%BF%82%E3%81%AF%E5%BF%85%E3%81%9A%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E6%8C%81%E3%81%A4\"\u003e振替関係は必ずサービスを持つ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6%E3%81%AE%E9%85%8D%E7%BD%AE%E3%83%AB%E3%83%BC%E3%83%AB\"\u003e不変条件の配置ルール\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8B\"\u003e例\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"1-システム概要\"\u003e1. システム概要\u003c/h1\u003e\n\u003ch2 id=\"システムの目的\"\u003eシステムの目的\u003c/h2\u003e\n\u003cp\u003eこのシステムは何を解決するものか。\u003c/p\u003e","title":"ドメイン設計テンプレート（補強版）"},{"content":" DDDにおける「集約」「ドメインサービス」「ユースケース」の違い まず結論 集約（Aggregate） ドメインサービス ユースケース（Application Service） ドメインロジックをどこに置くか 状態を持つドメインサービスはどうなるか ケース1：新しいドメイン概念が生まれた ケース2：一時的な処理状態 判断のための質問 よくある失敗 まとめ DDDにおける「集約」「ドメインサービス」「ユースケース」の違い DDD（ドメイン駆動設計）を学び始めると、多くの人が次の疑問にぶつかります。\n集約とドメインサービスは何が違うのか ユースケースはどこまで責任を持つのか ドメインロジックはどこに書くべきなのか この記事では、この3つの概念を整理しながら、ドメインロジックをどこに置くべきかの判断基準を解説します。\nまず結論 3つの役割は次のように整理できます。\n集約（Aggregate）\nドメインの状態を持つ 不変条件を守る ドメインモデルの中心 ドメインサービス（Domain Service）\nエンティティに属さないドメインロジック 複数の集約にまたがる処理 ユースケース（Use Case / Application Service）\nユーザー操作を実現する手順 ドメインモデルを組み合わせる 依存関係は次のようになります。\nUI ↓ UseCase ↓ DomainService ↓ Aggregate 重要なルールは 内側の層は外側を知らないこと です。\n集約（Aggregate） 集約は 状態と不変条件を守るドメインモデル です。\n例として「口座振替」を考えます。\n振替関係には次のルールがあります。\n振替日は 1〜31 「振替元 + 振替先」が同じ振替関係は 1 つだけ (重複不可) このルールを守る主体が TransferRelation です。\nclass TransferRelation( val accountId: AccountId, val serviceId: ServiceId, private var paymentDay: PaymentDay ) { fun changePaymentDay(newDay: PaymentDay) { paymentDay = newDay } fun stop() { // 状態変更 } } 【集約の特徴】\n状態を持つ 不変条件を守る ドメインの中心となる概念 DDDでは、 まずは集約にロジックを入れることを検討します。\nドメインサービス ドメインサービスは 集約 (エンティティ) に入らないドメインロジック を表現します。\n典型的なケースは 複数の集約にまたがる処理 です。\n【例：銀行振込】\n処理内容\n口座Aから引き落とす 口座Bに入金する この処理は\nAccountA AccountB という 2つの集約 に関係します。\nそのため集約の責務にすると不自然になります。\nclass TransferService { fun transfer(from: Account, to: Account, amount: Money) { from.withdraw(amount) to.deposit(amount) } } ドメインサービスの特徴\n状態を持たない ドメインロジックを表す 複数の集約を扱う ユースケース（Application Service） ユースケースは アプリケーションの操作手順 を表します。\n【役割】\nユーザー操作を実現する ドメインモデルを組み合わせる Repositoryを呼び出す 【例】\nclass TransferUseCase( private val accountRepository: AccountRepository, private val transferService: TransferService ) { fun execute(fromId: AccountId, toId: AccountId, amount: Money) { val from = accountRepository.find(fromId) val to = accountRepository.find(toId) transferService.transfer(from, to, amount) accountRepository.save(from) accountRepository.save(to) } } 【ユースケースの特徴】\n手順を書く ドメインを呼び出す トランザクションを管理する ドメインロジックをどこに置くか 実務では次の順序で判断すると迷いません。\n① 1つの集約の状態だけで完結するか？\n→ 集約に入れる\n【例】\n振替日を変更する 注文をキャンセルする ② 複数の集約にまたがるか？\n→ ドメインサービス\n【例】\n口座A → 口座Bへの送金 ③ それでもドメインの概念に属さないか？\n→ ユースケース\n状態を持つドメインサービスはどうなるか DDDでは ドメインサービスは基本的に状態を持ちません。\nもし状態を持つようになった場合、次の可能性があります。\nケース1：新しいドメイン概念が生まれた 【例】\n以下の Service 「振込処理」があったとします。\nclass TransferService( val fromAccountId: AccountId, val toAccountId: AccountId, val amount: Money ) そこに TransferStatus という状態 (以下) が追加されたとします。\nPENDING PROCESSING COMPLETED FAILED すると次のようなモデリングが必要になります。\nclass Transfer( val fromAccountId: AccountId, val toAccountId: AccountId, val amount: Money, var status: TransferStatus ) つまり\nTransferService → Transfer（集約） という ドメイン概念の発見 が起こります。\nケース2：一時的な処理状態 例えば\nAPIリトライ回数 バッチ処理の進捗 などは ドメインの状態ではありません。\nこの場合は ユースケース（アプリケーション層） に置きます。\n判断のための質問 設計で迷ったときは次の質問をします。\nその状態はドメインの概念か？\nYES\n→ 新しいエンティティ（集約）\nNO\n→ アプリケーション層\nよくある失敗 DDD初心者がよくやる設計があります。\nUserService OrderService PaymentService AccountService これは ドメインモデル貧血症（Anemic Domain Model） と呼ばれます。\n原因は\nドメインロジックをすべてサービスに入れてしまうこと です。\nDDDでは逆のアプローチを取ります。\nロジックはまず集約に置く サービスは最小限にする まとめ 今回触れた DDD の 3 つの役割は次の通りです。\n集約\n状態を持つ 不変条件を守る ドメインモデルの中心 ドメインサービス\n集約に入らないドメインロジック 複数の集約を扱う ユースケース\nユーザー操作の手順 ドメインモデルを組み合わせる ドメインロジックを配置するときは次の順序で考えます。\nまず集約に入れる 複数の集約をまたぐ場合はドメインサービス そもそもドメイン概念に関係ない場合はユースケース DDDでは ドメインモデルは最初から完成しているものではありません。\n設計を進める中で\nサービスだったものがエンティティになる 新しい概念が見つかる ということがよく起こります。\nこの モデルを発見していくプロセス こそが、DDDの大きな特徴です。\n「この振る舞いは誰の責任か？」\nこの問いを繰り返すことで、集約、ドメインサービス、ユースケースは徐々に洗練されていきます。\n","permalink":"https://design.okuda-studio.com/posts/0015-aggregate-domain-service-usecase/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#ddd%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E9%9B%86%E7%B4%84%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9%E3%81%AE%E9%81%95%E3%81%84\"\u003eDDDにおける「集約」「ドメインサービス」「ユースケース」の違い\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%9A%E7%B5%90%E8%AB%96\"\u003eまず結論\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%9B%86%E7%B4%84aggregate\"\u003e集約（Aggregate）\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9\"\u003eドメインサービス\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9application-service\"\u003eユースケース（Application Service）\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF%E3%82%92%E3%81%A9%E3%81%93%E3%81%AB%E7%BD%AE%E3%81%8F%E3%81%8B\"\u003eドメインロジックをどこに置くか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%8A%B6%E6%85%8B%E3%82%92%E6%8C%81%E3%81%A4%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AF%E3%81%A9%E3%81%86%E3%81%AA%E3%82%8B%E3%81%8B\"\u003e状態を持つドメインサービスはどうなるか\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B1%E3%83%BC%E3%82%B91%E6%96%B0%E3%81%97%E3%81%84%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E6%A6%82%E5%BF%B5%E3%81%8C%E7%94%9F%E3%81%BE%E3%82%8C%E3%81%9F\"\u003eケース1：新しいドメイン概念が生まれた\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B1%E3%83%BC%E3%82%B92%E4%B8%80%E6%99%82%E7%9A%84%E3%81%AA%E5%87%A6%E7%90%86%E7%8A%B6%E6%85%8B\"\u003eケース2：一時的な処理状態\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E8%B3%AA%E5%95%8F\"\u003e判断のための質問\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%88%E3%81%8F%E3%81%82%E3%82%8B%E5%A4%B1%E6%95%97\"\u003eよくある失敗\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"dddにおける集約ドメインサービスユースケースの違い\"\u003eDDDにおける「集約」「ドメインサービス」「ユースケース」の違い\u003c/h2\u003e\n\u003cp\u003eDDD（ドメイン駆動設計）を学び始めると、多くの人が次の疑問にぶつかります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e集約とドメインサービスは何が違うのか\u003c/li\u003e\n\u003cli\u003eユースケースはどこまで責任を持つのか\u003c/li\u003e\n\u003cli\u003eドメインロジックはどこに書くべきなのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの記事では、この3つの概念を整理しながら、\u003cstrong\u003eドメインロジックをどこに置くべきかの判断基準\u003c/strong\u003eを解説します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"まず結論\"\u003eまず結論\u003c/h2\u003e\n\u003cp\u003e3つの役割は次のように整理できます。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e集約（Aggregate）\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eドメインの状態を持つ\u003c/li\u003e\n\u003cli\u003e不変条件を守る\u003c/li\u003e\n\u003cli\u003eドメインモデルの中心\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eドメインサービス（Domain Service）\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eエンティティに属さないドメインロジック\u003c/li\u003e\n\u003cli\u003e複数の集約にまたがる処理\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eユースケース（Use Case / Application Service）\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eユーザー操作を実現する手順\u003c/li\u003e\n\u003cli\u003eドメインモデルを組み合わせる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e依存関係は次のようになります。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eUI\n ↓\nUseCase\n ↓\nDomainService\n ↓\nAggregate\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e重要なルールは \u003cstrong\u003e内側の層は外側を知らないこと\u003c/strong\u003e です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"集約aggregate\"\u003e集約（Aggregate）\u003c/h2\u003e\n\u003cp\u003e集約は \u003cstrong\u003e状態と不変条件を守るドメインモデル\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003e例として「口座振替」を考えます。\u003c/p\u003e\n\u003cp\u003e振替関係には次のルールがあります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e振替日は 1〜31\u003c/li\u003e\n\u003cli\u003e「振替元 + 振替先」が同じ振替関係は 1 つだけ (重複不可)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこのルールを守る主体が \u003ccode\u003eTransferRelation\u003c/code\u003e です。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eTransferRelation\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e accountId: AccountId,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e serviceId: ServiceId,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eprivate\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e paymentDay: PaymentDay\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efun\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003echangePaymentDay\u003c/span\u003e(newDay: PaymentDay) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        paymentDay = newDay\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efun\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estop\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// 状態変更\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e【集約の特徴】\u003c/p\u003e","title":"DDDにおける「集約」「ドメインサービス」「ユースケース」の違い"},{"content":" DDDでドメインを設計するときの流れ ドメイン設計の全体の流れ この記事の前提 1. ユースケースを書き出す 2. ドメイン用語を整理する（ユビキタス言語） 3. エンティティ候補を出す 4. 不変条件を書く 5. 状態遷移を整理する 6. 集約（Aggregate）を決める 7. エンティティの責務を設計する setterが問題になる理由 ドメインメソッドは「操作」を表す 重要な考え方 8. ドメインサービスを定義する 9. リポジトリを定義する 10. 最後にUIを作る まとめ この流れで設計する際のテンプレート DDDでドメインを設計するときの流れ ― 実践的な設計手順 ―\nドメイン駆動設計（DDD）を学び始めると、多くの人が次の疑問を持ちます。\nドメイン設計は何から始めればいいのか 実際の開発ではどのような手順で設計するのか DDDの本では概念の説明が多く、「実際の設計手順」がはっきりしないことがあります。\nこの記事では、実務で使える ドメイン設計の具体的な手順 を整理して紹介します。\nドメイン設計の全体の流れ DDDでドメインを設計する場合、次の順序で進めると整理しやすくなります。\nユースケースを書き出す ドメイン用語を整理する（ユビキタス言語） エンティティ候補を出す 不変条件を書く 状態遷移を整理する 集約（Aggregate）を決める エンティティの責務を設計する 必要ならドメインサービスを作る リポジトリを定義する 最後にUIを設計する 重要なのは UIから設計を始めないこと です。\nDDDでは、基本的には、\nユースケース → ドメイン → UI\nという順序で設計します。\n実際には、一度でバシッと決められるわけではないため、ドメインを設計しているときに、ユースケースに戻るなど、各プロセス間を何度も行ったり来たりします。\nこの記事の前提 この記事では、口座振替管理アプリの開発を想定して、設計の流れを説明してきます。\n振替元と振替先をユーザーが紐づけるメモアプリを想像してください。\n1. ユースケースを書き出す 最初に、システムでユーザーが行う操作を書き出します。\nポイントは UIではなく行動を書くこと です。\n【例】\n口座を登録する 振替関係を作る 振替関係を停止する 振替予定を確認する ここでは 動詞を使って定義する ことが重要です。\nこの一覧が、アプリケーションのユースケースになります。\n2. ドメイン用語を整理する（ユビキタス言語） 次に、ドメインで使う重要な言葉を整理します。\n【例】\n口座 サービス 振替関係 振替予定 支払日 ここでやることは次の2つです。\n同じ意味の言葉を統一する UIの言葉をそのまま使わない 例えば次のような状態は避けます。\n【NG 例】\n支払い元 銀行 口座 これらは意味が同じである場合、例えば 口座 に統一します。\nDDDでは、このようにチーム全体で共通の言葉を使うことを ユビキタス言語 と呼びます。\n3. エンティティ候補を出す 次に、システムの中心になる概念を探します。\n【例】\nAccount Service TransferRelation TransferSchedule この段階では、まだ厳密に決める必要はありません。 重要なのは ドメインの主要な概念を見つけること です。\n4. 不変条件を書く DDDで最も重要なのが 不変条件（Invariant） です。\n不変条件とは\nどんな操作をしても絶対に破ってはいけないルール\nです。\n【例】\n振替関係は必ず1つの口座を持つ 振替関係は必ず1つのサービスを持つ 振替日は1〜31の範囲 「口座とサービス」が同じ組み合わせの振替関係は、重複できない このように 箇条書きで書く のがポイントです。\n実際の設計では、この不変条件がシステム仕様の大部分を決めます。\n5. 状態遷移を整理する 状態を持つエンティティについては 状態遷移 を整理します。\n【例：振替関係】\n作成 ↓ 有効 ↓ 停止 ↓ 削除 さらに重要なのは\nどの操作で状態が変わるのか\nです。\n【例】\ncreate → 有効 stop → 停止 resume → 有効 delete → 削除 この整理をしておくことで、 不正な状態遷移を防ぐことができます。\n6. 集約（Aggregate）を決める DDDでは、不変条件を守る単位を 集約（Aggregate） と呼びます。\n特に、複数のエンティティをまたぐ不変条件は、それらを束ねる集約で定義します。\n【例】\nTransferRelation ├ AccountId ├ ServiceId └ paymentDay このエンティティは次のルールを守ります。\n「口座 + サービス」が同じ組み合わせの振替関係は 1 つだけ (重複不可)\nこのルールを守る境界が 集約 です。\n7. エンティティの責務を設計する 次に、エンティティのドメインメソッドを設計します。\n【例】\nclass TransferRelation { stop() resume() changePaymentDay() } ここで重要なのは setterを作らないこと です。\n【NG】\nsetPaymentDay() 【OK】\nchangePaymentDay() では、なぜ setter は避けるべきなのでしょうか。\nsetterが問題になる理由 setPaymentDay() のような setter は、単に値を代入するだけのメソッドです。\ntransferRelation.setPaymentDay(50) このコードは 技術的には成立してしまいます。\nしかし、ドメインのルールには次のものがあります。\n振替日は1〜31の範囲 つまり、setPaymentDay() を許すと\n不正な値が設定できてしまう 不変条件が破られる という問題が起こります。\nドメインメソッドは「操作」を表す DDDでは、エンティティのメソッドは 単なる値変更ではなく、ドメインの操作を表す べきです。\nchangePaymentDay(newDay) という名前にすると\n支払日を変更するという操作 その操作にはルールがある という意味を持たせることができます。\n例えば次のように実装できます。\nfun changePaymentDay(newDay: Int) { require(newDay in 1..31) paymentDay = newDay } このように 不変条件のチェックをエンティティの中に閉じ込める ことができます。\n重要な考え方 DDDでは、エンティティは単なるデータ構造ではありません。\nエンティティはビジネスルールを守る存在です。\nそのため\nsetXxx() のような単純な setter 外部から自由に状態を変更できる設計 は避けます。\n代わりに\nchangePaymentDay() stop() resume() のように ドメインの操作を表すメソッド を設計します。\nこれによって\n不変条件が守られる ドメインモデルが壊れにくくなる コードから業務の意味が読み取れる というメリットが生まれます。\n8. ドメインサービスを定義する エンティティに入らない処理は ドメインサービス にします。\n無理に作成する必要はなく、必要な場合のみ作成します。\n【例】\nTransferExecutionService\n【責務】\n今日振替すべきものを取得する 振替を実行する エンティティが持つべきでない処理をここに配置します。\n9. リポジトリを定義する 永続化のためのインターフェースです。\n【例】\nTransferRelationRepository AccountRepository ServiceRepository リポジトリは ドメイン層にインターフェースだけ定義 します。\n10. 最後にUIを作る ここまで終わって、初めてUIを設計します。\n多くのアプリは次の順序で設計されます。\nUI ↓ ViewModel ↓ Repository ↓ DB しかし、DDDでは次の順序になります。\nユースケース ↓ ドメイン ↓ UI この順序にすると\nUI変更の影響を受けない ビジネスルールが守られる 設計が崩れにくい というメリットがあります。\nまとめ DDDでドメイン設計をする際は、次の手順で進めると整理しやすくなります。\nユースケースを書く ドメイン用語を整理する エンティティ候補を出す 不変条件を書く 状態遷移を整理する 集約を決める エンティティの責務を設計する ドメインサービスを定義する リポジトリを定義する 最後にUIを設計する DDDの設計で最も重要な問いは次のものです。\n「このルールはどこで守るのか？」\nこの問いを繰り返すことで、ドメインモデルは徐々に洗練されていきます。\nこの流れで設計する際のテンプレート この流れで設計する際のテンプレートを ドメイン設計テンプレート に用意しました。\n","permalink":"https://design.okuda-studio.com/posts/0014-domain-design-flow/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#ddd%E3%81%A7%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92%E8%A8%AD%E8%A8%88%E3%81%99%E3%82%8B%E3%81%A8%E3%81%8D%E3%81%AE%E6%B5%81%E3%82%8C\"\u003eDDDでドメインを設計するときの流れ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E8%A8%AD%E8%A8%88%E3%81%AE%E5%85%A8%E4%BD%93%E3%81%AE%E6%B5%81%E3%82%8C\"\u003eドメイン設計の全体の流れ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E8%A8%98%E4%BA%8B%E3%81%AE%E5%89%8D%E6%8F%90\"\u003eこの記事の前提\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#1-%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9%E3%82%92%E6%9B%B8%E3%81%8D%E5%87%BA%E3%81%99\"\u003e1. ユースケースを書き出す\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#2-%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E7%94%A8%E8%AA%9E%E3%82%92%E6%95%B4%E7%90%86%E3%81%99%E3%82%8B%E3%83%A6%E3%83%93%E3%82%AD%E3%82%BF%E3%82%B9%E8%A8%80%E8%AA%9E\"\u003e2. ドメイン用語を整理する（ユビキタス言語）\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#3-%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%83%86%E3%82%A3%E5%80%99%E8%A3%9C%E3%82%92%E5%87%BA%E3%81%99\"\u003e3. エンティティ候補を出す\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#4-%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6%E3%82%92%E6%9B%B8%E3%81%8F\"\u003e4. 不変条件を書く\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#5-%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%E3%82%92%E6%95%B4%E7%90%86%E3%81%99%E3%82%8B\"\u003e5. 状態遷移を整理する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#6-%E9%9B%86%E7%B4%84aggregate%E3%82%92%E6%B1%BA%E3%82%81%E3%82%8B\"\u003e6. 集約（Aggregate）を決める\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#7-%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%83%86%E3%82%A3%E3%81%AE%E8%B2%AC%E5%8B%99%E3%82%92%E8%A8%AD%E8%A8%88%E3%81%99%E3%82%8B\"\u003e7. エンティティの責務を設計する\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#setter%E3%81%8C%E5%95%8F%E9%A1%8C%E3%81%AB%E3%81%AA%E3%82%8B%E7%90%86%E7%94%B1\"\u003esetterが問題になる理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AF%E6%93%8D%E4%BD%9C%E3%82%92%E8%A1%A8%E3%81%99\"\u003eドメインメソッドは「操作」を表す\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E9%87%8D%E8%A6%81%E3%81%AA%E8%80%83%E3%81%88%E6%96%B9\"\u003e重要な考え方\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#8-%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E5%AE%9A%E7%BE%A9%E3%81%99%E3%82%8B\"\u003e8. ドメインサービスを定義する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#9-%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%82%92%E5%AE%9A%E7%BE%A9%E3%81%99%E3%82%8B\"\u003e9. リポジトリを定義する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#10-%E6%9C%80%E5%BE%8C%E3%81%ABui%E3%82%92%E4%BD%9C%E3%82%8B\"\u003e10. 最後にUIを作る\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E6%B5%81%E3%82%8C%E3%81%A7%E8%A8%AD%E8%A8%88%E3%81%99%E3%82%8B%E9%9A%9B%E3%81%AE%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88\"\u003eこの流れで設計する際のテンプレート\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"dddでドメインを設計するときの流れ\"\u003eDDDでドメインを設計するときの流れ\u003c/h2\u003e\n\u003cp\u003e― 実践的な設計手順 ―\u003c/p\u003e\n\u003cp\u003eドメイン駆動設計（DDD）を学び始めると、多くの人が次の疑問を持ちます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eドメイン設計は何から始めればいいのか\u003c/li\u003e\n\u003cli\u003e実際の開発ではどのような手順で設計するのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eDDDの本では概念の説明が多く、「実際の設計手順」がはっきりしないことがあります。\u003c/p\u003e\n\u003cp\u003eこの記事では、実務で使える \u003cstrong\u003eドメイン設計の具体的な手順\u003c/strong\u003e を整理して紹介します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"ドメイン設計の全体の流れ\"\u003eドメイン設計の全体の流れ\u003c/h2\u003e\n\u003cp\u003eDDDでドメインを設計する場合、次の順序で進めると整理しやすくなります。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eユースケースを書き出す\u003c/li\u003e\n\u003cli\u003eドメイン用語を整理する（ユビキタス言語）\u003c/li\u003e\n\u003cli\u003eエンティティ候補を出す\u003c/li\u003e\n\u003cli\u003e不変条件を書く\u003c/li\u003e\n\u003cli\u003e状態遷移を整理する\u003c/li\u003e\n\u003cli\u003e集約（Aggregate）を決める\u003c/li\u003e\n\u003cli\u003eエンティティの責務を設計する\u003c/li\u003e\n\u003cli\u003e必要ならドメインサービスを作る\u003c/li\u003e\n\u003cli\u003eリポジトリを定義する\u003c/li\u003e\n\u003cli\u003e最後にUIを設計する\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e重要なのは \u003cstrong\u003eUIから設計を始めないこと\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003eDDDでは、基本的には、\u003c/p\u003e\n\u003cp\u003eユースケース → ドメイン → UI\u003c/p\u003e\n\u003cp\u003eという順序で設計します。\u003c/p\u003e\n\u003cp\u003e実際には、一度でバシッと決められるわけではないため、ドメインを設計しているときに、ユースケースに戻るなど、各プロセス間を何度も行ったり来たりします。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"この記事の前提\"\u003eこの記事の前提\u003c/h2\u003e\n\u003cp\u003eこの記事では、口座振替管理アプリの開発を想定して、設計の流れを説明してきます。\u003c/p\u003e\n\u003cp\u003e振替元と振替先をユーザーが紐づけるメモアプリを想像してください。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"1-ユースケースを書き出す\"\u003e1. ユースケースを書き出す\u003c/h2\u003e\n\u003cp\u003e最初に、システムでユーザーが行う操作を書き出します。\u003c/p\u003e\n\u003cp\u003eポイントは \u003cstrong\u003eUIではなく行動を書くこと\u003c/strong\u003e です。\u003c/p\u003e","title":"DDDでドメインを設計するときの流れ"},{"content":" リファクタリングには二種類ある ― 構造を変えるものと、概念を変えるもの まず整理：構造と概念の違い 構造の変更 概念の変更 なぜこの区別が重要なのか？ なぜ通常は「構造 → 概念」なのか？ ① 変更の安全性 ② デバッグのしやすさ ③ 複雑性の増幅 実務での使い分け（私の優先順位） 第1段階：可視化 第2段階：構造整理 第3段階：責務の明確化 第4段階：概念強化 まとめ リファクタリングには二種類ある ― 構造を変えるものと、概念を変えるもの 私は最近の失敗から、大きな学びを得ました。\nそれは、\nリファクタリングには二種類ある\nということです。\n構造 を変えるリファクタリング 概念 を変えるリファクタリング この区別を意識していなかったことが、バグの原因でした。\nこの記事では、自分なりに整理した実務的な優先順位と共にまとめます。\nまず整理：構造と概念の違い 構造の変更 関数抽出 共通化 重複削除 名前変更 ネスト解消 責務分離 振る舞いは変えない（意味は同じ）\nこれは「コードの形」を整える作業です。\n概念の変更 Boolean → sealed class nullable → 非null設計 エラー型明確化 状態遷移の型化 エンティティ再設計 ドメインモデル再定義 責務の再解釈 プログラムが表現する「意味」が変わる\nこれは「コードが何を表現しているか」を変える作業です。\nなぜこの区別が重要なのか？ 私は「成功」という概念を Boolean で扱っていました。\nしかし実際には：\n作成成功 更新成功 失敗 という複数の意味がありました。\nBoolean に押し込めたことで、 意味の差が見えなくなり、無意識に共通化してしまった のです。\nこれは単なる実装ミスではなく、\n概念を粗く扱ったことによる設計ミス\nでした。\nなぜ通常は「構造 → 概念」なのか？ 実務では、変更の順序がとても重要です。\n基本原則は：\n構造を整えてから、概念を強化する\n理由はシンプルです。\n① 変更の安全性 構造変更は：\n振る舞いを変えないことが前提 テストが通れば安全 概念変更は：\n振る舞いの意味そのものを変える 影響範囲が広い リスクが高い ② デバッグのしやすさ 構造変更だけなら：\nバグが出たら直前の変更が原因\nと特定できます。\nしかし構造と概念を同時に変えると：\nどこで壊れたのかわからない\n事故率が一気に上がります。\n③ 複雑性の増幅 概念変更は波及範囲が広い：\nViewModel UseCase Repository UI テスト 一気に影響します。\nだから基本原則はこれです。\n小さい意味変更を段階的に積み上げる\n実務での使い分け（私の優先順位） 私が実務で使う順序はこうです。\n第1段階：可視化 ログ追加 テスト追加 現在の挙動を完全に把握 ここを飛ばすと事故ります。\nまず「今どう動いているか」を固定する。\n第2段階：構造整理 重複除去 関数抽出 ネスト削減 名前改善 意味は変えない\nここでは整理だけをする。\n第3段階：責務の明確化 UI責務とドメイン責務の分離 副作用の分離 純粋関数化 ここまで来ると、設計の輪郭が見えてきます。\n第4段階：概念強化 Boolean → sealed nullable排除 エラー型明確化 状態遷移の型化 ここで初めて「概念」を変える。\nまとめ リファクタリングは一種類ではありません。\n実務では次の二つに分類して考えると安全です。\n種類 何を変えるか リスク 保存的リファクタリング 構造 低い 進化的リファクタリング 概念 高い そして基本順序は：\n保存的リファクタリングで構造を整える 意味を完全理解する 進化的リファクタリングで概念を強化する この順番が事故を減らします。\n","permalink":"https://design.okuda-studio.com/posts/0013-refactoring-type/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca 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%E3%81%AB%E3%81%AF%E4%BA%8C%E7%A8%AE%E9%A1%9E%E3%81%82%E3%82%8B--%E6%A7%8B%E9%80%A0%E3%82%92%E5%A4%89%E3%81%88%E3%82%8B%E3%82%82%E3%81%AE%E3%81%A8%E6%A6%82%E5%BF%B5%E3%82%92%E5%A4%89%E3%81%88%E3%82%8B%E3%82%82%E3%81%AE\"\u003eリファクタリングには二種類ある ― 構造を変えるものと、概念を変えるもの\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%9A%E6%95%B4%E7%90%86%E6%A7%8B%E9%80%A0%E3%81%A8%E6%A6%82%E5%BF%B5%E3%81%AE%E9%81%95%E3%81%84\"\u003eまず整理：構造と概念の違い\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E6%A7%8B%E9%80%A0%E3%81%AE%E5%A4%89%E6%9B%B4\"\u003e構造の変更\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%A6%82%E5%BF%B5%E3%81%AE%E5%A4%89%E6%9B%B4\"\u003e概念の変更\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E3%81%93%E3%81%AE%E5%8C%BA%E5%88%A5%E3%81%8C%E9%87%8D%E8%A6%81%E3%81%AA%E3%81%AE%E3%81%8B\"\u003eなぜこの区別が重要なのか？\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E9%80%9A%E5%B8%B8%E3%81%AF%E6%A7%8B%E9%80%A0--%E6%A6%82%E5%BF%B5%E3%81%AA%E3%81%AE%E3%81%8B\"\u003eなぜ通常は「構造 → 概念」なのか？\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#-%E5%A4%89%E6%9B%B4%E3%81%AE%E5%AE%89%E5%85%A8%E6%80%A7\"\u003e① 変更の安全性\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#-%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E3%81%AE%E3%81%97%E3%82%84%E3%81%99%E3%81%95\"\u003e② デバッグのしやすさ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#-%E8%A4%87%E9%9B%91%E6%80%A7%E3%81%AE%E5%A2%97%E5%B9%85\"\u003e③ 複雑性の増幅\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%AE%9F%E5%8B%99%E3%81%A7%E3%81%AE%E4%BD%BF%E3%81%84%E5%88%86%E3%81%91%E7%A7%81%E3%81%AE%E5%84%AA%E5%85%88%E9%A0%86%E4%BD%8D\"\u003e実務での使い分け（私の優先順位）\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E7%AC%AC1%E6%AE%B5%E9%9A%8E%E5%8F%AF%E8%A6%96%E5%8C%96\"\u003e第1段階：可視化\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%AC%AC2%E6%AE%B5%E9%9A%8E%E6%A7%8B%E9%80%A0%E6%95%B4%E7%90%86\"\u003e第2段階：構造整理\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%AC%AC3%E6%AE%B5%E9%9A%8E%E8%B2%AC%E5%8B%99%E3%81%AE%E6%98%8E%E7%A2%BA%E5%8C%96\"\u003e第3段階：責務の明確化\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%AC%AC4%E6%AE%B5%E9%9A%8E%E6%A6%82%E5%BF%B5%E5%BC%B7%E5%8C%96\"\u003e第4段階：概念強化\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"リファクタリングには二種類ある--構造を変えるものと概念を変えるもの\"\u003eリファクタリングには二種類ある ― 構造を変えるものと、概念を変えるもの\u003c/h1\u003e\n\u003cp\u003e私は最近の失敗から、大きな学びを得ました。\u003c/p\u003e\n\u003cp\u003eそれは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eリファクタリングには二種類ある\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eということです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e構造\u003c/strong\u003e を変えるリファクタリング\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e概念\u003c/strong\u003e を変えるリファクタリング\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの区別を意識していなかったことが、バグの原因でした。\u003c/p\u003e\n\u003cp\u003eこの記事では、自分なりに整理した実務的な優先順位と共にまとめます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"まず整理構造と概念の違い\"\u003eまず整理：構造と概念の違い\u003c/h1\u003e\n\u003ch2 id=\"構造の変更\"\u003e構造の変更\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e関数抽出\u003c/li\u003e\n\u003cli\u003e共通化\u003c/li\u003e\n\u003cli\u003e重複削除\u003c/li\u003e\n\u003cli\u003e名前変更\u003c/li\u003e\n\u003cli\u003eネスト解消\u003c/li\u003e\n\u003cli\u003e責務分離\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e振る舞いは変えない（意味は同じ）\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eこれは「コードの形」を整える作業です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"概念の変更\"\u003e概念の変更\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eBoolean → sealed class\u003c/li\u003e\n\u003cli\u003enullable → 非null設計\u003c/li\u003e\n\u003cli\u003eエラー型明確化\u003c/li\u003e\n\u003cli\u003e状態遷移の型化\u003c/li\u003e\n\u003cli\u003eエンティティ再設計\u003c/li\u003e\n\u003cli\u003eドメインモデル再定義\u003c/li\u003e\n\u003cli\u003e責務の再解釈\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eプログラムが表現する「意味」が変わる\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eこれは「コードが何を表現しているか」を変える作業です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"なぜこの区別が重要なのか\"\u003eなぜこの区別が重要なのか？\u003c/h1\u003e\n\u003cp\u003e私は「成功」という概念を Boolean で扱っていました。\u003c/p\u003e\n\u003cp\u003eしかし実際には：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e作成成功\u003c/li\u003e\n\u003cli\u003e更新成功\u003c/li\u003e\n\u003cli\u003e失敗\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという複数の意味がありました。\u003c/p\u003e\n\u003cp\u003eBoolean に押し込めたことで、\n\u003cstrong\u003e意味の差が見えなくなり、無意識に共通化してしまった\u003c/strong\u003e のです。\u003c/p\u003e","title":"リファクタリングには二種類ある"},{"content":" Boolean に潰された「成功」 ― リファクタリングで気づいた抽象化の罠 はじめに 元のコード リファクタリングでやったこと 最初は「うっかり」だと思った 本当の原因 抽象化の粒度が粗すぎた 型で守る設計 学び 終わりに Boolean に潰された「成功」 ― リファクタリングで気づいた抽象化の罠 はじめに ViewModel の保存処理をリファクタリングしていたとき、 私は一度コードを壊しました。\n原因は単純な「うっかりミス」に見えました。\nしかし振り返ってみると、問題はもっと深いところにありました。\nそれは、\n「成功」という概念を Boolean に潰してしまったこと\nでした。\nこの記事では、その過程と学びを書きます。\n元のコード 保存処理は、新規作成と更新で分岐していました。\nprivate fun saveData() { viewModelScope.launch { val isExistingItem: Boolean = (取得) if (destId == 0) { // 新規作成 val resultSuccess = directDebitDefRepo.createDestination(...) if (resultSuccess) { // フォームの初期化 _formInputState.update { FormInputState() } showSuccess() } else { showFailure() } } else { // 更新 val resultSuccess = directDebitDefRepo.updateDestination(...) if (resultSuccess) { showSuccess() } else { showFailure() } } } } ポイントはここです。\ncreate 成功 → フォーム初期化あり update 成功 → フォーム初期化なし つまり、\ncreate成功 ≠ update成功 でした。\nリファクタリングでやったこと 私は「成功時の処理はほぼ同じ」と考え、共通化しました。\nしかしその結果、\ncreate のときだけ必要だったフォーム初期化を消してしまいました。 そして動作が壊れました。\n最初は「うっかり」だと思った 私はこう思いました。\ncreate と update の違いを吸収しすぎた、単なるミスだ。\nでも本当にそうでしょうか？\n本当の原因 問題はここでした。\ntrue = 成功 false = 失敗 Boolean は 2つの状態 です。\nしかし実際のドメインはこうでした。\nCreatedSuccess UpdatedSuccess Failure 3つの状態があったものを、 Boolean に圧縮していました。\nその瞬間に、\nCreatedSuccess と UpdatedSuccess が同一化した のです。\nそして「成功は同じ」と思い込んでしまった。\n抽象化の粒度が粗すぎた 今回の失敗はロジックの問題ではありませんでした。\n抽象化の粒度の問題でした。\n「成功」という言葉を、技術的成功（DB操作成功）として扱ってしまった。\nしかし UI から見ると、\n新規作成成功 更新成功 は意味が違う。\nこのズレがバグを生みました。\n型で守る設計 もし最初からこうしていたらどうだったでしょうか。\nsealed interface SaveResult { data object Created : SaveResult data object Updated : SaveResult data object Failed : SaveResult } そして：\nwhen (result) { Created -\u0026gt; { _formInputState.update { FormInputState() } showSuccess() } Updated -\u0026gt; { showSuccess() } Failed -\u0026gt; showFailure() } この設計では、\nCreated と Updated を無意識に同一視することはできません。\n型が設計を強制します。\n型が未来の自分を守ります。\n学び 今回の経験から得たことは2つです。\nBoolean は情報を潰す ドメインの意味をそのまま型に表すと事故が減る 終わりに 今回のバグは、小さなものでした。\nしかし、\n抽象化は便利だが、意味を削りすぎると危険\nという重要な気づきを得ました。\nリファクタリングはコードを綺麗にする作業ではありません。\nドメインの意味を正しく表現し直す作業です。\nそしてときどき、 型が私たちを守ってくれます。\n","permalink":"https://design.okuda-studio.com/posts/0012-boolean-destroy-domain/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#boolean-%E3%81%AB%E6%BD%B0%E3%81%95%E3%82%8C%E3%81%9F%E6%88%90%E5%8A%9F--%E3%83%AA%E3%83%95%E3%82%A1%E3%82%AF%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%A7%E6%B0%97%E3%81%A5%E3%81%84%E3%81%9F%E6%8A%BD%E8%B1%A1%E5%8C%96%E3%81%AE%E7%BD%A0\"\u003eBoolean に潰された「成功」 ― リファクタリングで気づいた抽象化の罠\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\"\u003eはじめに\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%85%83%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%89\"\u003e元のコード\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca 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%E3%81%A7%E3%82%84%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8\"\u003eリファクタリングでやったこと\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9C%80%E5%88%9D%E3%81%AF%E3%81%86%E3%81%A3%E3%81%8B%E3%82%8A%E3%81%A0%E3%81%A8%E6%80%9D%E3%81%A3%E3%81%9F\"\u003e最初は「うっかり」だと思った\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%9C%AC%E5%BD%93%E3%81%AE%E5%8E%9F%E5%9B%A0\"\u003e本当の原因\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%8A%BD%E8%B1%A1%E5%8C%96%E3%81%AE%E7%B2%92%E5%BA%A6%E3%81%8C%E7%B2%97%E3%81%99%E3%81%8E%E3%81%9F\"\u003e抽象化の粒度が粗すぎた\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%9E%8B%E3%81%A7%E5%AE%88%E3%82%8B%E8%A8%AD%E8%A8%88\"\u003e型で守る設計\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%AD%A6%E3%81%B3\"\u003e学び\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%B5%82%E3%82%8F%E3%82%8A%E3%81%AB\"\u003e終わりに\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"boolean-に潰された成功--リファクタリングで気づいた抽象化の罠\"\u003eBoolean に潰された「成功」 ― リファクタリングで気づいた抽象化の罠\u003c/h1\u003e\n\u003ch2 id=\"はじめに\"\u003eはじめに\u003c/h2\u003e\n\u003cp\u003eViewModel の保存処理をリファクタリングしていたとき、\n私は一度コードを壊しました。\u003c/p\u003e\n\u003cp\u003e原因は単純な「うっかりミス」に見えました。\u003c/p\u003e\n\u003cp\u003eしかし振り返ってみると、問題はもっと深いところにありました。\u003c/p\u003e\n\u003cp\u003eそれは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e「成功」という概念を Boolean に潰してしまったこと\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eでした。\u003c/p\u003e\n\u003cp\u003eこの記事では、その過程と学びを書きます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"元のコード\"\u003e元のコード\u003c/h2\u003e\n\u003cp\u003e保存処理は、新規作成と更新で分岐していました。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eprivate\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efun\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003esaveData\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    viewModelScope.launch {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e isExistingItem: Boolean = (取得)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (destId \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e// 新規作成\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e resultSuccess = directDebitDefRepo.createDestination(\u003cspan style=\"color:#f92672\"\u003e..\u003c/span\u003e.)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (resultSuccess) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#75715e\"\u003e// フォームの初期化\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                _formInputState.update { FormInputState() }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                showSuccess()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            } \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                showFailure()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e// 更新\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e resultSuccess = directDebitDefRepo.updateDestination(\u003cspan style=\"color:#f92672\"\u003e..\u003c/span\u003e.)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (resultSuccess) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                showSuccess()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            } \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                showFailure()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eポイントはここです。\u003c/p\u003e","title":"Boolean に潰された「状態」"},{"content":" Aggregate Root とは はじめに Aggregate（集約）とは Aggregate Root（集約ルート）とは 具体例（イメージ） 注文ドメインの例 なぜ Aggregate Root が必要なのか ① 整合性を守るため ② トランザクション境界を明確にするため ③ 依存関係をシンプルにするため 設計時の注意点 ① Aggregate を大きくしすぎない ② 他 Aggregate を直接参照しない ③ Repository は Aggregate Root 単位 よくある誤解 まとめ Aggregate Root とは はじめに DDD（Domain-Driven Design）の文脈で頻繁に登場する Aggregate Root（集約ルート） について解説していきます。\n本記事では、\nAggregate / Aggregate Root とは何か なぜこの概念が必要なのか 設計時の注意点 を整理します。\nAggregate（集約）とは Aggregate とは、\n関連する複数の Entity / Value Object を 一つのまとまり（整合性の境界） として扱う DDD の設計単位です。\n重要なのは、\nAggregate は「常に一貫した状態を保つべき単位」\nという点です。\nAggregate Root（集約ルート）とは Aggregate Root とは、\nAggregate の中で 外部から直接参照・操作してよい唯一の Entity を指します。\nAggregate 内には複数の Entity が存在することがありますが、\n外部のコードは Aggregate Root 経由でしか操作できない 内部の Entity は、Root に守られた存在 という関係になります。\n具体例（イメージ） 注文ドメインの例 Order（注文） ← Aggregate Root OrderItem（注文明細） この場合、\nOrderItem を単体で保存・取得しない OrderItem の追加・削除は 必ず Order を通して行う というルールを設けます。\nclass Order( val id: OrderId, private val items: MutableList\u0026lt;OrderItem\u0026gt; ) { fun addItem(item: OrderItem) { // 整合性チェック items.add(item) } } OrderItem は Order の内部状態であり、\n勝手に変更されること 不正な状態になること を Aggregate Root が防ぎます。\nなぜ Aggregate Root が必要なのか ① 整合性を守るため もし内部 Entity を直接操作できると、\n制約チェックが漏れる 状態が壊れる といった事故が起こりやすくなります。\nAggregate Root は、\n状態変更の入口を一箇所に集約 することで、これを防ぎます。\n② トランザクション境界を明確にするため DDD では、\n1 トランザクション = 1 Aggregate が原則です。\n本記事でいう「トランザクション」は、\nDB の BEGIN / COMMIT を指すものではなく、\nビジネス的に一貫性が保たれるべき操作単位 を意味します。\nAggregate Root を単位にすれば、\nどこまでを一括で保存するか どこからを別トランザクションにするか が自然に決まります。\n③ 依存関係をシンプルにするため 外部コードが\nRoot だけを知っていればよい 状態になるため、\n依存が減る 設計が読みやすくなる というメリットがあります。\n設計時の注意点 ① Aggregate を大きくしすぎない 「関連しているから」という理由だけで\n何でも一つの Aggregate に詰め込む のは危険です。\n更新頻度 トランザクションの必要性 を基準に分けるのがポイントです。\n② 他 Aggregate を直接参照しない Aggregate 間の参照は、\nID 参照のみ に留めるのが原則です。\nclass Order( val customerId: CustomerId ) Customer オブジェクトを直接持たないことで、\n境界が崩れる トランザクションが肥大化する のを防ぎます。\n③ Repository は Aggregate Root 単位 Repository は、\nAggregate Root の取得・保存のみを責務とする のが基本です。\ninterface OrderRepository { fun findById(id: OrderId): Order? fun save(order: Order) } 内部 Entity 用の Repository を作らない点が重要です。\nよくある誤解 Entity = Aggregate Root ではない テーブル = Aggregate ではない 画面単位で Aggregate を決める Aggregate は、\nビジネスルールと整合性の単位\nから導かれるものです。\nまとめ Aggregate は「整合性の境界」 Aggregate Root は「外部との唯一の窓口」 状態変更・保存・取得は Root 経由 この概念を意識することで、\nドメインモデルが壊れにくく 変更に強い設計 になります。\n今後、UseCase や Repository を設計するときも、\n「これはどの Aggregate Root を操作しているか？」\nを常に意識していきたいところです。\n","permalink":"https://design.okuda-studio.com/posts/0011-what-is-aggregate-root/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#aggregate-root-%E3%81%A8%E3%81%AF\"\u003eAggregate Root とは\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\"\u003eはじめに\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#aggregate%E9%9B%86%E7%B4%84%E3%81%A8%E3%81%AF\"\u003eAggregate（集約）とは\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#aggregate-root%E9%9B%86%E7%B4%84%E3%83%AB%E3%83%BC%E3%83%88%E3%81%A8%E3%81%AF\"\u003eAggregate Root（集約ルート）とは\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%85%B7%E4%BD%93%E4%BE%8B%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8\"\u003e具体例（イメージ）\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E6%B3%A8%E6%96%87%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AE%E4%BE%8B\"\u003e注文ドメインの例\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C-aggregate-root-%E3%81%8C%E5%BF%85%E8%A6%81%E3%81%AA%E3%81%AE%E3%81%8B\"\u003eなぜ Aggregate Root が必要なのか\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#-%E6%95%B4%E5%90%88%E6%80%A7%E3%82%92%E5%AE%88%E3%82%8B%E3%81%9F%E3%82%81\"\u003e① 整合性を守るため\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#-%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E5%A2%83%E7%95%8C%E3%82%92%E6%98%8E%E7%A2%BA%E3%81%AB%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81\"\u003e② トランザクション境界を明確にするため\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#-%E4%BE%9D%E5%AD%98%E9%96%A2%E4%BF%82%E3%82%92%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%AB%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81\"\u003e③ 依存関係をシンプルにするため\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E6%99%82%E3%81%AE%E6%B3%A8%E6%84%8F%E7%82%B9\"\u003e設計時の注意点\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#-aggregate-%E3%82%92%E5%A4%A7%E3%81%8D%E3%81%8F%E3%81%97%E3%81%99%E3%81%8E%E3%81%AA%E3%81%84\"\u003e① Aggregate を大きくしすぎない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#-%E4%BB%96-aggregate-%E3%82%92%E7%9B%B4%E6%8E%A5%E5%8F%82%E7%85%A7%E3%81%97%E3%81%AA%E3%81%84\"\u003e② 他 Aggregate を直接参照しない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#-repository-%E3%81%AF-aggregate-root-%E5%8D%98%E4%BD%8D\"\u003e③ Repository は Aggregate Root 単位\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%88%E3%81%8F%E3%81%82%E3%82%8B%E8%AA%A4%E8%A7%A3\"\u003eよくある誤解\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"aggregate-root-とは\"\u003eAggregate Root とは\u003c/h1\u003e\n\u003ch2 id=\"はじめに\"\u003eはじめに\u003c/h2\u003e\n\u003cp\u003eDDD（Domain-Driven Design）の文脈で頻繁に登場する \u003cstrong\u003eAggregate Root（集約ルート）\u003c/strong\u003e について解説していきます。\u003c/p\u003e\n\u003cp\u003e本記事では、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAggregate / Aggregate Root とは何か\u003c/li\u003e\n\u003cli\u003eなぜこの概念が必要なのか\u003c/li\u003e\n\u003cli\u003e設計時の注意点\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを整理します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"aggregate集約とは\"\u003eAggregate（集約）とは\u003c/h2\u003e\n\u003cp\u003eAggregate とは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e関連する複数の Entity / Value Object を\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e一つのまとまり（整合性の境界）\u003c/strong\u003e として扱う\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eDDD の設計単位です。\u003c/p\u003e\n\u003cp\u003e重要なのは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eAggregate は「常に一貫した状態を保つべき単位」\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eという点です。\u003c/p\u003e","title":"Aggregate Root とは"},{"content":" SQL の条件を固定しない はじめに 改善前の実装 DAO にドメインの意味が入り込んでいた 問題意識 改善方針 改善後の実装 DAO：検索軸だけを知る Repository / UseCase：意味を与える この設計で得られたメリット 1. SQL / DAO の数が増えにくくなった 2. DAO の責務が明確になった 3. ドメインの変更に強くなった おわりに SQL の条件を固定しない DAO の責務を整理して、ドメインに意味を寄せる設計改善\nはじめに Android アプリ開発において、 「とりあえず動く」状態から一段上の設計に進もうとすると、 ViewModel・UseCase・Repository・DAO の責務の境界で悩むことが多い。\n今回は、\nSQL で条件を固定していた実装を見直し 条件をパラメータ化して SQL の数を減らし その「意味」を Domain / UseCase 側で与える という設計改善を行ったので、その考え方をまとめる。\n改善前の実装 DAO にドメインの意味が入り込んでいた もともと DAO には、次のような Query が定義されていた。\n@Query(\u0026#34;SELECT * FROM transfer_item WHERE isSourceItem = 1\u0026#34;) fun observeSources(): Flow\u0026lt;List\u0026lt;TransferItemEntity\u0026gt;\u0026gt; この実装はシンプルで分かりやすいが、次の問題を抱えていた。\nDAO が「Source（振替元）」というドメインの意味を知っている 条件が増えるたびに SQL / DAO メソッドが増える 将来的に Query が爆発する兆候がある 問題意識 ここで違和感を覚えたのは、次の点だった。\n「振替元である」というのはドメインの意味 DAO は本来、**永続化の都合（カラムやインデックス）**だけを知るべき 「なぜ isSourceItem = 1 なのか」を DAO が理解しているのは不自然 つまり、\nDAO が「意味」を持ち始めているのではないか？\nという疑問である。\n改善方針 改善の方向性はシンプルに次の 2 点とした。\nSQL の条件を固定せず、パラメータ化する 条件の意味づけは Domain / UseCase 側で行う 改善後の実装 DAO：検索軸だけを知る SQL を次のように変更した。\n@Query(\u0026#34;SELECT * FROM transfer_item WHERE isSourceItem = :isSource\u0026#34;) fun observeByIsSource(isSource: Boolean): Flow\u0026lt;List\u0026lt;TransferItemEntity\u0026gt;\u0026gt; この DAO は、\nisSourceItem というカラムがある Boolean で絞り込める という 検索の軸 しか知らない。\n「それが振替元なのか」「どの画面で使うのか」は一切知らない。\nRepository / UseCase：意味を与える class LoadSourceItemsUseCase( private val repository: TransferItemRepository ) { fun execute(): Flow\u0026lt;List\u0026lt;SourceItem\u0026gt;\u0026gt; = repository.observeByIsSource(isSource = true) .map { it.map { entity -\u0026gt; entity.toDomain() } } } ここで初めて、\nisSource = true が 「振替元を取得する」という ドメインの意味 を持つ。\nDAO → Repository → UseCase と層を上がるにつれて、\n実装寄り → 意味寄り に責務が移動している。\nこの設計で得られたメリット 1. SQL / DAO の数が増えにくくなった 条件ごとに Query を生やす必要がなくなった 将来的に isActive などが増えても拡張しやすい 2. DAO の責務が明確になった DAO は 「どうやって取るか」 だけを担当 「なぜ取るか」 は Domain / UseCase の責務 3. ドメインの変更に強くなった 「振替元」の定義が変わっても 修正箇所は UseCase / Repository に閉じる SQL や DAO への影響を最小限にできる おわりに SQL の条件を固定するか、パラメータ化するかは 一見すると小さな実装差に見える。\nしかし、\nどの層が意味を知るべきか どこで判断を下すべきか を意識すると、設計の責務分離が一段クリアになる。\nDAO を「賢く」しすぎず、 Domain / UseCase に意味を寄せる。\nこのバランスは、長く運用するアプリほど効いてくると感じている。\n","permalink":"https://design.okuda-studio.com/posts/0010-do-not-fix-sql-conditions/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#sql-%E3%81%AE%E6%9D%A1%E4%BB%B6%E3%82%92%E5%9B%BA%E5%AE%9A%E3%81%97%E3%81%AA%E3%81%84\"\u003eSQL の条件を固定しない\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\"\u003eはじめに\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%94%B9%E5%96%84%E5%89%8D%E3%81%AE%E5%AE%9F%E8%A3%85\"\u003e改善前の実装\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#dao-%E3%81%AB%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AE%E6%84%8F%E5%91%B3%E3%81%8C%E5%85%A5%E3%82%8A%E8%BE%BC%E3%82%93%E3%81%A7%E3%81%84%E3%81%9F\"\u003eDAO にドメインの意味が入り込んでいた\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%95%8F%E9%A1%8C%E6%84%8F%E8%AD%98\"\u003e問題意識\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%94%B9%E5%96%84%E6%96%B9%E9%87%9D\"\u003e改善方針\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%94%B9%E5%96%84%E5%BE%8C%E3%81%AE%E5%AE%9F%E8%A3%85\"\u003e改善後の実装\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#dao%E6%A4%9C%E7%B4%A2%E8%BB%B8%E3%81%A0%E3%81%91%E3%82%92%E7%9F%A5%E3%82%8B\"\u003eDAO：検索軸だけを知る\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#repository--usecase%E6%84%8F%E5%91%B3%E3%82%92%E4%B8%8E%E3%81%88%E3%82%8B\"\u003eRepository / UseCase：意味を与える\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E8%A8%AD%E8%A8%88%E3%81%A7%E5%BE%97%E3%82%89%E3%82%8C%E3%81%9F%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88\"\u003eこの設計で得られたメリット\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#1-sql--dao-%E3%81%AE%E6%95%B0%E3%81%8C%E5%A2%97%E3%81%88%E3%81%AB%E3%81%8F%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F\"\u003e1. SQL / DAO の数が増えにくくなった\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#2-dao-%E3%81%AE%E8%B2%AC%E5%8B%99%E3%81%8C%E6%98%8E%E7%A2%BA%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F\"\u003e2. DAO の責務が明確になった\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#3-%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AE%E5%A4%89%E6%9B%B4%E3%81%AB%E5%BC%B7%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F\"\u003e3. ドメインの変更に強くなった\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB\"\u003eおわりに\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"sql-の条件を固定しない\"\u003eSQL の条件を固定しない\u003c/h1\u003e\n\u003cp\u003eDAO の責務を整理して、ドメインに意味を寄せる設計改善\u003c/p\u003e\n\u003ch2 id=\"はじめに\"\u003eはじめに\u003c/h2\u003e\n\u003cp\u003eAndroid アプリ開発において、\n「とりあえず動く」状態から一段上の設計に進もうとすると、\n\u003cstrong\u003eViewModel・UseCase・Repository・DAO の責務の境界\u003c/strong\u003eで悩むことが多い。\u003c/p\u003e\n\u003cp\u003e今回は、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSQL で条件を固定していた実装を見直し\u003c/li\u003e\n\u003cli\u003e条件をパラメータ化して SQL の数を減らし\u003c/li\u003e\n\u003cli\u003eその「意味」を Domain / UseCase 側で与える\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという設計改善を行ったので、その考え方をまとめる。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"改善前の実装\"\u003e改善前の実装\u003c/h2\u003e\n\u003ch3 id=\"dao-にドメインの意味が入り込んでいた\"\u003eDAO にドメインの意味が入り込んでいた\u003c/h3\u003e\n\u003cp\u003eもともと DAO には、次のような Query が定義されていた。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@Query\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;SELECT * FROM transfer_item WHERE isSourceItem = 1\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efun\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eobserveSources\u003c/span\u003e(): Flow\u0026lt;List\u0026lt;TransferItemEntity\u0026gt;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eこの実装はシンプルで分かりやすいが、次の問題を抱えていた。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDAO が「Source（振替元）」という\u003cstrong\u003eドメインの意味\u003c/strong\u003eを知っている\u003c/li\u003e\n\u003cli\u003e条件が増えるたびに SQL / DAO メソッドが増える\u003c/li\u003e\n\u003cli\u003e将来的に Query が爆発する兆候がある\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"問題意識\"\u003e問題意識\u003c/h2\u003e\n\u003cp\u003eここで違和感を覚えたのは、次の点だった。\u003c/p\u003e","title":"SQL の条件を固定しない"},{"content":" 「サービスクラス」とは何か？ 「サービス」という言葉の語源と基本ニュアンス Web / サーバーサイドでの Service クラスの起源 なぜ「サービスクラス」が問題視されるようになったのか DDD における「Service」との分岐 UseCase は何に対するアンチテーゼなのか Web エンジニアが「サービスクラス」と言うときの意味 1. 中立的な意味 2. 否定的な意味（設計議論） まとめ 「サービスクラス」とは何か？ ──語源・ニュアンス・UseCaseとの違いを整理する\n設計の議論をしていると、「それ、サービスクラスじゃない？」という言葉が出てくることがある。 一方で、Web エンジニアの中には「Service クラス」は普通に使う用語だ、という人も多い。\nこの「サービスクラス」という言葉は、厳密な定義がなく、文脈によって意味が変わるため、混乱を生みやすい。 この記事では、語源と歴史をたどりながら、\nなぜ「サービス」と呼ばれるのか Web ではどのように使われてきたのか なぜ設計議論では否定的に使われることがあるのか UseCase と何が違うのか を整理する。\n「サービス」という言葉の語源と基本ニュアンス 英語の service は、\n奉仕 提供 役務 といった意味を持つ。\nソフトウェア設計においては、そこから転じて、\n「他のオブジェクトのために処理を提供するもの」\nという、かなり広い意味で使われるようになった。\nこの時点では、「サービス」はあくまで 役割を説明するための便利な言葉であり、設計上の厳密な概念ではない。\nWeb / サーバーサイドでの Service クラスの起源 「サービスクラス」という言葉が広く使われるようになったのは、 Java EE や Spring に代表される レイヤードアーキテクチャの文脈である。\n典型的な構成は以下のようなものだ。\nController ↓ Service ↓ Repository (DAO) ここでの Service クラスは、\nController から呼ばれる 複数の Repository を組み合わせる トランザクション境界になる 業務ロジックを書く場所 という役割を担っていた。\nこの文脈では、Service クラスは 中立的、あるいは肯定的な存在である。\nなぜ「サービスクラス」が問題視されるようになったのか 問題は、「Service」という言葉の 意味が広すぎることにある。\nService という名前は、\n何でも入れられる 責務が曖昧でも違和感が出にくい 「とりあえずここに置く」が起きやすい という性質を持つ。\nその結果、次のようなクラスが生まれやすい。\nUserService { login() logout() changePassword() resetPassword() sendMail() updateProfile() } これは、\n複数の理由で変更される テストが肥大化する クラス名が振る舞いを説明していない という問題を抱える。\nこうして、\n「目的が曖昧で、何でも入っているクラス」\nを皮肉る意味で、 **「サービスクラス（アンチパターン）」**という言い方が使われるようになった。\nDDD における「Service」との分岐 さらに混乱を招く要因として、DDD（ドメイン駆動設計）がある。\nDDD には Domain Service という正当な概念が存在する。\nEntity や ValueObject に属さない しかしドメインとして意味のある操作 例えば：\nMoneyTransferService これはアンチパターンではない。\n一方で、設計議論で問題にされる「サービスクラス」は、\nDomain Service でもない UseCase でもない ただの「便利な中間層」 という点で、まったく別物である。\nUseCase は何に対するアンチテーゼなのか UseCase は、\nService という 広すぎる箱を否定し 「ユーザーの目的・操作」単位で責務を切り出す という考え方である。\nOrderService ❌ PlaceOrderUseCase ✅ CancelOrderUseCase ✅ ここで重要なのは、\nクラス名が「やること」を明確に表している public API が原則 1 つ 変更理由が 1 つに収まりやすい という点だ。\nUseCase は、「Service を使うかどうか」の問題ではなく、 責務をどう切るかに対する答えである。\nWeb エンジニアが「サービスクラス」と言うときの意味 Web エンジニアが「サービスクラス」という言葉を使う場合、文脈は大きく二つに分かれる。\n1. 中立的な意味 Controller にロジックを書くな Repository でもない処理を書く場所 という意味での「Service」。\nこの場合、単なるレイヤ名であり、否定的な意味はない。\n2. 否定的な意味（設計議論） 責務が曖昧 何でも屋になっている UseCase として分解できていない という状態を指して、\n「それ、サービスクラス化していないか？」\nという警告として使われる。\nまとめ 「サービスクラス」には厳密な定義はない 語源的には「処理を提供するもの」という広い意味 Web の文脈では、Controller と Repository の間の中間層として使われてきた その曖昧さゆえに、設計が崩れた結果の「なんでも屋」を指す言葉にもなった UseCase は、その曖昧さへのアンチテーゼとして生まれた考え方 重要なのは名前ではなく、 そのクラスが「何のために存在するのか」が一言で説明できるかどうかである。\n","permalink":"https://design.okuda-studio.com/posts/0009-what-is-service-class/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B\"\u003e「サービスクラス」とは何か？\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%A8%E3%81%84%E3%81%86%E8%A8%80%E8%91%89%E3%81%AE%E8%AA%9E%E6%BA%90%E3%81%A8%E5%9F%BA%E6%9C%AC%E3%83%8B%E3%83%A5%E3%82%A2%E3%83%B3%E3%82%B9\"\u003e「サービス」という言葉の語源と基本ニュアンス\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#web--%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%82%B5%E3%82%A4%E3%83%89%E3%81%A7%E3%81%AE-service-%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E8%B5%B7%E6%BA%90\"\u003eWeb / サーバーサイドでの Service クラスの起源\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%8C%E5%95%8F%E9%A1%8C%E8%A6%96%E3%81%95%E3%82%8C%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%8B\"\u003eなぜ「サービスクラス」が問題視されるようになったのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ddd-%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8Bservice%E3%81%A8%E3%81%AE%E5%88%86%E5%B2%90\"\u003eDDD における「Service」との分岐\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#usecase-%E3%81%AF%E4%BD%95%E3%81%AB%E5%AF%BE%E3%81%99%E3%82%8B%E3%82%A2%E3%83%B3%E3%83%81%E3%83%86%E3%83%BC%E3%82%BC%E3%81%AA%E3%81%AE%E3%81%8B\"\u003eUseCase は何に対するアンチテーゼなのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#web-%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%8C%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%A8%E8%A8%80%E3%81%86%E3%81%A8%E3%81%8D%E3%81%AE%E6%84%8F%E5%91%B3\"\u003eWeb エンジニアが「サービスクラス」と言うときの意味\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#1-%E4%B8%AD%E7%AB%8B%E7%9A%84%E3%81%AA%E6%84%8F%E5%91%B3\"\u003e1. 中立的な意味\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#2-%E5%90%A6%E5%AE%9A%E7%9A%84%E3%81%AA%E6%84%8F%E5%91%B3%E8%A8%AD%E8%A8%88%E8%AD%B0%E8%AB%96\"\u003e2. 否定的な意味（設計議論）\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"サービスクラスとは何か\"\u003e「サービスクラス」とは何か？\u003c/h1\u003e\n\u003cp\u003e──語源・ニュアンス・UseCaseとの違いを整理する\u003c/p\u003e\n\u003cp\u003e設計の議論をしていると、「それ、サービスクラスじゃない？」という言葉が出てくることがある。\n一方で、Web エンジニアの中には「Service クラス」は普通に使う用語だ、という人も多い。\u003c/p\u003e\n\u003cp\u003eこの「サービスクラス」という言葉は、\u003cstrong\u003e厳密な定義がなく、文脈によって意味が変わる\u003c/strong\u003eため、混乱を生みやすい。\nこの記事では、語源と歴史をたどりながら、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eなぜ「サービス」と呼ばれるのか\u003c/li\u003e\n\u003cli\u003eWeb ではどのように使われてきたのか\u003c/li\u003e\n\u003cli\u003eなぜ設計議論では否定的に使われることがあるのか\u003c/li\u003e\n\u003cli\u003eUseCase と何が違うのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを整理する。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"サービスという言葉の語源と基本ニュアンス\"\u003e「サービス」という言葉の語源と基本ニュアンス\u003c/h2\u003e\n\u003cp\u003e英語の \u003cem\u003eservice\u003c/em\u003e は、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e奉仕\u003c/li\u003e\n\u003cli\u003e提供\u003c/li\u003e\n\u003cli\u003e役務\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった意味を持つ。\u003c/p\u003e\n\u003cp\u003eソフトウェア設計においては、そこから転じて、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e「他のオブジェクトのために処理を提供するもの」\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eという、かなり広い意味で使われるようになった。\u003c/p\u003e\n\u003cp\u003eこの時点では、「サービス」はあくまで\n\u003cstrong\u003e役割を説明するための便利な言葉\u003c/strong\u003eであり、設計上の厳密な概念ではない。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"web--サーバーサイドでの-service-クラスの起源\"\u003eWeb / サーバーサイドでの Service クラスの起源\u003c/h2\u003e\n\u003cp\u003e「サービスクラス」という言葉が広く使われるようになったのは、\nJava EE や Spring に代表される \u003cstrong\u003eレイヤードアーキテクチャ\u003c/strong\u003eの文脈である。\u003c/p\u003e\n\u003cp\u003e典型的な構成は以下のようなものだ。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eController\n  ↓\nService\n  ↓\nRepository (DAO)\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eここでの Service クラスは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eController から呼ばれる\u003c/li\u003e\n\u003cli\u003e複数の Repository を組み合わせる\u003c/li\u003e\n\u003cli\u003eトランザクション境界になる\u003c/li\u003e\n\u003cli\u003e業務ロジックを書く場所\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという役割を担っていた。\u003c/p\u003e","title":"「サービスクラス」とは何か？"},{"content":" ViewModel が肥大化する理由 よくある誤解：ViewModel は「中継役」だから重くなる ViewModel が肥大化する本当の理由 「UI の判断」と「業務の判断」は別物 UseCase が登場する理由 ViewModel と UseCase の境界線 「ViewModel から処理がほとんど消えそう」問題 まとめ ViewModel が肥大化する理由 Android アプリを作っていると、ある日ふと気づきます。\nViewModel、でかくなりすぎじゃない？\nState の定義、Flow の合成、エラーハンドリング、変換ロジック、画面固有の分岐……。 気づけば 1 ファイルに数百行。しかも「どこを直すと何が壊れるのか分からない」状態。\nこの記事では、なぜ ViewModel は肥大化しやすいのか、そして それを防ぐための本質的な境界の引き方 について整理します。\nよくある誤解：ViewModel は「中継役」だから重くなる よく言われる説明に、こんなものがあります。\nViewModel は UI と Domain の橋渡しだから Flow や State を扱うから 非同期処理が集まりやすいから どれも一理ありますが、本当の理由ではありません。\nFlow があるから肥大化するのではなく、 ViewModel が 本来持つべきでない判断 を持ち始めたときに肥大化します。\nViewModel が肥大化する本当の理由 結論から言うと理由はシンプルです。\n「何をするか」を ViewModel が決め始めるから 本来の ViewModel の役割は、次の 2 つです。\nUI からのイベントを受け取る UI が描画しやすい State に変換して公開する ところが実際には、次のような責務が入り込みがちです。\nこの操作は許可すべきか？ このデータは保存すべきか？ A のときは B、C のときは D Entity をどう解釈すべきか？ これらはすべて UI の問題ではありません。\n「UI の判断」と「業務の判断」は別物 ViewModel が持つべき判断は、あくまで UI に閉じたものです。\nローディングを表示するか エラーメッセージをどう出すか ボタンを活性にするか 一方で、次のような判断は UI の外側にあります。\nこれは作成できるデータか？ 更新してよい状態か？ 保存先はどうあるべきか？ これらは 画面が変わっても意味が変わらない判断 です。\nここを ViewModel に置くと、画面が増えるたびに同じロジックが増殖し、 結果として ViewModel が肥大化します。\nUseCase が登場する理由 UseCase は、よく「処理の切り出し先」として語られますが、 本質はそこではありません。\nUseCase の役割はただ一つです。\nアプリとして「何をするか」を定義すること ここでは、口座振替を管理するアプリの場合 を例に考えてみます。\nたとえば次のようなものです。\n振替元の口座一覧を取得する 口座振替の設定を保存する 入力された金額や日付が有効かを検証する これらはすべて、\nどの画面から呼ばれても UI が変わっても 保存方法（DB / クラウドなど）が変わっても 意味が変わりません。\nだから ViewModel ではなく、UseCase に置かれます。\nViewModel と UseCase の境界線 迷ったときは、次の問いを自分に投げてみてください。\nこの判断は、別の画面でも同じ意味を持つか？ YES なら UseCase。 NO なら ViewModel。\nたとえば、\n入力が正しいか？ → UseCase エラーをトーストで出すか？ → ViewModel この基準で分けると、自然と ViewModel は軽くなります。\n「ViewModel から処理がほとんど消えそう」問題 ここでよく出る不安があります。\nUseCase に移したら、ViewModel に何も残らないのでは？\n実際には、ちゃんと残ります。\nUI イベントの受信 UseCase の呼び出し 結果を State に詰め替える UI 専用の状態管理 むしろ、ViewModel が本来の姿に戻る だけです。\nまとめ ViewModel が肥大化する原因は、\n技術的な問題ではなく レイヤーの責務が曖昧になること にあります。\nViewModel は UI の都合だけを知る UseCase は アプリとして「何をするか」を知る この境界を意識すると、\nViewModel は小さく保たれ ロジックは再利用可能になり 変更に強い構造になります ViewModel が苦しくなってきたら、 それは 設計を見直すサイン かもしれません。\n","permalink":"https://design.okuda-studio.com/posts/0008-cause-of-fat-viewmodels/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#viewmodel-%E3%81%8C%E8%82%A5%E5%A4%A7%E5%8C%96%E3%81%99%E3%82%8B%E7%90%86%E7%94%B1\"\u003eViewModel が肥大化する理由\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%88%E3%81%8F%E3%81%82%E3%82%8B%E8%AA%A4%E8%A7%A3viewmodel-%E3%81%AF%E4%B8%AD%E7%B6%99%E5%BD%B9%E3%81%A0%E3%81%8B%E3%82%89%E9%87%8D%E3%81%8F%E3%81%AA%E3%82%8B\"\u003eよくある誤解：ViewModel は「中継役」だから重くなる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#viewmodel-%E3%81%8C%E8%82%A5%E5%A4%A7%E5%8C%96%E3%81%99%E3%82%8B%E6%9C%AC%E5%BD%93%E3%81%AE%E7%90%86%E7%94%B1\"\u003eViewModel が肥大化する本当の理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ui-%E3%81%AE%E5%88%A4%E6%96%AD%E3%81%A8%E6%A5%AD%E5%8B%99%E3%81%AE%E5%88%A4%E6%96%AD%E3%81%AF%E5%88%A5%E7%89%A9\"\u003e「UI の判断」と「業務の判断」は別物\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#usecase-%E3%81%8C%E7%99%BB%E5%A0%B4%E3%81%99%E3%82%8B%E7%90%86%E7%94%B1\"\u003eUseCase が登場する理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#viewmodel-%E3%81%A8-usecase-%E3%81%AE%E5%A2%83%E7%95%8C%E7%B7%9A\"\u003eViewModel と UseCase の境界線\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#viewmodel-%E3%81%8B%E3%82%89%E5%87%A6%E7%90%86%E3%81%8C%E3%81%BB%E3%81%A8%E3%82%93%E3%81%A9%E6%B6%88%E3%81%88%E3%81%9D%E3%81%86%E5%95%8F%E9%A1%8C\"\u003e「ViewModel から処理がほとんど消えそう」問題\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"viewmodel-が肥大化する理由\"\u003eViewModel が肥大化する理由\u003c/h1\u003e\n\u003cp\u003eAndroid アプリを作っていると、ある日ふと気づきます。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eViewModel、でかくなりすぎじゃない？\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eState の定義、Flow の合成、エラーハンドリング、変換ロジック、画面固有の分岐……。\n気づけば 1 ファイルに数百行。しかも「どこを直すと何が壊れるのか分からない」状態。\u003c/p\u003e\n\u003cp\u003eこの記事では、\u003cstrong\u003eなぜ ViewModel は肥大化しやすいのか\u003c/strong\u003e、そして \u003cstrong\u003eそれを防ぐための本質的な境界の引き方\u003c/strong\u003e について整理します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"よくある誤解viewmodel-は中継役だから重くなる\"\u003eよくある誤解：ViewModel は「中継役」だから重くなる\u003c/h2\u003e\n\u003cp\u003eよく言われる説明に、こんなものがあります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eViewModel は UI と Domain の橋渡しだから\u003c/li\u003e\n\u003cli\u003eFlow や State を扱うから\u003c/li\u003e\n\u003cli\u003e非同期処理が集まりやすいから\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eどれも一理ありますが、\u003cstrong\u003e本当の理由ではありません\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003eFlow があるから肥大化するのではなく、\nViewModel が \u003cem\u003e本来持つべきでない判断\u003c/em\u003e を持ち始めたときに肥大化します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"viewmodel-が肥大化する本当の理由\"\u003eViewModel が肥大化する本当の理由\u003c/h2\u003e\n\u003cp\u003e結論から言うと理由はシンプルです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e「何をするか」を ViewModel が決め始めるから\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e本来の ViewModel の役割は、次の 2 つです。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUI からのイベントを受け取る\u003c/li\u003e\n\u003cli\u003eUI が描画しやすい State に変換して公開する\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eところが実際には、次のような責務が入り込みがちです。\u003c/p\u003e","title":"ViewModel が肥大化する理由"},{"content":" Domain と UseCase の違いを整理してみる 一言で言うと何が違うのか Domain とは何か Domain は「意味」と「ルール」の集合体 Domain の例 Domain がやらないこと UseCase とは何か UseCase は「動詞の層」 UseCase の例 Domain と UseCase の関係 なぜ UseCase が分かりにくいのか UseCase を作るべきタイミング Entity → Domain 変換はどこでやるべきか Domain と UseCase を分ける最大のポイント よくあるアンチパターン おわりに Domain と UseCase の違いを整理してみる Clean Architecture や DDD を学んでいると、ほぼ確実に次の疑問にぶつかります。\nDomain と UseCase の違いがよく分からない どこまでが Domain で、どこからが UseCase なのか曖昧 UseCase を作ろうとすると、何を書けばいいのか分からない 私自身、このあたりで何度も立ち止まりました。 この記事では、実装経験を通して整理できた Domain と UseCase の違い を、自分なりの言葉でまとめてみます。\n一言で言うと何が違うのか まず、かなり大胆に要約します。\nDomain →「この世界では、何が正しく、何が成り立つか」を表す\nUseCase →「その正しさを、どういう手順・文脈で使うか」を表す\nこの一文を起点にすると、境界が見えやすくなります。\nDomain とは何か Domain は「意味」と「ルール」の集合体 Domain が表すのは、次のようなものです。\nアプリが扱う概念（名詞） その概念に関する制約 不変条件 正しい / 正しくないの判断基準 重要なのは、Domain が 技術から切り離されている という点です。\nDomain の例 @JvmInline value class SourceId(val value: String) data class Source( val id: SourceId, val name: String, val isActive: Boolean ) { init { require(name.isNotBlank()) } } ここでやっているのは、\n「Source とは何か」の定義 名前は空ではいけない、というルール であって、\nDB API Flow Android といったものは一切登場しません。\nDomain は 世界観そのもの を表します。\nDomain がやらないこと これはかなり重要です。\nDomain は、次のようなことをやりません。\nデータを取得する 保存する 非同期処理を扱う 時系列を持つ Repository を呼ぶ Domain は常に 現在形 で存在します。\nUseCase とは何か UseCase は「動詞の層」 UseCase は、Domain とは役割がはっきり違います。\nUseCase が表すのは、\nユーザーの行動 アプリとしての操作単位 一連の手順や流れ つまり、何かをする という文脈です。\nUseCase の例 class ObserveSourcesUseCase( private val repo: SourceRepository ) { operator fun invoke(): Flow\u0026lt;List\u0026lt;Source\u0026gt;\u0026gt; = repo.observeSources() .map { list -\u0026gt; list.filter { it.isActive } } } このコードには、\nRepository Flow データの流れ 条件による選別 といった 時間や手順 の概念が含まれています。\nこれが Domain との決定的な違いです。\nDomain と UseCase の関係 関係性を整理すると、次のようになります。\nDomain は単体で完結する UseCase は Domain を使って何かをする Domain は「正しさ」を持つ UseCase は「使われ方」を持つ UseCase は Domain の上位互換ではありません。 役割がまったく違う層 です。\nなぜ UseCase が分かりにくいのか UseCase が分かりにくくなる原因は、だいたい次のどれかです。\nRepository の薄いラッパーになっている CRUD をそのまま移しただけ 「層を作ること」が目的になっている こうなると、\n「これ、本当に必要？」\nという感覚になります。\nその違和感は正しいです。\nUseCase を作るべきタイミング 私の中での判断基準は、次のようなケースです。\n複数の Repository をまたぐ データを加工して意味のある形にする List / Map / Filter / Sort などを組み合わせる UI から切り離したい判断が含まれる これらは 「どう使うか」 の話なので、UseCase の責務になります。\nEntity → Domain 変換はどこでやるべきか よくある疑問に、\nEntity を Domain に変換するのは UseCase？ Repository？\nというものがあります。\n答えは一択ではありません。\nEntity と Domain がほぼ 1:1 → Repository で変換するのが自然 ユースケースごとに意味が変わる → UseCase で変換するのが自然 重要なのは、ViewModel が Entity を知らないこと です。\nDomain と UseCase を分ける最大のポイント 自分なりに一番しっくり来た整理は、これです。\nDomain は「これは正しいか」を決める UseCase は「それをいつ・どう使うか」を決める\nこの2つを混ぜ始めると、境界は一気に崩れます。\nよくあるアンチパターン Domain に Flow が出てくる → 時間の概念が混ざっている UseCase に Entity が出てくる → インフラが漏れている UseCase が ViewModel の代わりになっている → UI 依存が侵食している このあたりは要注意です。\nおわりに Domain と UseCase の違いは、 ルールを暗記しても分かりにくい部分です。\n実装しながら、\nこれは「意味」なのか これは「使い方」なのか と問い続けることで、少しずつ輪郭が見えてきました。\n","permalink":"https://design.okuda-studio.com/posts/0007-domain-vs-usecase/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#domain-%E3%81%A8-usecase-%E3%81%AE%E9%81%95%E3%81%84%E3%82%92%E6%95%B4%E7%90%86%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B\"\u003eDomain と UseCase の違いを整理してみる\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%B8%80%E8%A8%80%E3%81%A7%E8%A8%80%E3%81%86%E3%81%A8%E4%BD%95%E3%81%8C%E9%81%95%E3%81%86%E3%81%AE%E3%81%8B\"\u003e一言で言うと何が違うのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#domain-%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B\"\u003eDomain とは何か\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#domain-%E3%81%AF%E6%84%8F%E5%91%B3%E3%81%A8%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%AE%E9%9B%86%E5%90%88%E4%BD%93\"\u003eDomain は「意味」と「ルール」の集合体\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#domain-%E3%81%AE%E4%BE%8B\"\u003eDomain の例\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#domain-%E3%81%8C%E3%82%84%E3%82%89%E3%81%AA%E3%81%84%E3%81%93%E3%81%A8\"\u003eDomain がやらないこと\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#usecase-%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B\"\u003eUseCase とは何か\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#usecase-%E3%81%AF%E5%8B%95%E8%A9%9E%E3%81%AE%E5%B1%A4\"\u003eUseCase は「動詞の層」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#usecase-%E3%81%AE%E4%BE%8B\"\u003eUseCase の例\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#domain-%E3%81%A8-usecase-%E3%81%AE%E9%96%A2%E4%BF%82\"\u003eDomain と UseCase の関係\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C-usecase-%E3%81%8C%E5%88%86%E3%81%8B%E3%82%8A%E3%81%AB%E3%81%8F%E3%81%84%E3%81%AE%E3%81%8B\"\u003eなぜ UseCase が分かりにくいのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#usecase-%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%B9%E3%81%8D%E3%82%BF%E3%82%A4%E3%83%9F%E3%83%B3%E3%82%B0\"\u003eUseCase を作るべきタイミング\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#entity--domain-%E5%A4%89%E6%8F%9B%E3%81%AF%E3%81%A9%E3%81%93%E3%81%A7%E3%82%84%E3%82%8B%E3%81%B9%E3%81%8D%E3%81%8B\"\u003eEntity → Domain 変換はどこでやるべきか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#domain-%E3%81%A8-usecase-%E3%82%92%E5%88%86%E3%81%91%E3%82%8B%E6%9C%80%E5%A4%A7%E3%81%AE%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88\"\u003eDomain と UseCase を分ける最大のポイント\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%88%E3%81%8F%E3%81%82%E3%82%8B%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3\"\u003eよくあるアンチパターン\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB\"\u003eおわりに\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"domain-と-usecase-の違いを整理してみる\"\u003eDomain と UseCase の違いを整理してみる\u003c/h1\u003e\n\u003cp\u003eClean Architecture や DDD を学んでいると、ほぼ確実に次の疑問にぶつかります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDomain と UseCase の違いがよく分からない\u003c/li\u003e\n\u003cli\u003eどこまでが Domain で、どこからが UseCase なのか曖昧\u003c/li\u003e\n\u003cli\u003eUseCase を作ろうとすると、何を書けばいいのか分からない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e私自身、このあたりで何度も立ち止まりました。\nこの記事では、実装経験を通して整理できた \u003cstrong\u003eDomain と UseCase の違い\u003c/strong\u003e を、自分なりの言葉でまとめてみます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"一言で言うと何が違うのか\"\u003e一言で言うと何が違うのか\u003c/h2\u003e\n\u003cp\u003eまず、かなり大胆に要約します。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eDomain\u003c/strong\u003e\n→「この世界では、何が正しく、何が成り立つか」を表す\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eUseCase\u003c/strong\u003e\n→「その正しさを、どういう手順・文脈で使うか」を表す\u003c/p\u003e","title":"Domain と UseCase の違いを整理してみる"},{"content":" Domain レイヤーかどうかを判断する基準 Domain レイヤーとは何か（簡単に） 判断基準：ユーザーがそれを意識するか？ 例1：保存処理は Domain か？ ケースA：保存先をユーザーが意識しない場合 ケースB：保存先をユーザーが意識的に選択する場合 「ユーザーが意識する」という基準の使いどころ UseCase との関係 注意点：すべてを Domain に入れない 迷ったときの最終チェック おわりに Domain レイヤーかどうかを判断する基準 ―「ユーザーが意識するか？」という視点―\n設計をしていると、次のような悩みにぶつかることがあります。\nこの処理は Domain レイヤーに置くべきか？ UseCase なのか、それとも Data レイヤーの責務なのか？ そもそも Domain って何を置く場所なのか？ とくに Clean Architecture や DDD を学び始めた頃は、 「正解の置き場所」を探そうとして、かえって混乱しがちです。\nこの記事では、私が設計を考える際に ひとつの判断基準 として使っている考え方を紹介します。\nDomain レイヤーとは何か（簡単に） Domain レイヤーは、ざっくり言うと\nアプリが扱う 概念 その概念に関する ルール 「それは正しいかどうか」の判断 を表す層です。\n技術的な詳細（DB、API、ライブラリなど）からは距離を置き、 アプリの意味そのもの を表現する場所だと考えています。\n判断基準：ユーザーがそれを意識するか？ 私が Domain レイヤーかどうかを判断する際に使っている基準は、次の問いです。\n「ユーザーは、その機能や概念を意識してアプリを操作するか？」\nこの問いに YES なら、 その概念や処理は Domain レイヤー（または UseCase）に属する可能性が高いです。\nNO なら、 それは Data レイヤーや Infrastructure に閉じ込めるべきものだと考えます。\n例1：保存処理は Domain か？ ケースA：保存先をユーザーが意識しない場合 ユーザーは「保存」ボタンを押すだけ データがどこに保存されるかは気にしない ローカルかクラウドかはアプリ側の都合 この場合、ユーザーが意識しているのは 「保存する」ことだけ です。\nDomain が知るのは「保存する」という意味 「どこに保存するか」は Data レイヤーの責務 Domain に\nSQLite Room Firebase といった言葉が出てくる必要はありません。\nケースB：保存先をユーザーが意識的に選択する場合 ユーザーが 「ローカルに保存」 or 「クラウドに保存」 を明示的に選ぶ場合、「保存先」はユーザーにとって 操作上の意味を持つ概念 です。\nここで重要なのは、\nDomain が知るべきなのは 技術名 ではない Domain が知るべきなのは 選択肢が存在するという事実 という点です。\nDomain では、\n「ローカル」 「クラウド」 といった 概念 を扱い、 それをどう実装するかは Data レイヤーに任せます。\n「ユーザーが意識する」という基準の使いどころ この基準が役立つのは、次のような迷いどころです。\nフィルタ条件は Domain か？ 並び順は Domain か？ キャッシュ戦略は Domain か？ List か Map かはどこで決めるのか？ その都度、\nユーザーはこれを意識して操作しているか？\nと自分に問いかけると、 レイヤーの境界がかなりクリアになります。\nUseCase との関係 UseCase は、\nユーザーの操作 ユーザーの意図 Domain の概念を使った一連の流れ を表す層です。\nそのため、\nユーザーが意識する操作 ユーザーが選択する条件 ユーザーの行動単位 は、UseCase に置かれることが多くなります。\nDomain が「名詞」だとすると、 UseCase は「動詞」に近い存在です。\n注意点：すべてを Domain に入れない 「ユーザーが意識するか」という基準は便利ですが、 すべてを Domain に押し込むためのものではありません。\nパフォーマンス最適化 キャッシュの仕方 再試行ロジック 通信方法 これらは、たとえユーザーに見えていたとしても 意味ではなく実装の問題 であることがほとんどです。\nここは冷静に切り分ける必要があります。\n迷ったときの最終チェック 最後に、私がよく使うチェックを紹介します。\nこの概念は、ユーザー向けの説明書に書くだろうか？\n書く → Domain / UseCase 側 書かない → Data / Infrastructure 側 この問いを挟むだけで、 「なんとなく」でレイヤーを決めることが減りました。\nおわりに Domain レイヤーの判断は、 ルール暗記よりも 視点 の問題だと感じています。\n「ユーザーが意識するか？」\nこの問いを持って設計すると、 ViewModel や Repository の責務も自然と整理されていきます。\n","permalink":"https://design.okuda-studio.com/posts/0006-domain-layer-or-not/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#domain-%E3%83%AC%E3%82%A4%E3%83%A4%E3%83%BC%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E6%96%AD%E3%81%99%E3%82%8B%E5%9F%BA%E6%BA%96\"\u003eDomain レイヤーかどうかを判断する基準\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#domain-%E3%83%AC%E3%82%A4%E3%83%A4%E3%83%BC%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B%E7%B0%A1%E5%8D%98%E3%81%AB\"\u003eDomain レイヤーとは何か（簡単に）\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%88%A4%E6%96%AD%E5%9F%BA%E6%BA%96%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%8C%E3%81%9D%E3%82%8C%E3%82%92%E6%84%8F%E8%AD%98%E3%81%99%E3%82%8B%E3%81%8B\"\u003e判断基準：ユーザーがそれを意識するか？\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8B1%E4%BF%9D%E5%AD%98%E5%87%A6%E7%90%86%E3%81%AF-domain-%E3%81%8B\"\u003e例1：保存処理は Domain か？\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B1%E3%83%BC%E3%82%B9a%E4%BF%9D%E5%AD%98%E5%85%88%E3%82%92%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%8C%E6%84%8F%E8%AD%98%E3%81%97%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88\"\u003eケースA：保存先をユーザーが意識しない場合\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%B1%E3%83%BC%E3%82%B9b%E4%BF%9D%E5%AD%98%E5%85%88%E3%82%92%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%8C%E6%84%8F%E8%AD%98%E7%9A%84%E3%81%AB%E9%81%B8%E6%8A%9E%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88\"\u003eケースB：保存先をユーザーが意識的に選択する場合\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%8C%E6%84%8F%E8%AD%98%E3%81%99%E3%82%8B%E3%81%A8%E3%81%84%E3%81%86%E5%9F%BA%E6%BA%96%E3%81%AE%E4%BD%BF%E3%81%84%E3%81%A9%E3%81%93%E3%82%8D\"\u003e「ユーザーが意識する」という基準の使いどころ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#usecase-%E3%81%A8%E3%81%AE%E9%96%A2%E4%BF%82\"\u003eUseCase との関係\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%B3%A8%E6%84%8F%E7%82%B9%E3%81%99%E3%81%B9%E3%81%A6%E3%82%92-domain-%E3%81%AB%E5%85%A5%E3%82%8C%E3%81%AA%E3%81%84\"\u003e注意点：すべてを Domain に入れない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%BF%B7%E3%81%A3%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AE%E6%9C%80%E7%B5%82%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF\"\u003e迷ったときの最終チェック\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB\"\u003eおわりに\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"domain-レイヤーかどうかを判断する基準\"\u003eDomain レイヤーかどうかを判断する基準\u003c/h1\u003e\n\u003cp\u003e―「ユーザーが意識するか？」という視点―\u003c/p\u003e\n\u003cp\u003e設計をしていると、次のような悩みにぶつかることがあります。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eこの処理は Domain レイヤーに置くべきか？\u003c/li\u003e\n\u003cli\u003eUseCase なのか、それとも Data レイヤーの責務なのか？\u003c/li\u003e\n\u003cli\u003eそもそも Domain って何を置く場所なのか？\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eとくに Clean Architecture や DDD を学び始めた頃は、\n「正解の置き場所」を探そうとして、かえって混乱しがちです。\u003c/p\u003e\n\u003cp\u003eこの記事では、私が設計を考える際に \u003cstrong\u003eひとつの判断基準\u003c/strong\u003e として使っている考え方を紹介します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"domain-レイヤーとは何か簡単に\"\u003eDomain レイヤーとは何か（簡単に）\u003c/h2\u003e\n\u003cp\u003eDomain レイヤーは、ざっくり言うと\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eアプリが扱う \u003cstrong\u003e概念\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003eその概念に関する \u003cstrong\u003eルール\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e「それは正しいかどうか」の判断\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを表す層です。\u003c/p\u003e\n\u003cp\u003e技術的な詳細（DB、API、ライブラリなど）からは距離を置き、\n\u003cstrong\u003eアプリの意味そのもの\u003c/strong\u003e を表現する場所だと考えています。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"判断基準ユーザーがそれを意識するか\"\u003e判断基準：ユーザーがそれを意識するか？\u003c/h2\u003e\n\u003cp\u003e私が Domain レイヤーかどうかを判断する際に使っている基準は、次の問いです。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e「ユーザーは、その機能や概念を意識してアプリを操作するか？」\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eこの問いに \u003cstrong\u003eYES\u003c/strong\u003e なら、\nその概念や処理は Domain レイヤー（または UseCase）に属する可能性が高いです。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eNO\u003c/strong\u003e なら、\nそれは Data レイヤーや Infrastructure に閉じ込めるべきものだと考えます。\u003c/p\u003e","title":"Domain レイヤーかどうかを判断する基準"},{"content":" 設計不良なソフトウェアの現場で起きていること 影響範囲が見えないまま進む実装 ここで言う「影響範囲がわからない」とはどういう状態か 実装完了後に始まる、本当の消耗戦 なぜこの状況は繰り返されるのか エンジニアは「疲れたから」辞めているわけではない 設計の役割は「人間が判断できる状態」を作ること 消耗戦を終わらせるために 設計不良なソフトウェアの現場で起きていること 設計不良なソフトウェアの現場では、共通して起きることがあります。\n変更を入れようとすると、「どこまで影響するのか分からない」という声が上がる。\nそれでも、プロジェクトは止まりません。\nスケジュールは既に決まっている 調整は簡単には認められない 技術的制約を解消するための時間も取れない 結果として、「今の構造のまま、なんとか実装してほしい」という判断が下されます。\nこの時点で、プロジェクトはすでに消耗戦に入り始めています。\n影響範囲が見えないまま進む実装 影響範囲が分からない状態では、エンジニアは慎重になります。しかし、慎重に考えれば考えるほど、時間は足りません。\n安全に直したい でも期限がある 設計を整理する余裕はない その結果、選ばれるのは「期限内に動く可能性が高そうな実装」です。\n設計的には無理があると分かっていても、他に選択肢がないため、応急処置的な実装が積み重なっていきます。\nここで言う「影響範囲がわからない」とはどういう状態か ここで、この記事で使っている「影響範囲がわからない」という言葉の意味を、少しだけ整理します。\nこれは単に、\n調査が足りない エンジニアの理解が浅い という話ではありません。\n影響が 大きすぎて、複雑すぎて、人間の脳の仕組み的に追いきれない という状態を指しています。\nどこを変更すると、\nどの画面に どの機能に どの状態に 影響するのか。\nそれを一人のエンジニアが頭の中で安全にトレースできない。これが「影響範囲が見えない」状態です。\n実装完了後に始まる、本当の消耗戦 スケジュール上は、実装は一度「完了」します。しかし、その後に不具合が多発します。\n影響範囲を把握できないまま実装している以上、これはほぼ必然です。\n想定外の画面で不具合が発生する 特定の操作順でのみ再現するバグが出る 修正すると別の箇所が壊れる 不具合対応という 予定外の作業 が発生し、本来進めるはずだったタスクは後ろ倒しになります。\nエンジニアは長時間労働になり、管理者はスケジュールを組み直すことになります。\n誰も得をしません。\nなぜこの状況は繰り返されるのか この問題は、エンジニアの努力不足ではありません。むしろ、責任感の強いエンジニアほど無理をします。\nしかし、\n影響範囲が見えない設計 技術的負債を返すための時間や構造がない これが変わらない限り、結果も変わりません。\nエンジニアは「疲れたから」辞めているわけではない 長時間労働が続くと、「エンジニアが疲れて辞めた」と説明されがちです。\nしかし実際には、\n頑張っても状況が改善しない 技術的負債が解消される兆しが見えない 消耗戦が続く未来が想像できてしまう こうした 構造的な行き止まり を感じた結果として、プロジェクトを抜ける決断をしているケースが多いのではないでしょうか。\nエンジニアが定期的に入れ替わる現場では、個人の忍耐力やモチベーションではなく、\n影響範囲が見えない設計が放置されていないか 技術的負債を解消するための構造や仕組みが存在するか といった点を、疑うべきだと考えます。\n設計の役割は「人間が判断できる状態」を作ること 設計の役割は、コードを綺麗にすることではありません。\n影響範囲を把握できるようにする 変更に対して判断できる状態を作る 段階的な改善を可能にする 設計とは、 人間が無理なく考えられる状態を作ること です。\n消耗戦を終わらせるために 設計を軽視すれば、短期的にはスピードが出ているように見えるかもしれません。しかしその代償として、現場は確実に消耗していきます。\n設計不良による消耗戦は、エンジニアも、管理者も、プロダクトも疲弊させます。\n設計はコストではありません。 消耗を防ぐための投資 です。\n","permalink":"https://design.okuda-studio.com/posts/0005-problems-caused-by-poor-design/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E4%B8%8D%E8%89%AF%E3%81%AA%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%AE%E7%8F%BE%E5%A0%B4%E3%81%A7%E8%B5%B7%E3%81%8D%E3%81%A6%E3%81%84%E3%82%8B%E3%81%93%E3%81%A8\"\u003e設計不良なソフトウェアの現場で起きていること\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%BD%B1%E9%9F%BF%E7%AF%84%E5%9B%B2%E3%81%8C%E8%A6%8B%E3%81%88%E3%81%AA%E3%81%84%E3%81%BE%E3%81%BE%E9%80%B2%E3%82%80%E5%AE%9F%E8%A3%85\"\u003e影響範囲が見えないまま進む実装\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%93%E3%81%A7%E8%A8%80%E3%81%86%E5%BD%B1%E9%9F%BF%E7%AF%84%E5%9B%B2%E3%81%8C%E3%82%8F%E3%81%8B%E3%82%89%E3%81%AA%E3%81%84%E3%81%A8%E3%81%AF%E3%81%A9%E3%81%86%E3%81%84%E3%81%86%E7%8A%B6%E6%85%8B%E3%81%8B\"\u003eここで言う「影響範囲がわからない」とはどういう状態か\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%AE%9F%E8%A3%85%E5%AE%8C%E4%BA%86%E5%BE%8C%E3%81%AB%E5%A7%8B%E3%81%BE%E3%82%8B%E6%9C%AC%E5%BD%93%E3%81%AE%E6%B6%88%E8%80%97%E6%88%A6\"\u003e実装完了後に始まる、本当の消耗戦\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E3%81%93%E3%81%AE%E7%8A%B6%E6%B3%81%E3%81%AF%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%95%E3%82%8C%E3%82%8B%E3%81%AE%E3%81%8B\"\u003eなぜこの状況は繰り返されるのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AF%E7%96%B2%E3%82%8C%E3%81%9F%E3%81%8B%E3%82%89%E8%BE%9E%E3%82%81%E3%81%A6%E3%81%84%E3%82%8B%E3%82%8F%E3%81%91%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84\"\u003eエンジニアは「疲れたから」辞めているわけではない\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E3%81%AE%E5%BD%B9%E5%89%B2%E3%81%AF%E4%BA%BA%E9%96%93%E3%81%8C%E5%88%A4%E6%96%AD%E3%81%A7%E3%81%8D%E3%82%8B%E7%8A%B6%E6%85%8B%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%93%E3%81%A8\"\u003e設計の役割は「人間が判断できる状態」を作ること\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%B6%88%E8%80%97%E6%88%A6%E3%82%92%E7%B5%82%E3%82%8F%E3%82%89%E3%81%9B%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB\"\u003e消耗戦を終わらせるために\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"設計不良なソフトウェアの現場で起きていること\"\u003e設計不良なソフトウェアの現場で起きていること\u003c/h3\u003e\n\u003cp\u003e設計不良なソフトウェアの現場では、共通して起きることがあります。\u003c/p\u003e\n\u003cp\u003e変更を入れようとすると、「どこまで影響するのか分からない」という声が上がる。\u003c/p\u003e\n\u003cp\u003eそれでも、プロジェクトは止まりません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eスケジュールは既に決まっている\u003c/li\u003e\n\u003cli\u003e調整は簡単には認められない\u003c/li\u003e\n\u003cli\u003e技術的制約を解消するための時間も取れない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e結果として、「今の構造のまま、なんとか実装してほしい」という判断が下されます。\u003c/p\u003e\n\u003cp\u003eこの時点で、プロジェクトはすでに消耗戦に入り始めています。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"影響範囲が見えないまま進む実装\"\u003e影響範囲が見えないまま進む実装\u003c/h3\u003e\n\u003cp\u003e影響範囲が分からない状態では、エンジニアは慎重になります。しかし、慎重に考えれば考えるほど、時間は足りません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e安全に直したい\u003c/li\u003e\n\u003cli\u003eでも期限がある\u003c/li\u003e\n\u003cli\u003e設計を整理する余裕はない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eその結果、選ばれるのは「期限内に動く可能性が高そうな実装」です。\u003c/p\u003e\n\u003cp\u003e設計的には無理があると分かっていても、他に選択肢がないため、応急処置的な実装が積み重なっていきます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"ここで言う影響範囲がわからないとはどういう状態か\"\u003eここで言う「影響範囲がわからない」とはどういう状態か\u003c/h3\u003e\n\u003cp\u003eここで、この記事で使っている「影響範囲がわからない」という言葉の意味を、少しだけ整理します。\u003c/p\u003e\n\u003cp\u003eこれは単に、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e調査が足りない\u003c/li\u003e\n\u003cli\u003eエンジニアの理解が浅い\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eという話ではありません。\u003c/p\u003e\n\u003cp\u003e影響が \u003cstrong\u003e大きすぎて、複雑すぎて、人間の脳の仕組み的に追いきれない\u003c/strong\u003e という状態を指しています。\u003c/p\u003e\n\u003cp\u003eどこを変更すると、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどの画面に\u003c/li\u003e\n\u003cli\u003eどの機能に\u003c/li\u003e\n\u003cli\u003eどの状態に\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e影響するのか。\u003c/p\u003e\n\u003cp\u003eそれを一人のエンジニアが頭の中で安全にトレースできない。これが「影響範囲が見えない」状態です。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"実装完了後に始まる本当の消耗戦\"\u003e実装完了後に始まる、本当の消耗戦\u003c/h3\u003e\n\u003cp\u003eスケジュール上は、実装は一度「完了」します。しかし、その後に不具合が多発します。\u003c/p\u003e\n\u003cp\u003e影響範囲を把握できないまま実装している以上、これはほぼ必然です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e想定外の画面で不具合が発生する\u003c/li\u003e\n\u003cli\u003e特定の操作順でのみ再現するバグが出る\u003c/li\u003e\n\u003cli\u003e修正すると別の箇所が壊れる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e不具合対応という \u003cstrong\u003e予定外の作業\u003c/strong\u003e が発生し、本来進めるはずだったタスクは後ろ倒しになります。\u003c/p\u003e\n\u003cp\u003eエンジニアは長時間労働になり、管理者はスケジュールを組み直すことになります。\u003c/p\u003e\n\u003cp\u003e誰も得をしません。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"なぜこの状況は繰り返されるのか\"\u003eなぜこの状況は繰り返されるのか\u003c/h3\u003e\n\u003cp\u003eこの問題は、エンジニアの努力不足ではありません。むしろ、責任感の強いエンジニアほど無理をします。\u003c/p\u003e\n\u003cp\u003eしかし、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e影響範囲が見えない設計\u003c/li\u003e\n\u003cli\u003e技術的負債を返すための時間や構造がない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれが変わらない限り、結果も変わりません。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"エンジニアは疲れたから辞めているわけではない\"\u003eエンジニアは「疲れたから」辞めているわけではない\u003c/h3\u003e\n\u003cp\u003e長時間労働が続くと、「エンジニアが疲れて辞めた」と説明されがちです。\u003c/p\u003e\n\u003cp\u003eしかし実際には、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e頑張っても状況が改善しない\u003c/li\u003e\n\u003cli\u003e技術的負債が解消される兆しが見えない\u003c/li\u003e\n\u003cli\u003e消耗戦が続く未来が想像できてしまう\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこうした \u003cstrong\u003e構造的な行き止まり\u003c/strong\u003e を感じた結果として、プロジェクトを抜ける決断をしているケースが多いのではないでしょうか。\u003c/p\u003e\n\u003cp\u003eエンジニアが定期的に入れ替わる現場では、個人の忍耐力やモチベーションではなく、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e影響範囲が見えない設計が放置されていないか\u003c/li\u003e\n\u003cli\u003e技術的負債を解消するための構造や仕組みが存在するか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった点を、疑うべきだと考えます。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"設計の役割は人間が判断できる状態を作ること\"\u003e設計の役割は「人間が判断できる状態」を作ること\u003c/h3\u003e\n\u003cp\u003e設計の役割は、コードを綺麗にすることではありません。\u003c/p\u003e","title":"設計不良による消耗戦"},{"content":" ソフトウェア設計が分かっていても、 Android アプリが作れない理由 Android アプリの設計は「掛け算」で成立する Android OS 固有の制約 Kotlin を「使っている」と「使いこなしている」の差 Jetpack Composeは「 UI 実装」ではなく「設計そのもの」 「設計思想 × Android 文脈」が価値になる 自分の強みについて ソフトウェア設計が分かっていても、 Android アプリが作れない理由 ソフトウェア設計が分かっている人が、必ずしも Android アプリをうまく作れるとは限らない。 これは、 Android 開発を続けてきて、何度も実感してきたことだ。\n設計原則を理解している。 責務分離の重要性も分かっている。 それでも、 Android アプリとして形にしようとすると、どこかで無理が出る。\nその理由は、単に Android OS の制約が強いから、というだけではない。\nAndroid アプリの設計は「掛け算」で成立する Android アプリの設計は、次の要素が同時に成立して初めて機能する。\nAndroid OS 固有の制約 Kotlin という言語の前提 Jetpack Compose という UI モデル どれか一つだけ分かっていても足りない。\nAndroid OS 固有の制約 まず避けて通れないのが、 OS の制約だ。\nライフサイクルが複雑で、いつ破棄されるか分からない プロセスは OS 都合で突然 kill される バックグラウンド動作や権限には厳しい制限がある これらを無視した「きれいな設計」は、実機上では簡単に崩れる。\nAndroid では、 壊されることを前提に設計する 必要がある。\nKotlin を「使っている」と「使いこなしている」の差 次に重要なのが、 Kotlin という言語そのものだ。\nKotlin は書きやすいが、設計の前提として使いこなせていないと、簡単に歪みが出る。\n不変性を前提にした設計が、 mutable な状態で侵食される nullable の扱いが曖昧になり、責務境界が崩れる Coroutine のスコープやキャンセルを理解しないまま非同期設計をすると、副作用が漏れる 設計思想があっても、 言語機能を前提に設計を落とせない と、 Android アプリでは破綻しやすい。\nJetpack Composeは「 UI 実装」ではなく「設計そのもの」 Jetpack Compose は、UIフレームワークというより、 設計モデルそのもの だと感じている。\n状態駆動 宣言的 UI 再コンポーズ 副作用の明示的な管理 これらを理解せずに使うと、\nなぜ再描画されるのか分からない どこで状態が変わっているのか追えない UI とロジックの境界が曖昧になる といった問題が起きる。\nCompose を使うということは、 状態と副作用をどう分離するかを設計すること でもある。\n「設計思想 × Android 文脈」が価値になる ここまで書いてきて思うのは、\n一般的なソフトウェア設計が分かっている だけでは Androidアプリは成立しない ということだ。\nAndroid には、\nOS の制約 Kotlin の言語特性 Compose の UI モデル という、強い前提条件がある。\nこれらを理解した上で、\nどこに状態を置くか どこで副作用を起こすか 何を UI に公開し、何を隠すか を判断できて、初めて Android アプリとしての設計 になる。\n自分の強みについて 今回あらためて気づいたのは、自分の強みは\n設計思想 × Android アプリ実装\nの掛け算にある、ということだった。\n世の中を見渡すと、\n設計は分かるが、 Android の文脈が分からない人 Androidは分かるが、設計が分からない人 は、それぞれ一定数いるように思う。\n一方で、 設計と Android の両方を、深く理解している人 は、決して多くないと感じている。\nAndroid という制約の強い環境で 現実的に動く形まで落とし込み 後から破綻しにくい設計を考える これは、設計だけ分かっていても、 Android だけ書けても、簡単には身につかない。\nこれからも、「設計思想 × Android アプリ実装」を積み重ねていきたい。\n","permalink":"https://design.okuda-studio.com/posts/0004-my-strongness/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E8%A8%AD%E8%A8%88%E3%81%8C%E5%88%86%E3%81%8B%E3%81%A3%E3%81%A6%E3%81%84%E3%81%A6%E3%82%82-android-%E3%82%A2%E3%83%97%E3%83%AA%E3%81%8C%E4%BD%9C%E3%82%8C%E3%81%AA%E3%81%84%E7%90%86%E7%94%B1\"\u003eソフトウェア設計が分かっていても、 Android アプリが作れない理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#android-%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E8%A8%AD%E8%A8%88%E3%81%AF%E6%8E%9B%E3%81%91%E7%AE%97%E3%81%A7%E6%88%90%E7%AB%8B%E3%81%99%E3%82%8B\"\u003eAndroid アプリの設計は「掛け算」で成立する\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#android-os-%E5%9B%BA%E6%9C%89%E3%81%AE%E5%88%B6%E7%B4%84\"\u003eAndroid OS 固有の制約\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#kotlin-%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E3%81%A8%E4%BD%BF%E3%81%84%E3%81%93%E3%81%AA%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%81%AE%E5%B7%AE\"\u003eKotlin を「使っている」と「使いこなしている」の差\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#jetpack-compose%E3%81%AF-ui-%E5%AE%9F%E8%A3%85%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%E8%A8%AD%E8%A8%88%E3%81%9D%E3%81%AE%E3%82%82%E3%81%AE\"\u003eJetpack Composeは「 UI 実装」ではなく「設計そのもの」\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%A8%AD%E8%A8%88%E6%80%9D%E6%83%B3--android-%E6%96%87%E8%84%88%E3%81%8C%E4%BE%A1%E5%80%A4%E3%81%AB%E3%81%AA%E3%82%8B\"\u003e「設計思想 × Android 文脈」が価値になる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E8%87%AA%E5%88%86%E3%81%AE%E5%BC%B7%E3%81%BF%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6\"\u003e自分の強みについて\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"ソフトウェア設計が分かっていても-android-アプリが作れない理由\"\u003eソフトウェア設計が分かっていても、 Android アプリが作れない理由\u003c/h2\u003e\n\u003cp\u003eソフトウェア設計が分かっている人が、必ずしも Android アプリをうまく作れるとは限らない。\nこれは、 Android 開発を続けてきて、何度も実感してきたことだ。\u003c/p\u003e\n\u003cp\u003e設計原則を理解している。\n責務分離の重要性も分かっている。\nそれでも、 Android アプリとして形にしようとすると、どこかで無理が出る。\u003c/p\u003e\n\u003cp\u003eその理由は、単に Android OS の制約が強いから、というだけではない。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"android-アプリの設計は掛け算で成立する\"\u003eAndroid アプリの設計は「掛け算」で成立する\u003c/h2\u003e\n\u003cp\u003eAndroid アプリの設計は、次の要素が同時に成立して初めて機能する。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAndroid OS 固有の制約\u003c/li\u003e\n\u003cli\u003eKotlin という言語の前提\u003c/li\u003e\n\u003cli\u003eJetpack Compose という UI モデル\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eどれか一つだけ分かっていても足りない。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"android-os-固有の制約\"\u003eAndroid OS 固有の制約\u003c/h2\u003e\n\u003cp\u003eまず避けて通れないのが、 OS の制約だ。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eライフサイクルが複雑で、いつ破棄されるか分からない\u003c/li\u003e\n\u003cli\u003eプロセスは OS 都合で突然 kill される\u003c/li\u003e\n\u003cli\u003eバックグラウンド動作や権限には厳しい制限がある\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらを無視した「きれいな設計」は、実機上では簡単に崩れる。\u003c/p\u003e\n\u003cp\u003eAndroid では、 \u003cstrong\u003e壊されることを前提に設計する\u003c/strong\u003e 必要がある。\u003c/p\u003e","title":"設計思想 × Androidアプリ実装という自分の強み"},{"content":" 当時のプロジェクト状況 技術的には明らかに課題が見えていた それでも、抜本的な改善をしなかった理由 私が選んだ技術的判断 この経験から学んだこと 当時のプロジェクト状況 以前関わっていたプロジェクトは、多重下請け構造になっており、私自身は二次受け企業と業務委託契約を結んでいました。チーム内には三次受け、二次受け、一次受けのメンバーが混在しており、Android のテックリードは一次受け企業に一人だけという体制でした。\nそのテックリードは複数チームを横断して担当しており、勤務地も異なっていたため、1年間一緒に仕事をしたにもかかわらず、対面どころかオンライン会議で直接会話したこともありませんでした。技術的な判断は基本的にその方に集約されており、私は設計の最終決定を主導できる立場ではありませんでした。\n技術的には明らかに課題が見えていた コードベースを見ていて、技術的な課題は比較的はっきりしていました。ホーム画面に相当する Activity は肥大化しており、多くの責務を抱え込んでいました。Fragment に分割することで、見通しや保守性が大きく改善できる状態だったと思います。\nまた、ドメインロジックやユースケースは一応共通化されていたものの、副作用が多く、どこかを修正すると別の箇所に影響が出やすい構造になっていました。本音を言えば、設計を見直し、腰を据えて整理したいと感じる場面は何度もありました。\nそれでも、抜本的な改善をしなかった理由 ただ、そのような改善は、実装者一人の判断で進められるものではありませんでした。Fragment 分割やドメイン設計の見直しは影響範囲が広く、他社のテックリードとの合意形成が前提になります。\nさらに当時は、設計以前に対処すべき問題が数多く存在しており、プロジェクト全体として常に余裕がない状況でした。その中で大きな構造変更を提案し、進めることは、技術的には正しくても、プロジェクトとしてはリスクが高いと感じていました。\n「重要だと分かっているからこそ、今はやるべきではない」 そう判断せざるを得ない状況だったと思います。\n私が選んだ技術的判断 最終的に私は、抜本的な構造変更は行わないという判断をしました。その代わり、既存の設計を前提としたうえで、自分が責任を持てる範囲に改善を限定し、変更による影響を最小化することを重視しました。\nここでの判断は、「何を実装するか」ではなく、「何をやらないかを決めること」だったと捉えています。設計を理想形に近づけることよりも、プロジェクト全体を不安定にしないことを優先しました。\nこの経験から学んだこと この経験を通じて、技術的な判断はコードの中だけで完結するものではないと強く感じるようになりました。設計の正しさだけでなく、その設計を実行できる組織構造や権限、合意形成のコストまで含めて考える必要があります。\n良い設計を思いつくことと、それを実際に推し進められることは別の話です。その違いを理解し、今やるべきことと、あえてやらないことを切り分けることも、エンジニアの重要な役割だと思っています。\n技術判断は、コードの外にもある。このプロジェクトは、そのことを強く意識するきっかけになりました。\n","permalink":"https://design.okuda-studio.com/posts/0003-decisions-that-were-not-made/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E5%BD%93%E6%99%82%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E7%8A%B6%E6%B3%81\"\u003e当時のプロジェクト状況\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%8A%80%E8%A1%93%E7%9A%84%E3%81%AB%E3%81%AF%E6%98%8E%E3%82%89%E3%81%8B%E3%81%AB%E8%AA%B2%E9%A1%8C%E3%81%8C%E8%A6%8B%E3%81%88%E3%81%A6%E3%81%84%E3%81%9F\"\u003e技術的には明らかに課題が見えていた\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%9D%E3%82%8C%E3%81%A7%E3%82%82%E6%8A%9C%E6%9C%AC%E7%9A%84%E3%81%AA%E6%94%B9%E5%96%84%E3%82%92%E3%81%97%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E7%90%86%E7%94%B1\"\u003eそれでも、抜本的な改善をしなかった理由\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E7%A7%81%E3%81%8C%E9%81%B8%E3%82%93%E3%81%A0%E6%8A%80%E8%A1%93%E7%9A%84%E5%88%A4%E6%96%AD\"\u003e私が選んだ技術的判断\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%93%E3%81%AE%E7%B5%8C%E9%A8%93%E3%81%8B%E3%82%89%E5%AD%A6%E3%82%93%E3%81%A0%E3%81%93%E3%81%A8\"\u003eこの経験から学んだこと\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"当時のプロジェクト状況\"\u003e当時のプロジェクト状況\u003c/h2\u003e\n\u003cp\u003e以前関わっていたプロジェクトは、多重下請け構造になっており、私自身は二次受け企業と業務委託契約を結んでいました。チーム内には三次受け、二次受け、一次受けのメンバーが混在しており、Android のテックリードは一次受け企業に一人だけという体制でした。\u003c/p\u003e\n\u003cp\u003eそのテックリードは複数チームを横断して担当しており、勤務地も異なっていたため、1年間一緒に仕事をしたにもかかわらず、対面どころかオンライン会議で直接会話したこともありませんでした。技術的な判断は基本的にその方に集約されており、私は設計の最終決定を主導できる立場ではありませんでした。\u003c/p\u003e\n\u003ch2 id=\"技術的には明らかに課題が見えていた\"\u003e技術的には明らかに課題が見えていた\u003c/h2\u003e\n\u003cp\u003eコードベースを見ていて、技術的な課題は比較的はっきりしていました。ホーム画面に相当する Activity は肥大化しており、多くの責務を抱え込んでいました。Fragment に分割することで、見通しや保守性が大きく改善できる状態だったと思います。\u003c/p\u003e\n\u003cp\u003eまた、ドメインロジックやユースケースは一応共通化されていたものの、副作用が多く、どこかを修正すると別の箇所に影響が出やすい構造になっていました。本音を言えば、設計を見直し、腰を据えて整理したいと感じる場面は何度もありました。\u003c/p\u003e\n\u003ch2 id=\"それでも抜本的な改善をしなかった理由\"\u003eそれでも、抜本的な改善をしなかった理由\u003c/h2\u003e\n\u003cp\u003eただ、そのような改善は、実装者一人の判断で進められるものではありませんでした。Fragment 分割やドメイン設計の見直しは影響範囲が広く、他社のテックリードとの合意形成が前提になります。\u003c/p\u003e\n\u003cp\u003eさらに当時は、設計以前に対処すべき問題が数多く存在しており、プロジェクト全体として常に余裕がない状況でした。その中で大きな構造変更を提案し、進めることは、技術的には正しくても、プロジェクトとしてはリスクが高いと感じていました。\u003c/p\u003e\n\u003cp\u003e「重要だと分かっているからこそ、今はやるべきではない」\nそう判断せざるを得ない状況だったと思います。\u003c/p\u003e\n\u003ch2 id=\"私が選んだ技術的判断\"\u003e私が選んだ技術的判断\u003c/h2\u003e\n\u003cp\u003e最終的に私は、抜本的な構造変更は行わないという判断をしました。その代わり、既存の設計を前提としたうえで、自分が責任を持てる範囲に改善を限定し、変更による影響を最小化することを重視しました。\u003c/p\u003e\n\u003cp\u003eここでの判断は、「何を実装するか」ではなく、「何をやらないかを決めること」だったと捉えています。設計を理想形に近づけることよりも、プロジェクト全体を不安定にしないことを優先しました。\u003c/p\u003e\n\u003ch2 id=\"この経験から学んだこと\"\u003eこの経験から学んだこと\u003c/h2\u003e\n\u003cp\u003eこの経験を通じて、技術的な判断はコードの中だけで完結するものではないと強く感じるようになりました。設計の正しさだけでなく、その設計を実行できる組織構造や権限、合意形成のコストまで含めて考える必要があります。\u003c/p\u003e\n\u003cp\u003e良い設計を思いつくことと、それを実際に推し進められることは別の話です。その違いを理解し、今やるべきことと、あえてやらないことを切り分けることも、エンジニアの重要な役割だと思っています。\u003c/p\u003e\n\u003cp\u003e技術判断は、コードの外にもある。このプロジェクトは、そのことを強く意識するきっかけになりました。\u003c/p\u003e","title":"技術的に正しいと分かっていながら、あえてやらなかった判断について"},{"content":" なぜクリーンアーキテクチャはドメインを守るのか はじめに 不変条件とは何か 例 不変条件は「判断」そのものである 不変条件が曖昧だと、設計は壊れる 不変条件をドメインに閉じ込める、という判断 なぜドメインなのか 「ドメインを守る」とは、何を守っているのか UI やインフラに不変条件を置くと何が起きるか まとめ おすすめの関連書籍（無料） なぜクリーンアーキテクチャはドメインを守るのか クリーンアーキテクチャはドメインを守っているが、その本質は「判断」を守ることである\nはじめに 「クリーンアーキテクチャでは、ドメインを守ることが重要だ」\nこの説明を、これまで何度も目にしてきましたし、自分でも何となく理解しているつもりでした。\nUI から独立させるため フレームワークに依存させないため テストしやすくするため どれも間違ってはいません。\nただ、実務で設計に向き合えば向き合うほど、\nそれで結局、何が一番大事なのか？\nという疑問が残りました。\n最近、その答えが少しはっきりしてきました。\nクリーンアーキテクチャの本質は、\n「判断をどこに閉じ込めるか？」を決める構造である\nという考え方です。\nどの判断は UI に任せてよいのか どの判断はユースケースで行うべきか どの判断は、絶対に外に漏らしてはいけないのか この「判断の置き場所」を曖昧にしたまま設計すると、\n責務が混ざり 修正のたびに迷いが生まれ 変更に弱い構造 になっていきます。\nでは、\n絶対に外に出してはいけない判断とは何なのか？\nその答えを整理するための言葉が、不変条件 でした。\n（不変条件という言葉は、英語では invariant という言葉でよく使用されます）\nこの記事では、\nクリーンアーキテクチャを「判断の置き場所」という視点で捉え直し その中で不変条件がどんな役割を持つのか なぜ不変条件をドメインに閉じ込めるのか を、実務の感覚に近い形で説明します。\n不変条件とは何か 不変条件とは、\nどれだけ仕様や実装が変わっても、絶対に破ってはいけない前提\nです。\nUI が変わっても API が変わっても DB が変わっても\nこれが壊れたら、そのシステムは成立しない\nそういう条件を指します。\n例 ログインしていないユーザーは、保護された操作をできない 残高は常に 0 以上である 同じ支払いは二重に確定しない これらは\n画面の都合でも 通信の都合でもなく ビジネスやドメインとして「そうでなければならない」条件 です。\n不変条件は「判断」そのものである 不変条件を別の言い方で表すと、こう言えます。\n不変条件 = 揺れてはいけない判断\n開発では、常に判断が発生します。\nどこでチェックするか どの層に責務を持たせるか どこまでを UI に任せるか その中には\n仕様変更で変わってよい判断 絶対に変えてはいけない判断 が混ざっています。\nこの 変えてはいけない判断 を明確に言語化したものが、不変条件です。\n不変条件が曖昧だと、設計は壊れる 不変条件が定義されていないと、次のようなことが起きます。\nある画面ではチェックしているが、別の画面では忘れている API 側では弾いているが、ローカルでは通ってしまう バグが出るたびに「どこで直すか」を毎回悩む これは技術力の問題ではありません。\n判断を置く場所が決まっていない ことが原因です。\n結果として、\n責務が混ざる 修正が各所に散在する 変更に弱い構造になる という状態に陥ります。\n不変条件をドメインに閉じ込める、という判断 ここで、クリーンアーキテクチャの話に戻ります。\nクリーンアーキテクチャが「ドメインを守る」理由は、\n不変条件を、最も外部影響の少ない場所に閉じ込めたい\nからです。\nなぜドメインなのか ドメイン層は、\nUI を知らない フレームワークを知らない 通信や保存方法を知らない つまり、\n最も変わりにくい層 です。\nそこに、\n残高チェック 状態遷移の正当性 ビジネスルール といった 不変条件を集約する。\nこれは\nこの判断は、ここでしか行わない\nと決める行為そのものです。\n「ドメインを守る」とは、何を守っているのか よくある説明では、\nドメインを UI から守る ドメインをフレームワークから守る と言われます。\nしかし、本質は少し違います。\n守っているのは、ドメインではなく「判断」 です。\nここで必ずチェックする ここで必ず保証する ここでは絶対に例外を許さない という判断を、\n仕様変更 実装都合 短期的な修正 から守っている。\nそれが結果として「ドメインを守っている」ように見えるだけです。\nUI やインフラに不変条件を置くと何が起きるか 不変条件を\nUI ViewModel Controller に置くと、どうなるでしょうか。\n画面が増えるたびに同じ判断が必要になる 実装漏れが起きる 「この画面だけ例外」が増える 不変条件は、本来\n考えなくていいようにするためのもの\nなのに、\n毎回考え直す対象 になってしまいます。\nまとめ 不変条件とは、揺れてはいけない判断である 設計とは、判断を置く場所を決める行為である クリーンアーキテクチャは、不変条件をドメインに閉じ込めるための構造である 「ドメインを守る」とは、「判断を守る」ことに他ならない クリーンアーキテクチャを\n難しいもの 大げさなもの と感じている場合、\n一度 不変条件という言葉 で捉え直してみてください。\n「なぜここにロジックを置くのか」 「なぜここに依存させないのか」\nその理由が、かなりクリアになるはずです。\nこの記事が、\n設計に違和感を感じている人 クリーンアーキテクチャにモヤっとしている人 の視点整理の助けになれば嬉しいです。\nおすすめの関連書籍（無料） この記事で触れた\n判断をどこに置くか 不変条件をどう扱うか 構造で設計を考えるとはどういうことか といったテーマについて、より体系的にまとめた本があります。\n『ソフトウェア開発における設計の本質』 https://zenn.dev/okuda0715tech/books/d5b48f9e2221d7\n無料で公開しているので、もしこの記事の内容に共感いただけたら、あわせて読んでみてください。\n","permalink":"https://design.okuda-studio.com/posts/0002-why-clean-architecture-guard-domain/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3%E3%81%AF%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92%E5%AE%88%E3%82%8B%E3%81%AE%E3%81%8B\"\u003eなぜクリーンアーキテクチャはドメインを守るのか\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\"\u003eはじめに\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B\"\u003e不変条件とは何か\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%8B\"\u003e例\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6%E3%81%AF%E5%88%A4%E6%96%AD%E3%81%9D%E3%81%AE%E3%82%82%E3%81%AE%E3%81%A7%E3%81%82%E3%82%8B\"\u003e不変条件は「判断」そのものである\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6%E3%81%8C%E6%9B%96%E6%98%A7%E3%81%A0%E3%81%A8%E8%A8%AD%E8%A8%88%E3%81%AF%E5%A3%8A%E3%82%8C%E3%82%8B\"\u003e不変条件が曖昧だと、設計は壊れる\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6%E3%82%92%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AB%E9%96%89%E3%81%98%E8%BE%BC%E3%82%81%E3%82%8B%E3%81%A8%E3%81%84%E3%81%86%E5%88%A4%E6%96%AD\"\u003e不変条件をドメインに閉じ込める、という判断\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%AA%E3%81%9C%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%AA%E3%81%AE%E3%81%8B\"\u003eなぜドメインなのか\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%82%92%E5%AE%88%E3%82%8B%E3%81%A8%E3%81%AF%E4%BD%95%E3%82%92%E5%AE%88%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E3%81%AE%E3%81%8B\"\u003e「ドメインを守る」とは、何を守っているのか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ui-%E3%82%84%E3%82%A4%E3%83%B3%E3%83%95%E3%83%A9%E3%81%AB%E4%B8%8D%E5%A4%89%E6%9D%A1%E4%BB%B6%E3%82%92%E7%BD%AE%E3%81%8F%E3%81%A8%E4%BD%95%E3%81%8C%E8%B5%B7%E3%81%8D%E3%82%8B%E3%81%8B\"\u003eUI やインフラに不変条件を置くと何が起きるか\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%BE%E3%81%A8%E3%82%81\"\u003eまとめ\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%8A%E3%81%99%E3%81%99%E3%82%81%E3%81%AE%E9%96%A2%E9%80%A3%E6%9B%B8%E7%B1%8D%E7%84%A1%E6%96%99\"\u003eおすすめの関連書籍（無料）\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"なぜクリーンアーキテクチャはドメインを守るのか\"\u003eなぜクリーンアーキテクチャはドメインを守るのか\u003c/h1\u003e\n\u003cp\u003eクリーンアーキテクチャはドメインを守っているが、その本質は「判断」を守ることである\u003c/p\u003e\n\u003ch2 id=\"はじめに\"\u003eはじめに\u003c/h2\u003e\n\u003cp\u003e「クリーンアーキテクチャでは、ドメインを守ることが重要だ」\u003c/p\u003e\n\u003cp\u003eこの説明を、これまで何度も目にしてきましたし、自分でも何となく理解しているつもりでした。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUI から独立させるため\u003c/li\u003e\n\u003cli\u003eフレームワークに依存させないため\u003c/li\u003e\n\u003cli\u003eテストしやすくするため\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eどれも間違ってはいません。\u003c/p\u003e\n\u003cp\u003eただ、実務で設計に向き合えば向き合うほど、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eそれで結局、何が一番大事なのか？\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eという疑問が残りました。\u003c/p\u003e\n\u003cp\u003e最近、その答えが少しはっきりしてきました。\u003c/p\u003e\n\u003cp\u003eクリーンアーキテクチャの本質は、\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e「判断をどこに閉じ込めるか？」を決める構造である\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eという考え方です。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eどの判断は UI に任せてよいのか\u003c/li\u003e\n\u003cli\u003eどの判断はユースケースで行うべきか\u003c/li\u003e\n\u003cli\u003eどの判断は、絶対に外に漏らしてはいけないのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこの「判断の置き場所」を曖昧にしたまま設計すると、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e責務が混ざり\u003c/li\u003e\n\u003cli\u003e修正のたびに迷いが生まれ\u003c/li\u003e\n\u003cli\u003e変更に弱い構造\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eになっていきます。\u003c/p\u003e\n\u003cp\u003eでは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e絶対に外に出してはいけない判断とは何なのか？\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eその答えを整理するための言葉が、\u003cstrong\u003e不変条件\u003c/strong\u003e でした。\u003c/p\u003e\n\u003cp\u003e（不変条件という言葉は、英語では invariant という言葉でよく使用されます）\u003c/p\u003e\n\u003cp\u003eこの記事では、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eクリーンアーキテクチャを「判断の置き場所」という視点で捉え直し\u003c/li\u003e\n\u003cli\u003eその中で不変条件がどんな役割を持つのか\u003c/li\u003e\n\u003cli\u003eなぜ不変条件をドメインに閉じ込めるのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eを、実務の感覚に近い形で説明します。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"不変条件とは何か\"\u003e不変条件とは何か\u003c/h2\u003e\n\u003cp\u003e不変条件とは、\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eどれだけ仕様や実装が変わっても、絶対に破ってはいけない前提\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eです。\u003c/p\u003e\n\u003cp\u003eUI が変わっても\nAPI が変わっても\nDB が変わっても\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eこれが壊れたら、そのシステムは成立しない\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eそういう条件を指します。\u003c/p\u003e\n\u003ch3 id=\"例\"\u003e例\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eログインしていないユーザーは、保護された操作をできない\u003c/li\u003e\n\u003cli\u003e残高は常に 0 以上である\u003c/li\u003e\n\u003cli\u003e同じ支払いは二重に確定しない\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eこれらは\u003c/p\u003e","title":"なぜクリーンアーキテクチャはドメインを守るのか"},{"content":" アーキテクチャとは 依存関係とは 物理的な依存関係 意味的な依存関係 ドメインとは ドメイン以外 同心円状の図の意味 意味的な依存関係とクリーンアーキテクチャ 具体例 依存関係の逆転が必要なケース 依存関係を逆転させる具体的な方法 おすすめの記事 おすすめの本（無料） クリーンアーキテクチャという言葉はよく聞くけれど、「わかったようでわからない」という人が多いのではないでしょうか？\nクリーンアーキテクチャを解説した記事は、探せばすぐに出てきますが、あまり本質について語られている記事は少ないように感じます。\nそこで、この記事でそれを簡潔に語っていこうと思います。\nアーキテクチャとは まず、そもそも「アーキテクチャ」とは何でしょうか？簡潔に説明したいので、どんどん答えを書いていきます。\n目的 壊れにくいソフトウェアを作る チーム内で統一した方針でソフトウェアを作る 実現方法 部品 (※1) 同士の依存関係 (※2) を整える 部品が果たす役割・責務を明確にする (※1) 「部品って具体的に何？」と思われた方は、一旦、クラスだと思っていただければ大丈夫です。 (※2) 後述します。\nめちゃくちゃシンプルに書くとこうなると思います。\n依存関係とは クリーンアーキテクチャの本質を知るためには、このセクションがめちゃくちゃ大事です！！ 「そんなの知ってるわ」という方も、クリーンアーキテクチャについての理解が「モヤッ」としている方は読んでください。\n依存関係には、二種類の依存関係があります。\n物理的な依存関係 まずは、物理的な依存関係について説明します。これは、多くの人が最初に思い浮かぶ依存関係の方だと思われます。\nすなわち、「どの部品 (クラスなど) がどの部品のことを知っているか」という関係性のことです。\n(このドキュメントのサンプルコードは Kotlin で記述させていただきます。ご了承ください。)\nclass A { val b: B } class B { // ... } 上記のサンプルでは、クラス A がクラス B を知っているので、これを「 A が B に依存している」と言います。\nこれが、物理的な依存関係です。 (超ざっくり)\n意味的な依存関係 次に、意味的な依存関係について説明します。ここで、クリーンアーキテクチャの記事でよく出てくる同心円状の図を見て下さい。 (探せばすぐに出てくるのでここには載せません。笑)\nドメインとは 中心にあるのが、 ドメインモデル や エンティティ ではないでしょうか？その一つ外側にあるのが、 ビジネスルール や ユースケース ではないでしょうか？\nそれらの中心の二つは、本質を理解する上では、同じものとみなして問題ないため、これらをまとめて ドメイン と呼ぶことにします。\nドメインとは、簡単に言うと、ソフトウェアで実現したい中心的な機能のことです。\n例えば、おみくじアプリなら、以下のようなものがあります。\nくじを表すモデル ユーザーがくじを引いたときに、どのくじを選ぶかのロジック ドメイン以外 クリーンアーキテクチャの本質を理解する上では、ドメインかドメイン以外かだけを区別すれば大丈夫です。\nドメイン以外のものの例を少し上げておきます。\nユーザーインターフェース (つまり画面そのもの) データベース リポジトリ 同心円状の図の意味 同心円状の図を見ると、「ドメイン以外」のものから「ドメイン」へ向かっていく方向で、いくつもの矢印が書いてあるはずです。この矢印が意味的な依存関係を示しています。\n意味的な依存関係がこうなっていると、ソフトウェアが壊れにくいよ！\nめっちゃ簡単に言うと、この図が示している意味はそれだけです。\n意味的な依存関係とクリーンアーキテクチャ 意味的な依存関係とは、コードには現れません。開発者の頭の中にだけ存在するものです。コードに現れるのは、物理的な依存関係だけです。\nでは、意味的な依存関係とは何なのか？\n意味的な依存関係とは、「物理的な依存関係の本来あるべき姿」のことです。\n「どの変更がどこに影響してほしいか／してほしくないか」によって、意味的な依存関係を定義します。\nつまり、物理的な依存関係が A -\u0026gt; B となっているけれど、「 B の変更の影響は B に閉じていてほしい」という場合、意味的な依存関係は A \u0026lt;- B となります。\nそして、本来あるべき依存関係を、ネットでよく見る「同心円状の図」のように思い描くことが クリーンアーキテクチャ とよばれる思想です。 これで、「クリーンアーキテクチャは思想だ」と言われる理由が分かったのではないでしょうか？\n具体例 ここからは、具体例をあげていきます。\n依存関係の逆転が必要なケース 多くのソフトウェアでは、\nユーザー入力 ビジネスロジックを実行 結果を保存 という流れを持っているのではないでしょうか？\nこの場合、普通に実装すると\nUI -\u0026gt; ドメイン -\u0026gt; リポジトリ という物理的な依存関係になると思います。\nしかし、思い出してください。 クリーンアーキテクチャでは、こう\nドメイン -\u0026gt; リポジトリ ではなく、こういう依存関係にしたかったはずです。\nリポジトリ -\u0026gt; ドメイン では、どうすれば依存関係が逆転できるのか？\n依存関係を逆転させる具体的な方法 逆転させる方法は、多くのエンジニアが知っている簡単な方法です。インターフェースを挟めば良いのです。\nインターフェースを挟む前：\nclass Domain { val repository: Repository } class Repository { // ... } インターフェースを挟んだ後：\nclass Domain { val repository: Repository interface Repository { // (※ 1) // ... } } class RepositoryImpl: Repository { // RepositoryImpl は、具体的な実装を持っているため // インターフェースを挟む前の Repository に相当します。 } (※ 1) 実際のプロジェクトでは、Repository インターフェースは Domain パッケージ直下などに 定義されることも多いですが、ここでは「ドメインの持ち物である」ことを強調するため、 この形で示しています。\nこうすることで、 Domain は\n自分の持ち物である Repository インターフェースにだけ依存する RepositoryImpl (リポジトリ本体) には依存していない RepositoryImpl は\nDomain の持ち物である Repository に依存する そのため、実質的に Domain に依存しているのと同じ という状況ができました。\nつまり、物理的な依存関係が意味的な依存関係である\nリポジトリ -\u0026gt; ドメイン という関係性になりました。\n「 Domain が Repository インターフェースに依存するのはいいのか？」 という声が聞こえてきそうですが、いいんです。 なぜなら、自分の持ち物であるから。\n自分の持ち物であるインターフェースに変更が発生したら、自分自身に影響が出るのはあたり前だからいいんです。\n問題なのは、自分に関係のない修正が発生した場合に、自分に影響が出ることです。\nそれが起きると、ちょっと修正しただけで、影響が爆発的に増えるソフトウェアになってしまいます。\nおすすめの記事 この記事では、「なぜドメインが図の中心にくると壊れにくいのか」には触れておりません。\nその理由はこちらの記事（ なぜクリーンアーキテクチャはドメインを守るのか ）で解説しております。\nもし、気になる方は、あわせてご参考にしていただけますと幸いです。\nおすすめの本（無料） クリーンアーキテクチャは、依存関係の話であり、 その本質は「どこで判断を終わらせるか」という話でもあります。\nこの「判断」という視点で、 状態・イベント・境界・UI・ViewModel が どこまで判断し、どこから判断を持ち越さないかを整理したものを、 『設計の本質』 という本にまとめ、無料公開しています。\nクリーンアーキテクチャが 「図としてはわかるが、実装になると迷う」 と感じていた方には、 補助線として役に立つはずですので、 あわせてご参考にしていただけますと幸いです。\n","permalink":"https://design.okuda-studio.com/posts/0001-clean-architecture-core/","summary":"\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3%E3%81%A8%E3%81%AF\"\u003eアーキテクチャとは\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%9D%E5%AD%98%E9%96%A2%E4%BF%82%E3%81%A8%E3%81%AF\"\u003e依存関係とは\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E7%89%A9%E7%90%86%E7%9A%84%E3%81%AA%E4%BE%9D%E5%AD%98%E9%96%A2%E4%BF%82\"\u003e物理的な依存関係\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%84%8F%E5%91%B3%E7%9A%84%E3%81%AA%E4%BE%9D%E5%AD%98%E9%96%A2%E4%BF%82\"\u003e意味的な依存関係\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%81%A8%E3%81%AF\"\u003eドメインとは\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E4%BB%A5%E5%A4%96\"\u003eドメイン以外\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%90%8C%E5%BF%83%E5%86%86%E7%8A%B6%E3%81%AE%E5%9B%B3%E3%81%AE%E6%84%8F%E5%91%B3\"\u003e同心円状の図の意味\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E6%84%8F%E5%91%B3%E7%9A%84%E3%81%AA%E4%BE%9D%E5%AD%98%E9%96%A2%E4%BF%82%E3%81%A8%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3\"\u003e意味的な依存関係とクリーンアーキテクチャ\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E5%85%B7%E4%BD%93%E4%BE%8B\"\u003e具体例\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%9D%E5%AD%98%E9%96%A2%E4%BF%82%E3%81%AE%E9%80%86%E8%BB%A2%E3%81%8C%E5%BF%85%E8%A6%81%E3%81%AA%E3%82%B1%E3%83%BC%E3%82%B9\"\u003e依存関係の逆転が必要なケース\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E4%BE%9D%E5%AD%98%E9%96%A2%E4%BF%82%E3%82%92%E9%80%86%E8%BB%A2%E3%81%95%E3%81%9B%E3%82%8B%E5%85%B7%E4%BD%93%E7%9A%84%E3%81%AA%E6%96%B9%E6%B3%95\"\u003e依存関係を逆転させる具体的な方法\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%8A%E3%81%99%E3%81%99%E3%82%81%E3%81%AE%E8%A8%98%E4%BA%8B\"\u003eおすすめの記事\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#%E3%81%8A%E3%81%99%E3%81%99%E3%82%81%E3%81%AE%E6%9C%AC%E7%84%A1%E6%96%99\"\u003eおすすめの本（無料）\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eクリーンアーキテクチャという言葉はよく聞くけれど、「わかったようでわからない」という人が多いのではないでしょうか？\u003c/p\u003e\n\u003cp\u003eクリーンアーキテクチャを解説した記事は、探せばすぐに出てきますが、あまり本質について語られている記事は少ないように感じます。\u003c/p\u003e\n\u003cp\u003eそこで、この記事でそれを簡潔に語っていこうと思います。\u003c/p\u003e\n\u003ch1 id=\"アーキテクチャとは\"\u003eアーキテクチャとは\u003c/h1\u003e\n\u003cp\u003eまず、そもそも「アーキテクチャ」とは何でしょうか？簡潔に説明したいので、どんどん答えを書いていきます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e目的\n\u003cul\u003e\n\u003cli\u003e壊れにくいソフトウェアを作る\u003c/li\u003e\n\u003cli\u003eチーム内で統一した方針でソフトウェアを作る\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e実現方法\n\u003cul\u003e\n\u003cli\u003e部品 (※1) 同士の依存関係 (※2) を整える\u003c/li\u003e\n\u003cli\u003e部品が果たす役割・責務を明確にする\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e(※1) 「部品って具体的に何？」と思われた方は、一旦、クラスだと思っていただければ大丈夫です。\n(※2) 後述します。\u003c/p\u003e\n\u003cp\u003eめちゃくちゃシンプルに書くとこうなると思います。\u003c/p\u003e\n\u003ch1 id=\"依存関係とは\"\u003e依存関係とは\u003c/h1\u003e\n\u003cp\u003eクリーンアーキテクチャの本質を知るためには、このセクションがめちゃくちゃ大事です！！\n「そんなの知ってるわ」という方も、クリーンアーキテクチャについての理解が「モヤッ」としている方は読んでください。\u003c/p\u003e\n\u003cp\u003e依存関係には、二種類の依存関係があります。\u003c/p\u003e\n\u003ch2 id=\"物理的な依存関係\"\u003e物理的な依存関係\u003c/h2\u003e\n\u003cp\u003eまずは、物理的な依存関係について説明します。これは、多くの人が最初に思い浮かぶ依存関係の方だと思われます。\u003c/p\u003e\n\u003cp\u003eすなわち、「どの部品 (クラスなど) がどの部品のことを知っているか」という関係性のことです。\u003c/p\u003e\n\u003cp\u003e(このドキュメントのサンプルコードは Kotlin で記述させていただきます。ご了承ください。)\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-kotlin\" data-lang=\"kotlin\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eA\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eval\u003c/span\u003e b: B\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eB\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// ...\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e上記のサンプルでは、クラス A がクラス B を知っているので、これを「 A が B に依存している」と言います。\u003c/p\u003e\n\u003cp\u003eこれが、物理的な依存関係です。 (超ざっくり)\u003c/p\u003e\n\u003ch2 id=\"意味的な依存関係\"\u003e意味的な依存関係\u003c/h2\u003e\n\u003cp\u003e次に、意味的な依存関係について説明します。ここで、クリーンアーキテクチャの記事でよく出てくる同心円状の図を見て下さい。 (探せばすぐに出てくるのでここには載せません。笑)\u003c/p\u003e","title":"クリーンアーキテクチャの本質をわかりやすく解説"},{"content":"Zenn で記事を書いていましたが、\n将来的な資産化を考えて Hugo + GitHub Pages で\n技術ブログを始めることにしました。\nこのブログでは、\nAndroid / Jetpack Compose 設計・アーキテクチャ 技術的な意思決定（ADR） について書いていきます。\n","permalink":"https://design.okuda-studio.com/hello/","summary":"\u003cp\u003eZenn で記事を書いていましたが、\u003cbr\u003e\n将来的な資産化を考えて Hugo + GitHub Pages で\u003cbr\u003e\n技術ブログを始めることにしました。\u003c/p\u003e\n\u003cp\u003eこのブログでは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAndroid / Jetpack Compose\u003c/li\u003e\n\u003cli\u003e設計・アーキテクチャ\u003c/li\u003e\n\u003cli\u003e技術的な意思決定（ADR）\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eについて書いていきます。\u003c/p\u003e","title":"技術ブログを始めました"},{"content":"Zenn で記事を書いていましたが、長期的な執筆活動を見越して、 Hugo + GitHub Pages で、技術ブログを始めることにしました。\nこのブログでは、\nAndroid / Jetpack Compose 設計・アーキテクチャ 技術的な意思決定（ADR） について書いていきます。\n","permalink":"https://design.okuda-studio.com/posts/0000-first-post/","summary":"\u003cp\u003eZenn で記事を書いていましたが、長期的な執筆活動を見越して、 Hugo + GitHub Pages で、技術ブログを始めることにしました。\u003c/p\u003e\n\u003cp\u003eこのブログでは、\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAndroid / Jetpack Compose\u003c/li\u003e\n\u003cli\u003e設計・アーキテクチャ\u003c/li\u003e\n\u003cli\u003e技術的な意思決定（ADR）\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eについて書いていきます。\u003c/p\u003e","title":"技術ブログを始めました"},{"content":" 目的 このウェブサイトは、Android / Jetpack Compose を中心に、 設計について考えたことを記録する場所 です。\n実装そのものの詳細よりも、以下の点に焦点を当てています。\nなぜそう判断したのか どこに違和感を覚えたのか どの責務をどこに置くべきだと考えたのか といった、判断の背景や思考の過程を言語化することを目的としています。\n「設計で、迷わなくなるために。」という言葉は、正解を断言するという意味ではなく、 迷い続けながらも、自分なりに判断できる軸を持つ ことを目指す、という意図で掲げています。\nこのサイトは、自分にとっては、過去の考えを振り返れる場所として存在します。つまり、自分が下した設計判断について、時間がたってから その判断が正しかったのか を振り返るためにあります。これは、チーム開発でも 判断を引き受ける という役割を担うための修行でもあります。\n読者の皆様にとっては、過去にさかのぼることで、私がどのような判断軸や思想を持ち、どのような試行錯誤を積み重ねてきたのか その活動の履歴を確認できる場所 でありたいと考えています。\n扱うテーマ このブログでは、主に以下のようなテーマを扱います。\nソフトウェア設計・設計思想 責務・境界・判断の置き方 Android アプリ開発 Jetpack Compose / アーキテクチャ / 状態管理 技術的な話題であっても、「API の使い方」より「どう考えるか」に重心を置いています。\n対象読者 以下のような方を想定しています。\nAndroid 開発の基礎は一通り理解している 実装はできるが、設計に違和感を覚えることが増えてきた 正解が一つに見えない問題に悩んでいる 一方で、完全な初心者向けの入門解説や、 流行技術の速報的な内容は主な対象としていません。\n書かないこと このブログでは、次のようなことは意図的に行いません。\n断定的に「これが唯一の正解」と言い切ること 炎上や対立を目的とした強い主張 技術トレンドの網羅や速報 あくまで、 現場で考え、悩み、判断してきた記録 を残すことを大切にしています。\n筆者について Android アプリ開発に長く携わってきました。\n実装だけでなく、 設計・レビュー・判断の難しさに悩む場面を多く経験する中で、 「違和感を言葉にすること」の重要性を強く感じ、このブログを書いています。\nここに書かれている内容は、完成された答えではなく、 その時点での考えのスナップショット です。\n記事が増えるにつれて、考えが変わったり、書き直したくなる部分も出てくると思いますが、それも含めて、このブログの一部だと考えています。\n仕事のご相談・連絡について このブログを読んで、「考え方が合いそう」「一度話してみたい」と感じていただけた方は、本ページ末尾のメールアドレスにご連絡ください。\nいきなり具体的な依頼でなくても構いません。初期段階の技術的な前提整理や、進め方の相談からお話しできればと思います。\n※ 営業目的・大量送信と思われる連絡には返信できない場合があります。\nポートフォリオについて GitHub とこのウェブサイトを合わせてご覧ください。\nGitHub：実装力・設計の落とし込み方 このサイト：日常的な判断基準・設計思想 両方を見ることで、より立体的に人物像を判断していただける構成を意図しています。\n外部プラットフォームとの関係 Zenn などの外部サービスには、入口として一部の記事や要約を掲載することがありますが、原本は常にこのサイトに置いています。\nこのサイトは、流行やプラットフォームに依存しない 技術と思考の保管庫（基地） として運用しています。\n連絡先 Mail okuda0715biz[at]gmail.com [at] 部分を @ に置き換えてください。 各種リンク GitHub https://github.com/okuda0715tech X https://twitter.com/okuda_studio Zenn https://zenn.dev/okuda0715tech Wantedly https://www.wantedly.com/id/okuda_tomohiro Goole Play Store https://play.google.com/store/apps/dev?id=8535228467829048647 ","permalink":"https://design.okuda-studio.com/about/","summary":"\u003chr\u003e\n\u003ch2 id=\"目的\"\u003e目的\u003c/h2\u003e\n\u003cp\u003eこのウェブサイトは、Android / Jetpack Compose を中心に、 \u003cstrong\u003e設計について考えたことを記録する場所\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003e実装そのものの詳細よりも、以下の点に焦点を当てています。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eなぜそう判断したのか\u003c/li\u003e\n\u003cli\u003eどこに違和感を覚えたのか\u003c/li\u003e\n\u003cli\u003eどの責務をどこに置くべきだと考えたのか\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eといった、判断の背景や思考の過程を言語化することを目的としています。\u003c/p\u003e\n\u003cp\u003e「設計で、迷わなくなるために。」という言葉は、正解を断言するという意味ではなく、 \u003cstrong\u003e迷い続けながらも、自分なりに判断できる軸を持つ\u003c/strong\u003e ことを目指す、という意図で掲げています。\u003c/p\u003e\n\u003cp\u003eこのサイトは、自分にとっては、過去の考えを振り返れる場所として存在します。つまり、自分が下した設計判断について、時間がたってから \u003cstrong\u003eその判断が正しかったのか\u003c/strong\u003e を振り返るためにあります。これは、チーム開発でも \u003cstrong\u003e判断を引き受ける\u003c/strong\u003e という役割を担うための修行でもあります。\u003c/p\u003e\n\u003cp\u003e読者の皆様にとっては、過去にさかのぼることで、私がどのような判断軸や思想を持ち、どのような試行錯誤を積み重ねてきたのか \u003cstrong\u003eその活動の履歴を確認できる場所\u003c/strong\u003e でありたいと考えています。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"扱うテーマ\"\u003e扱うテーマ\u003c/h2\u003e\n\u003cp\u003eこのブログでは、主に以下のようなテーマを扱います。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eソフトウェア設計・設計思想\u003c/li\u003e\n\u003cli\u003e責務・境界・判断の置き方\u003c/li\u003e\n\u003cli\u003eAndroid アプリ開発\u003c/li\u003e\n\u003cli\u003eJetpack Compose / アーキテクチャ / 状態管理\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e技術的な話題であっても、「API の使い方」より「どう考えるか」に重心を置いています。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"対象読者\"\u003e対象読者\u003c/h2\u003e\n\u003cp\u003e以下のような方を想定しています。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAndroid 開発の基礎は一通り理解している\u003c/li\u003e\n\u003cli\u003e実装はできるが、設計に違和感を覚えることが増えてきた\u003c/li\u003e\n\u003cli\u003e正解が一つに見えない問題に悩んでいる\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e一方で、完全な初心者向けの入門解説や、\n流行技術の速報的な内容は主な対象としていません。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"書かないこと\"\u003e書かないこと\u003c/h2\u003e\n\u003cp\u003eこのブログでは、次のようなことは意図的に行いません。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e断定的に「これが唯一の正解」と言い切ること\u003c/li\u003e\n\u003cli\u003e炎上や対立を目的とした強い主張\u003c/li\u003e\n\u003cli\u003e技術トレンドの網羅や速報\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eあくまで、\n\u003cstrong\u003e現場で考え、悩み、判断してきた記録\u003c/strong\u003e を残すことを大切にしています。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"筆者について\"\u003e筆者について\u003c/h2\u003e\n\u003cp\u003eAndroid アプリ開発に長く携わってきました。\u003c/p\u003e\n\u003cp\u003e実装だけでなく、\n設計・レビュー・判断の難しさに悩む場面を多く経験する中で、\n「違和感を言葉にすること」の重要性を強く感じ、このブログを書いています。\u003c/p\u003e\n\u003cp\u003eここに書かれている内容は、完成された答えではなく、 \u003cstrong\u003eその時点での考えのスナップショット\u003c/strong\u003e です。\u003c/p\u003e\n\u003cp\u003e記事が増えるにつれて、考えが変わったり、書き直したくなる部分も出てくると思いますが、それも含めて、このブログの一部だと考えています。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"仕事のご相談連絡について\"\u003e仕事のご相談・連絡について\u003c/h2\u003e\n\u003cp\u003eこのブログを読んで、「考え方が合いそう」「一度話してみたい」と感じていただけた方は、本ページ末尾のメールアドレスにご連絡ください。\u003c/p\u003e\n\u003cp\u003eいきなり具体的な依頼でなくても構いません。初期段階の技術的な前提整理や、進め方の相談からお話しできればと思います。\u003c/p\u003e\n\u003cp\u003e※ 営業目的・大量送信と思われる連絡には返信できない場合があります。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"ポートフォリオについて\"\u003eポートフォリオについて\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/okuda0715tech\"\u003eGitHub\u003c/a\u003e とこのウェブサイトを合わせてご覧ください。\u003c/p\u003e","title":"サイト概要"}]