クリーンアーキテクチャーとDDDのメリット・デメリット|選定理由と導入判断

スポンサーリンク
スポンサーリンク

クリーンアーキテクチャーは依存関係を整理する設計方針、DDD(ドメイン駆動設計)は業務知識をモデルへ反映する設計アプローチです。両者は併用できますが、必ずセットで導入する必要はありません。

業務ルールが複雑で、継続的に仕様が変わるシステムでは効果を期待できます。一方、単純なCRUDや短期間で役目を終えるツールでは、抽象化と学習のコストが上回る場合があります。選ぶ基準は「流行しているか」よりも、「どの変更や認識のずれに困っているか」です。

この記事ではWeb・ECシステムを例に、メリット・デメリット、採用する理由と見送る理由、段階的な導入方法を整理します。以下の例は設計判断を説明するための仮想例であり、特定案件の実績ではありません。

スポンサーリンク

クリーンアーキテクチャーとDDDの違い

DDDは業務をモデル化し、クリーンアーキテクチャーは依存を内側へ向ける役割の図
図1:DDDとクリーンアーキテクチャーの役割。矢印は呼び出し順ではなく、ソースコードの依存方向(本記事作成)。
比較項目 クリーンアーキテクチャー DDD
主な関心 業務の方針を、画面・DB・外部サービスの都合から守る 業務の意味・ルール・境界をモデルに表す
中心となる考え方 ソースコードの依存を内側の方針へ向ける ユビキタス言語、境界づけられたコンテキスト、モデルの継続的な改善
主なメリット 変更範囲の整理、業務ロジックのテストのしやすさ 業務認識の共有、ルールの一貫性、責任範囲の明確化
主なデメリット 境界・変換処理の増加、追跡や設計の負担 業務理解と対話の時間、モデルを見直す負担
導入の判断材料 技術的な変更が業務ロジックに波及しているか 業務の複雑さや用語の食い違いが問題になっているか

クリーンアーキテクチャーとは

業務の中心となるルールと、それを実現するユースケースを、フレームワークやDBなどの詳細から分離する考え方です。重要なのはフォルダ名や層の数ではなく、内側のコードが外側の具体的な実装へ依存しないことです。

たとえば注文処理が必要とする保存の契約を内側で定義し、外側にDB用の実装を置きます。実行時には注文処理が保存処理を呼び出しても、ソースコードの依存は外側から内側へ向けられます。処理の呼び出し順と依存の向きは区別しましょう。基本原則はRobert C. MartinのThe Clean Architectureを参照できます。

DDD(ドメイン駆動設計)とは

業務に詳しい人と開発者が対話し、共通の言葉で業務を理解し、その理解を設計・コードへ反映し続けるアプローチです。「注文」「売上確定」などの意味を曖昧にしたまま実装しないことが出発点です。

戦略的設計では業務の境界やモデル間の関係を整理します。戦術的設計ではエンティティ、値オブジェクト、集約などを使ってルールを表現します。リポジトリやクラスを増やすだけではDDDにはなりません。用語とパターンの一次資料として、Eric EvansのDDD Referenceがあります。

クリーンアーキテクチャーのメリット

1. 変更の影響を境界で整理できる

外部の配送APIのレスポンスが変わっても、その形式を変換する処理を境界に集めておけば、注文成立の条件まで書き換える事態を避けやすくなります。ただし、注文時に必要な業務条件そのものが変われば、内側の修正も必要です。

2. 業務ロジックを小さくテストしやすい

保存先や外部APIを差し替えられる構造なら、実際の通信をせずに注文確定の条件を検証できます。失敗時の分岐も再現しやすくなります。一方、SQL・ORMの振る舞いやトランザクションは、実DBを使う結合テストで別に確認します。

3. ユースケースの責任が見えやすい

コントローラーに入力検証、価格計算、保存、通知が混在している場合、注文確定などの処理単位へ責任を整理できます。画面からもバッチからも同じ業務処理を使うときに、ルールの重複を減らしやすくなります。

