企業環境向けのソフトウェアシステムを構築するには、コードを書くこと以上に、そのシステムを動かすビジネスロジックを深く理解することが求められる。この理解の核となるのがドメインモデルである。この責任に新たに取り組むアーキテクトにとって、理論的な設計から実際の実装への移行は、些細だが高コストな誤りを含みがちである。強固なドメインモデルは、単一の真実の源として機能し、ビジネス要件と技術的実装の間のギャップを埋める。しかし、注意を怠れば、意図は良くても、複雑さの前に設計が崩れてしまうことがある。
本書では、企業アーキテクチャの設計段階でよく見られる誤りを検証する。これらの罠を早期に特定することで、耐障害性があり、保守が容易で、組織の目標と整合性を持つシステムを構築できる。具体的なパターンや一般的な誤解、そしてモデルが長期間にわたって通用するようにするための実践的な戦略についても詳しく説明する。

貧弱なドメインモデルの罠 💀
現代のソフトウェア開発で最も広く見られる問題の一つが、貧弱なドメインモデルの作成である。ドメインオブジェクトが単なるデータコンテナにまで簡略化され、パブリックプロパティやゲッター/セッターは持つが、振る舞いが欠如している状態を指す。この状況では、ビジネスロジックがドメイン層から外れ、サービスクラスやコントローラーに散らばってしまう。
- なぜ起こるのか:開発者は、オブジェクト指向の原則よりも、データベースマッピングの容易さを優先しがちである。彼らはオブジェクトを主にテーブルの行として捉えている。
- 結果として:ドメインの意味が失われる。検証ルールが散らばり、オブジェクト自体が自己の整合性を保証しないため、エンティティのライフサイクルを追跡するのが難しくなる。
- 影響として:保守コストが急上昇する。ビジネスルールを変更するには、単一のドメインメソッドを変更するのではなく、複数のサービス層を修正しなければならない。
これを避けるためには、エンティティが状態と振る舞いをカプセル化していることを確認する必要がある。Customerオブジェクトは、注文を出す方法を知っているべきであり、注文を作成するために必要なデータを保持するだけでは不十分である。注文制限、クレジットチェック、アカウントステータスに関するロジックは、Customerクラス自体に存在すべきである。
分断された共通言語 🗣️
ドメイン駆動設計(DDD)は、共通言語(ユビキタス・ランゲージ)の重要性を強調している。これは、ビジネス関係者と技術チームが共有する語彙である。新任アーキテクトがよく陥る落とし穴は、ビジネスコンテキストとコード実装の間でこの言語が分断されることである。
ビジネスが「クライアント」と呼ぶのに、コードでは「UserAccount」を使用している場合、混乱は避けられない。ステークホルダーが「注文の履行」について話しているのに、システムは「出荷ステータス」をモデル化しているならば、モデルは現実を反映していない。この分断は、次のような結果をもたらす。
- 誤解:要件が翻訳段階で誤解される。
- リファクタリングの負担:変化するビジネス用語に合わせて、コードベースに常に変更を加える必要がある。
- 信頼の喪失:開発者がビジネスからの入力を聞かなくなる。なぜなら、システム内で彼らの用語が尊重されていないからである。
整合性を図るための戦略:
- 用語を明確に定義するワークショップを開催する。
- コード名をビジネス用語集と完全に一致させる。
- 用語集を常に更新される生きた文書として記録し、コードと並行して更新する。
理解を欠いたままの過剰設計 🏗️
建築家が、あらゆる想定される将来のシナリオに対応できる完璧で柔軟なシステムを設計しようとする誘惑がある。これはしばしば「YAGNI(あなたはそれが必要としない)」違反と呼ばれる。新米の建築家は、存在しない要件を想定して、複雑な継承階層や汎用インターフェースを頻繁に作成する。
過剰設計のリスク:
- 複雑性の増加:単純なユースケースが、構造がやりすぎているため実装が難しくなる。
- 隠れたバグ:複雑な論理経路は、エラーの発生機会を増やす。
- 遅延した納品:「完璧な」解決策を設計するのに費やす時間は、実際の価値の提供を遅らせる。
現在のニーズに集中する:
現在の問題に焦点を当てる。完成しない複雑なモデルよりも、後でリファクタリングできるシンプルで動作するモデルを持つほうが良い。モデルは進化することを受け入れる。特定の拡張ポイントが必要な場合は、ビジネス上の必要性が生じたときだけ追加する。
境界付きコンテキストを無視する 🌍
大規模なエンタープライズシステムでは、ドメインはめったに単一で統一された概念ではない。複数のサブドメインで構成される。新米の建築家は、企業全体を一つの巨大なオブジェクトグラフとしてモデル化しようとするかもしれない。これは、同じ用語がビジネスの異なる部分で異なる意味を持つ可能性があるという境界付きコンテキストの概念を無視している。
たとえば、用語「製品」は営業コンテキストでは価格や在庫状況を含むが、在庫コンテキストではSKUや倉庫の位置に焦点を当てる。これらを一つのモデルに統合すると、関係のないデータと混乱した論理を持つ肥大化したエンティティが生まれる。
- コンテキストの境界:異なるモデルが特定のデータを所有する明確な境界を定義する。
- コンテキストマッピング:これらのモデルがどのように通信するかを確立する。特定の実装詳細が一方のコンテキストから他方を汚染するのを防ぐために、アンチ腐敗レイヤーを使用する。
- 共有カーネル:統合が必要な場合、モデルの共有サブセットに合意するが、それ以外の部分は隔離したままにする。
データ中心の思考 vs. オブジェクト中心の思考 💾
建築家がデータベーススキーマから始め、それを基にドメインモデルを構築するのはよくあることだ。これはドメイン駆動設計の自然な流れを逆転させている。データベースは永続化に関する問題であり、ドメインモデルはビジネスに関する問題である。
データベースをモデルにした場合:
- 実装の詳細(外部キー、null制約など)をビジネスロジックに導入してしまう。
- データベーススキーマのリファクタリングは、ビジネスロジックにとって破壊的変更になる。
- ドメインを純粋なオブジェクトモデルとして扱う能力を失う。
関心の分離:
ドメインモデルをクリーンに保つ。ビジネス上の意味を持たないデータベースのカラムをプロパティとして公開しない。オブジェクトグラフとリレーショナル構造の間を変換するマッピングレイヤーを使用する。これにより、ビジネスロジックがストレージ技術から独立したままになることを保証する。
不変条件とビジネスルールを無視する ⚖️
不変条件とは、常に真でなければならない条件である。良好に設計されたドメインでは、不変条件はモデル自身によって強制される。新しく設計するアーキテクトはしばしば検証ロジックをUIやサービス層に押し込み、ドメインオブジェクトを一時的に無効な状態に置きかねない。
無視された不変条件の例:
- A
銀行口座overdraft保護が有効でない状態で、残高がマイナスになることを許可する。 - An
注文が出荷済み状態にあるが、有効な追跡番号. - A
割引が最低基準を下回る注文に適用される。
これらの検証がオブジェクトの外で行われると、オブジェクトが破損する可能性がある。メソッドが直接呼び出された場合(サービス層を迂回して)、不変条件が破られる可能性がある。モデルは自らの整合性を守らなければならない。
IDと値オブジェクトの混同 🆔
エンティティと値オブジェクトの違いを理解することは重要である。エンティティはその識別子によって定義される(たとえば特定の従業員)。一方、値オブジェクトはその属性によって定義される(たとえば住所または通貨).
よくある誤り:
値オブジェクトをエンティティとして扱うこと。もし通り住所に固有のIDを割り当てると、不要な複雑性が生じる。もし従業員を値オブジェクトとして扱うと、時間の経過とともにその履歴を追跡する能力を失う。
- エンティティ:識別子が必要。同じ名前の2人の従業員は異なる人物である。
- 値オブジェクト:識別子を持たない。同じ通り名と都市名を持つ2つの住所は同じ値である。
これらを混同すると、パフォーマンス上の問題(IDによる不要な検索)と論理的な誤り(変更不可であるべきデータを変更可能として扱う)が生じる。
停滞したモデル 🔄
ドメインモデルは一度きりの成果物ではない。ビジネスとともに進化しなければならない生きているアーティファクトである。初期設計を最終的な真実と見なしてしまうというよくある落とし穴がある。ビジネス要件が変化したとき、モデルもそれに合わせて変化すべきである。
停滞したモデルの兆候:
- 開発者は、既存の機能を壊さずに新しい機能を追加できないと感じている。
- コードのコメントが、特定の回避策が設けられている理由を説明している。
- モデルには何年も前に非推奨となった機能のロジックが含まれている。
継続的な改善:
リファクタリングを標準的な実践として推奨する。定期的にビジネス関係者とドメインモデルをレビューする。ビジネスに存在しなくなった概念は、コードから削除する。新しい概念が現れた場合は、すぐにモデル化する。変化しないモデルは、死にかけているモデルである。
一般的な落とし穴とより良い実践
以下の表は、一般的な誤りと推奨されるアーキテクチャ的アプローチの主な違いを要約している。
| 落とし穴 | 影響 | より良い実践 |
|---|---|---|
| 貧弱なドメインオブジェクト | ロジックが散らばり、保守が難しい | 挙動をカプセル化した豊かなドメインオブジェクト |
| データベース優先設計 | ストレージに強く結合される | ドメイン優先、後にストレージにマッピング |
| 単一のモノリシックモデル | 複雑性の爆発、混乱 | 明確な境界を持つバウンデッドコンテキスト |
| サービス層での検証 | 無効な状態が発生する可能性がある | ドメインエンティティ内での検証 |
| 過剰設計 | 遅延した納品、隠れたバグ | シンプルな設計、必要に応じて進化させる |
| 共通言語を無視する | 誤解、再作業 | ビジネスと技術の間での共有語彙 |
改善のための実践的ステップ 🛠️
これらの落とし穴を避けるには、マインドセットとプロセスの変化が必要です。以下は、アーキテクチャワークフローに組み込むための実行可能なステップです。
1. ドメインストーリーテリングセッションを行う
要件を単に集めるのではなく、ドメイン専門家と座ってシナリオを一緒に検討してください。取引の流れを説明してもらうようにしてください。彼らの物語をモデルにマッピングすることで、モデルが理論的な理想ではなく、実際の業務を反映していることを保証します。
2. コード所有権を強制する
ドメインモデルの特定の部分を特定の開発者またはチームに割り当てます。これにより責任が明確になります。もし注文モデルが壊れた場合、責任を持つチームはそれを修正しなければなりません。注文「誰もが何も所有しない」状態を防ぎます。
3. 静的解析を導入する
ツールを使ってアーキテクチャルルールを強制します。たとえば、サービスクラスがデータベースエンティティに直接アクセスすることを防ぎ、ドメインインターフェースを通すように強制します。これにより、関心の分離が自動的に維持されます。
4. 定期的なモデルレビュー
チームがドメインモデルをレビューする定期的なセッションをスケジュールします。長すぎるメソッド、ゴッドクラス、不整合な命名などの「臭い」を確認してください。本番コードと同様に、モデルにも厳密な検査を施すようにしましょう。
5. ドキュメントはコードとして扱う
ドキュメントをコードと同じリポジトリに保管してください。コードが変更されたら、ドキュメントも変更しなければなりません。コード構造から図を自動生成するツールを使用して、視覚的な表現が実装と一致していることを確認しましょう。
アーキテクチャの人的側面 👥
最後に、ドメインモデリングは単なる技術的作業ではなく、社会的なプロセスであることを忘れないでください。モデルの品質は、アーキテクト、開発者、ビジネス関係者との間のコミュニケーションに大きく依存します。ビジネスがモデルを理解できなければ、あるいは開発者が効率的に実装できなければ、完璧なモデルも無意味です。
協力が鍵です。設計フェーズにシニア開発者を参加させましょう。実装上の制約に関する経験があれば、実現不可能な理論的な設計を防ぐことができます。命名規則にはビジネスアナリストを参加させましょう。彼らの洞察により、モデルが組織にとって関係性を持ち続けることが保証されます。
アーキテクチャの健全性の要約 ✅
高品質なドメインモデルを構築することは、継続的な改善の旅です。スピードを優先して手を抜く誘惑に注意を払い、ビジネスルールとそれらを実行する人々への敬意を示す必要があります。本ガイドで示された落とし穴——たとえば貧弱なモデル、言語の断絶、データ中心の結合——を避けることで、堅牢で適応性のあるシステムの基盤を築くことができます。
明確性、カプセル化、整合性に注力してください。モデルはビジネスを支援するものであり、逆ではないようにしましょう。ドメインモデルが企業の現実を正確に反映しているとき、コードは書くのが簡単になり、テストしやすくなり、理解しやすくなります。これがアーキテクチャの成功の真の基準です。
繰り返し改善し、常に耳を傾け、継続的に精練してください。最高のモデルは1日で作られるものではなく、フィードバックによって育てられ、一貫した実践によって強化されていくものです。











