ドメインモデル中心のアーキテクチャ

2016.11.09

  • オリジナル記事

Edit by
増田 亨

ギルドワークスの増田です。

河上さんが書いていたヘキサゴナルアーキテクチャに関連して、ドメインモデル中心のアーキテクチャについて考えてみます。

「ドメイン駆動設計」本のアーキテクチャへの疑問

私の設計の考え方は、6年ほど前に出会ったエリック・エバンスの「ドメイン駆動設計」が基本になっています。しかしドメイン駆動設計を実践するためのアーキテクチャについては、エバンスが「ドメイン駆動設計」本の中で描いているアーキテクチャの図が、どうもしっくりきませんでした。 4章のレイヤ化アーキテクチャの説明そのものは、すっきりしています。

プレゼンテーション層
ユーザ向けの情報の表示。ユーザからのコマンドを受け取って解釈。
アプリケーション層
ソフトウェアが行うべき仕事を定義。実際の処理はドメイン層に委譲する。
ドメイン層(モデル層)
ビジネスの概念、ルールの記述。業務アプリケーションの核心。
インフラストラクチャ層
上位のレイヤを支える技術的な機能を提供する


しかし本に掲載されたアーキテクチャ図をみると、ドメイン層がアプリケーションの中心であるようには見えません。そこに違和感がありました。

ドメインモデルを中核にしたアーキテクチャ

ドメインモデルを中心にしたアーキテクチャの私のイメージはこんな感じです。 アーキテクチャ

私のオリジナルではなく以下のアーキテクチャを参考にしたものです。

共通しているのは、「内側」にアプリケーションやビジネスロジックがあって、「外側」に外部とのインタフェースがある、という捉え方です。 ユーザインタフェースも、データベースも、通信インタフェースも、外部とのインタフェースという意味で同じ性格の構成要素と考えます。

マーチン・ファウラーは「エンタープライズ・アプリケーション・アーキテクチャパターン」のなかで、コバーンのヘキサゴナルアーキテクチャにも触れています。ファウラーは「UIとデータベースとは、性格が異なるので、別のレイヤ要素として考えたがほうが良い」と述べています。

二人のアーキテクチャ観は、相反してはいません。

まず、アプリケーションの中核は、ビジネスの概念やルールを記述する、という考え方は、まったく同じです。 外部とのインタフェースを、その責務や構造から考えた時に、ユーザインタフェース層とデータアクセス層は、異なる要素である、という点も同じです。 コバーンの図でも、データベースとUIは、別の方角に配置しています。つまり同じ外部インタフェースだが、別の性格であることも意識しているわけです。

私自身は、図で示したように、全体のアーキテクチャを大きく3つに分けて考えています。

ドメインモデル(中核)
ビジネスルールの表現。ビジネスデータを元に、判断・加工・計算をするロジックを記述。
ユースケース層
業務手順を記述(できるだけ簡潔に)
外部インタフェース(外殻)
外部との接続インタフェース。イベントに反応して必要な処理を呼び出す「コントローラ」、処理の結果を表現する「プレゼンター」、外部システムとの連携を行う「ゲートウェイ」で構成する。


大きな関心事として「ドメインモデル」「ユースケース」「外部インタフェース」の三つに分けるという設計です。

技術の関心事:外部インタフェース

外部インタフェースは純粋に「技術」の関心事です。

技術の関心事は、どのような業務アプリケーションでも、ほぼ共通します。広く受け入れられている、定番的な解決方法が多いのが外部インタフェースの領域です。 外部インタフェースは、最近ではオープンソースのフレームワークやライブラリを使うことがあたりまえになっています。 対象分野固有の業務の関心事やビジネスルールを分離してしまえば、「外部インタフェース」は、純粋な技術的な世界です。そして、フレームワークなどで、汎用的な解決手段が提供されている領域です。

一般的な業務アプリケーションでは、それほど難しい設計は要求されない部分です。

※外部インタフェースにも、もちろん、難しい設計課題はあります。大量のデータを効率的に扱う/同時の多数のアクセスをさばく/サービス停止を防ぐ/障害発生時もデータを完全に保護する、などです。

業務の関心事

一方、外部インタフェースから分離したユースケースドメインモデルは、そのアプリケーションに固有の課題です。そして、業務アプリケーションを複雑にし、設計を難しくする根本原因です。