クリーンアーキテクチャーのデメリット

  • 初期実装が増える:インターフェース、入出力の型、データ変換などを設計する時間が必要です。
  • コードを追う距離が長くなる:小さな機能でも複数の層を移動するため、規約に慣れるまで調査に時間がかかります。
  • 抽象化を維持する負担がある:全クラスに機械的にインターフェースを作ると、変更箇所だけが増えることがあります。
  • フレームワークの利点との調整が必要:ORMのモデルと業務モデルを分ける場合、マッピングや永続化の設計が追加されます。

「いつかDBを交換するかもしれない」だけを理由に全面導入すると、使わない柔軟性へ投資することになります。現在起きている変更の波及やテストの困難さから境界を決める方が説明しやすいでしょう。

DDDのメリット

1. 業務担当者と開発者の認識を合わせやすい

ECの「注文済み」が、受付完了なのか、入金確認済みなのか、出荷可能なのかで実装は変わります。会話、仕様書、コードで同じ言葉を使うことで、認識のずれを発見しやすくなります。

2. 業務ルールをまとまりとして守りやすい

「出荷済みの注文は通常キャンセルできない」というルールを、複数画面の条件分岐へ散らすと修正漏れが起きます。注文の状態変更を担当するモデルへルールを集めれば、不正な状態遷移を防ぎやすくなります。

3. 異なる業務のモデルを分けて考えられる

販売部門にとっての「商品」と、物流部門にとっての「商品」は必要な情報が異なります。境界づけられたコンテキストを使うと、一つの巨大な商品モデルへすべてを詰め込まずに済みます。境界はまず概念やコード上で整理でき、直ちにマイクロサービスへ分割する必要はありません。

DDDのデメリット

  • 業務理解に時間がかかる:用語、例外、制約を確認する対話が必要です。開発者だけで正しいモデルを決めるのは困難です。
  • モデルは作って終わりではない:業務への理解や制度が変われば、境界や集約も見直します。
  • パターンの誤用が複雑さを増やす:DBテーブルをそのまま集約と見なしたり、巨大な集約へ多くの責任を集めたりすると、性能や更新競合の問題を招きます。
  • 単純なデータ管理には重くなりやすい:登録・一覧・更新・削除が中心の機能では、複雑なモデルより既存の仕組みを使う方が保守しやすい場合があります。

導入のリアル:すべてに「フルセット」を適用しない

クリーンアーキテクチャーやDDDを、システム全体へ同じ厚みで適用する必要はありません。単純なCRUD(登録・参照・更新・削除)にも多数の層・インターフェース・変換処理を一律に設けると、ファイル数や調査の負担が増え、得られる効果に見合わないオーバーエンジニアリングになる場合があります。

ただし、ファイル数が多いこと自体が失敗の基準ではありません。追加した構造によって業務ルールや責任が明確になり、変更しやすくなるなら価値があります。「フルセットにすること」より、解決したい問題に対して構造が適切かを判断します。

業務のまとまりごとに設計の厚みを変える

単純なデータ管理は標準構成を基本とし、複雑な業務ではDDDと必要な依存分離を検討する使い分けの図
図2:同一システム内でも、業務の複雑さに応じて設計を使い分ける(本記事作成)。
  • お知らせ・ブログなど、ルールが単純な機能:フレームワーク標準のMVCなどを基本とし、開発と保守の分かりやすさを優先します。
  • 在庫引当・返金条件・複雑な料金計算:DDDでルールと境界を整理し、外部APIやDBからの分離が必要ならクリーンアーキテクチャーの考え方も取り入れます。

機能名だけでは決まりません。ブログでも複雑な承認・権限制御があればモデル化を検討でき、決済でも外部サービスへの単純な橋渡しなら連携の境界を整理するだけで十分な場合があります。「MVCかDDDか」という二者択一でもありません。MVCを画面側の構成に使いながら、その奥にユースケースやドメインモデルを置くこともできます。

