DDDの読書記録(第4章、ドメインを隔離する)

DDDのモデル駆動設計では、在庫管理、注文管理といったドメインから生じる問題を解決するのに特化した部分に焦点を当てます。そして、ドメインの問題を他の問題から明確に切り離すことを設計上の至上命令としています。

これは夜空に星座を見つけ出そうとするようなものだ。ドメインオブジェクトはシステムの他の機能から切り離す必要がある。そうすることで、ドメインの概念を、ソフトウェアの技術にしか関係しない概念と混同したり、システム全体の中に紛れ込んでドメインを見失ってしまったりすることを避けられるようになる。

夜空に星座を見つけ出すというのも印象的な表現ですが、プラネタリウムで一見バラバラに並んでいる星の中からサソリや白鳥の形が線や星座絵によって浮き上がってくるように、ドメインモデルを探し出してはっきりとチーム全体でイメージを共有できるようにするということが重要だと思います。この章ではそのための前提となるレイヤ化アーキテクチャパターンについて説明されています。

レイヤ化アーキテクチャ(LAYERED ARCHITECTURE、P66)

大規模なシステムやアプリケーションを設計する時にレイヤーに分割しましょうというのは、今ではもはや常識的なことです。本によってレイヤーの分割の仕方は多少異なりますが、本質的にはだいたい同じですね。ただし、以前のJ2EEアーキテクチャでは、論理的なレイヤーと物理的な層(ティアー)を混同しそうな記述も時々見られるため注意が必要だと思います。DDDで言っているところのレイヤーとはあくまでも論理的なソフトウェアのレイヤーのことを示しているのであって、クライアントPC、アプリサーバー、DBサーバーの3階層のシステムといったような場合のティアーとは別の概念です。(もちろん、レイヤーとティアーの境界がある程度一致していることもありますが。)
ただし、P66の最初に出てくるレイヤーの図をよく観察すると、通常のレイヤー化アーキテクチャと比較して以下の点に気づきます。

  • ドメイン層は直上のアプリ層だけからでなくユーザインタフェース層からも依存されている。
  • インフラ層はアプリ層やインフラ層から利用されるだけでなく、ドメイン層やプレゼン層のベース(親)にもなっている。
  • イベントメッセージにより下位レイヤーから上位レイヤーへのイベントメッセージ通知による依存がある。(頭が半分の矢印で示される)

さすがに、エヴァンス氏は実践的モデラーなだけあって、重要な詳細に関するポイントを押さえているなと関心させられます。通常のアプリケーションだと特定のレイヤーが直下のレイヤーのみに依存するといった厳密なレイヤー構造にはなりませんので。このあたりの感覚はパワポVisio専門のアーキテクトではなかなか理解できないところでしょうね。
とにかく、DDDでは標準的なレイヤーとして以下の4種類のレイヤーを定義しています。ここでは私のこれまでのJava EEでの開発経験もふまえて、本の内容より少し具体的にまとめてみます。

レイヤー名 主な役割 通常のJava EEでの例
ユーザインタフェース
(プレゼンテーション層)
情報の表示
情報の入力
Webサービス公開
MVC フレームワーク
JSPサーブレットJavaScript
RIA、HTML、CSS
SOAP、REST
アプリケーション層 ドメイン層の呼び出し
トランザクション境界
他システム呼び出し
ワークフロー管理
セッション管理
セッションEJBPOJOサービスbean、DTO
ドメイン ビジネスソフトウェアの核心
ビジネスルール
エンティティ、値オブジェクト、列挙などのPOJO
ファクトリー、集約、レポジトリー、ドメインサービス
JPAなどのアノテーションを含む場合もある)
インフラストラクチャ層 上位レイヤを支えるサービス
画面部品、アスペクト
共通ベースクラスなど
DIコンテナ、O/Rマッパー、
メッセージGW、WebサービスGW、画面ツールキットなど

それで、以上の表を見てもわかりますが、ドメイン層はEJBサーブレットなどの特定のフレームワークに依存しないPOJOクラス*1としてできる限り自由に設計できるようにすることが大切なポイントです。もちろん、実際のレイヤー分けはSeamを使う場合とSpringを使う場合では当然異なりますし、アプリケーションの要件によっても最適な構成は異なるのが当然ですが、とにかくDDD的なモデル駆動開発に絶対に欠かせない必要条件はドメイン層のコードを他のレイヤーからはっきりと分離すべきという点にあります。そのような分離をして初めて、モデル駆動開発が可能になるからです。それゆえ、