業務アプリケーションが複雑になるのは、次のようなビジネス要求が絡み合うからです。

  • 商品の「種別」や、顧客の「区分」による場合分け
  • 残高、在庫状況、承認の済・未済など「状態」に応じた場合分け
  • 役割や権限に応じた「見える・見えない」「できる・できない」の場合分け
  • 未来の予定(予算)と実績との差異チェックとそれに基づくアラート
  • ...

こういうさまざまな視点の場合分けと関連する判断や計算のルールを、多元的に組み合わせたものがビジネスルールです。 そして、それらの場合分けとビジネスルールは、ビジネスの成長やビジネス環境の変化に合わせて、常に、変更が繰り返されます。 業務アプリケーションが複雑になるのは、こういう現実のビジネス世界の構造的な複雑さと、ビジネスは常に変化し続けるという流動性に起因する、必然なわけです。

ユースケースとドメインモデルの分離

複雑な業務ニーズを、やみくもにコードに落としても、プログラムが不要に複雑になり変更がたいへんになるばかりです。 そうならないために、業務の関心事を整理して、見通しの良いプログラムを記述する「工夫」が必要です。 その工夫のひとつがユースケースとドメインモデルの分離です。

もし、ユースケースの種類が少なく、また「区分」や「状態」の場合分けも単純であれば、ユースケース単位にプログラミングするのがてっとりばやい。ユースケースの業務手順の記述の中に、ビジネスルールの判断ロジックや計算ロジックを埋め込む書き方です。 これが「トランザクション・スクリプト」という設計スタイルです。

ユースケース単位でビジネスルールを記述する「トランザクションスクリプト」は、複数のユースケースに、同じビジネスルールを重複して記述することになりがちです。

たとえば「注文を登録する」「注文を変更する」「注文をキャンセルする」という3つのユースケースを考えてみましょう。この3つのユースケースは「注文」という共通の関心事についての異なるアクションです。「トランザクションスクリプト」では、「注文」に関するビジネスルール、判断・加工・計算のロジックは、3つのユースケースで重複して記述されます。

「ドメインモデル」は、この「注文」ような、複数のユースケースに共通する関心事を一か所に集約して、ビジネスルール、判断・加工・計算のロジックを整理する工夫です。「ドメインモデル」は、一つのビジネスルールをプログラムのあちこちに重複して記述することを防ぎます。重複した記述がなくなり、1箇所だけでビジネスルールを記述すれば、プログラムの変更は容易で安全になります。

ドメインモデルの設計と実装のスタイル

「ドメインモデル」は、業務の本質的な複雑さをそのまま反映しています。また、たえず、変更ニーズが発生することに備えることも、「ドメインモデル」の設計の重要な課題です。この設計課題を解決する工夫として、さまざまなアプローチのプログラミングのスタイルが提案され、実践されてきました。

手続き型プログラミングであれば、さまざまなビジネスルールを「共通サブルーチン」として実装します。 オブジェクト指向スタイルの設計であれば、関連するデータとロジックをクラスやパッケージに集約して、ビジネスロジックの整理を図ります。 Prologやルールエンジンのような論理型のパラダイムであれば、ドメインモデルは「ルール」と「事実」の集合とその演算として表現するでしょう。 関数型のパラダイムであれば、ビジネスルールは「関数」のネットワークとして表現することになりそうです。

どのようなスタイルで設計するとしても、大切なことは「ドメインモデル」を、アプリケーションの全体の中で、独立性の高い中核部品として分離することです。独立性が高い、という意味は、ユースケースや外部インタフェースの構造や都合に影響されないようにする、という意味です。 アプリケーションの中核に「ドメインモデル」を配置し、「ユースケース」はドメインモデルに依存し、「外部インタフェース」は、ユースケースとドメインモデルに依存する構造にします。こういう構造にする動機は次の2点です。

  • 業務の関心事と技術の関心事を分離して全体の見通しをよくする
  • 個々の業務を表現するユースケースから、業務をまたがって共通するビジネスロジックを「ドメインモデル」に集約して、複数のユースケースでひとつののビジネスロジックを重複して記述することを防ぐ

結果として、どこに何が書いてあるかわかりやすく、変更すべき箇所の特定が容易で、変更の影響範囲を構造的に限定できる、あつかいやすいソフトウェアになります。

※注意:この記事は2015年7月10日にGuildWorks Blogで公開したエントリをリライトしたものです。