また、一つの画面機能と、一つのドメインや境界づけられたコンテキストは同義ではありません。データの整合性、用語、責任のまとまりを見て境界を決めます。共通ルールとして、責任範囲、依存方向、連携方法、トランザクション境界、テスト方針を設計記録に残し、同じルールが複数箇所へ重複しないようにします。

MicrosoftのDDDを用いた設計ガイドでも、複雑な業務と単純なCRUDで異なる設計を使う考え方が示されています。同資料はマイクロサービスの文脈ですが、本記事では、複雑さに応じて設計を選ぶという判断をモノリス内の業務のまとまりにも応用しています。

なぜ企業は初期工数が増えても導入を検討するのか?

導入には業務理解、設計、学習、テストの工数がかかります。それでも長期運用するシステムで検討されるのは、初期開発だけでなく、将来の変更・引き継ぎまで含めた負担を抑えたいためです。以下は設計から期待できる価値を整理したものであり、すべての企業の採用理由や、コスト削減の実績を示すものではありません。

初期の業務理解・設計・テストの負担と、将来に期待する変更範囲の限定・技術の分離・引き継ぎの価値を比較した図
図3:初期コストと将来の価値を比較する。効果は導入後の変更で検証する(本記事作成)。

1. 長期的な保守・改修の負担を抑える

業務ルールの置き場所と責任範囲を明確にすると、仕様追加時に修正先を探しやすくなり、修正漏れを減らす助けになります。ただし、導入するだけで技術的負債を防げるわけではありません。不要な抽象化や形骸化した規約も負債になります。次の仕様変更で、調査時間、変更箇所、回帰不具合、レビュー負担を振り返ります。

2. フレームワークやDB変更の影響を限定する

技術の詳細を境界の外側へ分離すると、バージョンアップや外部APIの仕様変更が業務ルールへ直接波及しにくくなります。ただし「ビジネスロジックを一切変更せずに済む」という保証ではありません。DBの制約、トランザクション、性能、永続化の方法によってモデルの見直しが必要な場合もあり、移行と結合テストは別途必要です。

3. 長期運用とメンバー交代に備える

業務の言葉やルールをコードとテストで表現し、設計判断の理由も記録しておけば、引き継ぎ時の理解を助けられます。一方、コードだけですべての背景は伝わりません。ドキュメント、レビュー、業務担当者との対話を継続し、設計を維持できるチームの習熟度も選定条件にします。

長期運用を重視する企業に説明したいのは、数年先の運用・拡張を支えるために、どこへ設計コストをかけるかという判断です。導入・維持コストと、変更しやすさのトレードオフを説明できることが、設計の選定理由になります。

選定理由:採用する場合・見送る場合

次の表は本記事で提案する判断の目安です。人数や開発期間だけで一律に決めず、困りごと、変更頻度、チームが維持できる設計かを確認します。

状況 選択の目安 選定理由
割引・返金・在庫引当などの例外が多いEC DDDを軸に、重要なユースケースでクリーンアーキテクチャーを併用 業務ルールの整理と、外部連携からの分離の両方が必要
業務は単純だが、複数の外部APIと連携する 外部連携の境界を優先して整理 詳細なドメインモデルより、依存と変換の管理が主な課題
複数部門で同じ用語の意味が異なる DDDの戦略的設計から着手 実装の層分けより先に、業務の境界と用語の合意が必要
単純な管理画面・短期の検証用ツール フレームワーク標準の構成を基本にする 初期コストと開発速度を重視し、複雑化した部分で分離を検討
既存システムの全面改修は難しい 変更の多い一機能から段階導入 移行中の不具合や運用への影響を限定しやすい

選定理由を設計記録へ残す例