複雑なプログラムはレイヤに分割すること。各レイヤで設計を進め、凝集度を高めて下位層だけに依存するようにすること。標準的なアーキテクチャパターンに従って、上位のレイヤに対しては疎結合にすること。ドメインモデルに関係するコード全部を1つの層に集中させ、ユーザインタフェース、アプリケーション、インフラストラクチャのコードから分離すること。表示や格納、アプリケーションタスク管理などの責務から解放されることで、ドメインオブジェクトはドメインモデルを表現するという責務に専念できる。これによって、モデルは十分豊かで明確になるように進化し、本質的なビジネスの知識をとらえて、それを機能させることができるようになる。

というレイヤ化アーキテクチャがDDDの前提として重要となります。
なお、DDDでアプリケーションを作成するサンプルとしては、以下が参考となります。
DDD Sample Application - Introduction

アーキテクチャフレームワーク(P72)

多くの場合、永続化やセキュリティなどインフラストラクチャレイヤの機能は明示的なサービス呼び出しの形で上位から呼び出されることが普通です。その他の例として、ドメイン層のクラスが継承すべき共通のベースクラスを提供するなどの手段で共通ロジックを提供する場合もあります。しかし、いずれにしてもドメイン層とインフラ層はお互いに結合度を下げるべきであり、できることならドメイン層がインフラ層を意識しない透過的な方式をとることが望ましいと思います。実際、エヴァンス氏も以下のように説明しています。

最もよくできたアーキテクチャフレームワークは、複雑な技術的問題を解決する一方で、ドメイン開発者がモデルを表現できることに集中できるようにする。しかし、フレームワークは、ドメインについての設計の選択肢を制限する前提を多く設け過ぎたり、開発の速度を低下させるほど実装を重苦しくしてしまったりすることで、容易に開発の妨げとなり得るのだ。

これは、私が以前に書いた以下のエントリにも関連している議論ですね。
日本と欧米ではPOJOの意義に対して微妙な解釈の違いがあるような気がする - 達人プログラマーを目指して
実は、ドメイン層を隔離してできるかぎりインフラ層を透過的に意識させないようにするという工夫はDDDの原書が出版されてからの8年間の間に目覚ましい進歩を遂げている領域であると私は感じています。当時はStruts1やEJB2.1といった侵略的なフレームワークが一般的な時代でしたが、現在ではAOP、DI、O/Rマッピングの普及により、DDDの理想とするアーキテクチャフレームワークOSSJavaEEなどの標準として利用できるようになりつつあります。

利口なUIアンチパターン(SMART UI "ANTI-PATTERN"、P74)

残念ながら、今のところ日本のSI業界は前節で説明したパラダイムシフトに完全に乗り遅れてしまっています。海外ではドメイン層でドメインモデルを構築するという方法が広まってきているのに、依然としてオブジェクト指向でない設計(利口なUIアンチパターントランザクションスクリプト)を上から強制するようなフレームワークを使った開発が一般的に行われています。
Java EEや.NETはCOBOLやVB6よりも本当に生産性が高いか? - 達人プログラマーを目指して
侵略的なフレームワーク - 達人プログラマーを目指して
実は、このアンチパターンはごく小規模な例外的なケースをのぞけば、日本のほとんどのSI開発案件で採用されているデファクトスタンダードのパターンとなっています。実際、このアンチパターンを採用すると

  • 機能が簡単なアプリケーションは設計が形式化されており単純なため生産性が上がる
  • それほど有能でない開発者でもそれなりの仕事ができる

などの短期的なメリットが得られる一方で、

  • コピペにより機能追加は簡単だが部分的な機能変更に弱い
  • 大幅な機能拡張が困難なことが多いため、全体的な作り直しになる

などのデメリットがあります。しかし、これらのデメリットは困ったことにSIerモデルだと必ずしもデメリットにならないというところもあるのですよね。
しかし、頭数要員だけでこなせる仕事が今後もずっと取れると考えているSIerの仮説は間違っている - 達人プログラマーを目指してでも指摘したように、そもそも頭を使わずに単純作業で作成できるようなアプリケーションはSalesforceクラウドなどで自動的に作成できるようになりつつありますし、いつまでも非生産的な方式で開発していたらインドなどのオフショアに仕事を持っていかれることは目に見えて明らかです。
それゆえ、今後は、DDDによるモデリングが必要となるような戦略的な領域の開発がもっと注目されるようにならないといけないと思います。もちろん、ドメイン層を隔離し、モデル駆動で、オブジェクト指向的なメリットを生かした設計を行うためには、現状様々な障壁があることは確かですが、アジャイル開発プロセスなどの段階的な採用などにより、今後DDDで成功するプロジェクトが登場することを願っていますし、私もそのようなプロジェクトでドメインモデルを作成するような仕事に挑戦してみたいと強く希望します。

*1:純粋主義者の人はJPAアノテーションをエンティティにつけることはドメイン層の分離に反すると考える人もいますが、実用的にはJPAアノテーションドメイン層の記述を強化するDSLの一種と考えることもできると思います。