課題:キャンセル条件が画面・バッチごとに重複し、条件追加時に修正漏れが起きる。
決定:注文の状態遷移をモデルへ集め、キャンセルのユースケースから実行する。配送APIの形式は外側で変換する。
代替案:既存のサービスクラスへ集約する案も検討したが、状態変更の入口を統一する必要があるためモデル化を選ぶ。
受け入れる負担:永続化との変換処理と、チーム内での用語整理が増える。
再評価:次の仕様変更で修正範囲、調査時間、修正漏れを振り返る。

このように「何を解決するか」「何を選ばなかったか」「どの負担を受け入れるか」を書くと、後から判断を見直せます。

ECの注文キャンセルを例に、役割を分ける

仮に「出荷前の注文だけキャンセル可能。キャンセル後は在庫を戻し、決済の取り消しを依頼する」という仕様を考えます。

  1. DDDで業務を整理する:出荷前の定義、部分出荷、取り消し失敗時の扱いを業務担当者と確認します。注文・在庫・決済で、どこまで同時に整合性を守るかを検討します。
  2. モデルでルールを表す:注文のキャンセル可否と状態遷移を注文モデルへ置きます。在庫や決済のすべての判断を注文モデルへ詰め込みません。
  3. ユースケースで処理を調整する:注文を取得し、キャンセルを要求し、保存や後続処理を調整します。
  4. 外側で技術の詳細を扱う:DBへの保存、決済APIとの通信、通知の送信を具体的に実装します。

層を分けるだけでは、注文と決済を同時に成功させられるわけではありません。外部APIを含む処理では、再試行、二重実行の防止、失敗時の補償や手動対応も設計します。DB内のトランザクション境界と、外部サービスをまたぐ整合性は別の論点です。

導入で失敗しないための進め方

  1. 困っている変更を一つ選ぶ:割引条件の追加など、修正漏れや調査負担が実際にある機能を選びます。
  2. 用語と具体例をそろえる:正常系に加え、境界値や例外を業務担当者と確認します。
  3. 既存の振る舞いをテストで押さえる:現在の仕様を確認してから、業務ルールと外部依存を分離します。
  4. 必要な境界だけを作る:全機能に同じ層数やリポジトリを強制せず、複雑さに応じて構成を選びます。
  5. 次の変更で効果を確認する:修正箇所、テストのしやすさ、不具合、レビューの負担を導入前と比較します。

LaravelやEC-CUBEなどの既存システムでも、全面的に作り直すことが前提ではありません。標準の拡張方法を尊重しながら、業務ルールが集中する部分から適用範囲を決めましょう。

よくある質問

クリーンアーキテクチャーとDDDは必ずセットですか?

必須ではありません。依存関係だけを整理したい場合はクリーンアーキテクチャーの考え方を部分適用でき、業務の用語や境界を整理したい場合はDDDの戦略的設計から始められます。

小規模開発や一人開発でも導入できますか?

できます。ただし、規模の小ささより業務ルールの複雑さと継続的な変更の有無が判断材料です。一人でも複雑な課金処理には有効な場合があり、単純なCRUDでは標準構成で十分な場合があります。

DDDを採用するとマイクロサービスになりますか?

必ずしもなりません。境界づけられたコンテキストはモデルの適用範囲であり、デプロイ単位と常に一対一になるものではありません。モノリス内で境界を整理する選択もできます。

導入すると開発速度や性能は必ず上がりますか?

保証されません。初期は設計・学習・変換処理の負担が増えます。継続的な変更への対応を評価し、性能はクエリ、通信、ロックなどを計測して判断します。

まとめ:業務の複雑さと変更の痛みから選ぶ

クリーンアーキテクチャーは依存の整理、DDDは業務理解とモデル化に強みがあります。導入の目的、受け入れるコスト、効果の確かめ方を明確にし、変更の多い一機能から試すのが現実的です。

背景や依存関係逆転のコード例は、関連記事「DDD・クリーンアーキテクチャーが求められる理由と実践例」も参考にしてください。

参考資料

タイトルとURLをコピーしました