ネクストデザイン有限会社  |  English  

ドメイン駆動設計 ドメインモデルからアプリケーションを自動生成する

更新日:

本記事では、まずドメイン駆動設計の考え方を整理し、次に、ドメイン駆動設計の実践例を紹介します。

例では、ドメインモデルからアプリケーションを自動生成するツールを活用した、ドメインモデル駆動型の開発例を紹介します。

[自動生成ツールの詳細はこちら]

ドメイン駆動設計の考え方

ドメイン駆動設計とは

ドメイン駆動設計は、 Eric Evans氏の著書「エリック・エヴァンスのドメイン駆動設計」で示されたソフトウェアの設計手法です。

原著は2003年、日本語版は2011年に出版されました。(本記事では、日本語版を DDD本と略記します)

※ドメイン駆動設計 Domain-driven design, DDD

※「エリック・エヴァンスのドメイン駆動設計」: 翔泳社 (ISBN 9784798121963)


DDD本は500ページ超の分厚い本です。

読者の関心事や経験などによっても、その捉え方は変わってきます。


ドメイン駆動設計は、他の開発方法論のように、"何か新しい特別な手法" を示しているわけではありません。

その代わりに、 オブジェクト指向モデル駆動アジャイル手法 といった、(すでに多くの実績やノウハウが蓄積されている) 既存の手法を活用します。

ドメイン駆動設計とは「ドメイン中心」を強調したオブジェクト指向設計であり、モデル駆動の考え方とアジャイル手法を協調させた手法だと言えます。


また、ドメイン駆動設計は「デザインパターン」や「アナリシスパターン」と同様に有用なパターン集です。

ただ、DDD本に書かれているパターンを多く取り入れることが、優れたドメイン駆動設計とは限りません。

パターンや指針に振り回されて、難しく考え過ぎたり、議論をし過ぎたりしないで、実践を重ねる中で、徐々に理解し取り入れていく方が良いと思います。

※「デザインパターン」 エリック・ガンマ、ラルフ・ジョンソン、リチャード・ヘルム、ジョン・ブリシディース著

※「アナリシスパターン」 マーチン・ファウラー著


ドメイン駆動設計に関しては、DDD本以外にも多くの情報があります。

ここでは、その中から、「Domain-Driven Design Quickly」を挙げておきます。

この文献は、Abel Avram氏とFloyd Marinescu氏の共著で、徳武 聡氏によって翻訳されたものです。

A4サイズで90ページ程で、よくまとまっていて、日本語も分かり易く、お薦めします。

学ぶ理由

アプリケーション開発において、ドメイン駆動設計を使えば必ず成功し、使わなければ失敗するということではありません。

ただ、失敗とまではいかなくても、100点満点で80点のシステムもあれば、40点のシステムも存在します。

点数の物差しは様々ありますが、より高い点数のシステムを作るためにはスキルアップが必要です。

自分流や社内流だけではなく、他の優れた手法も学ぶべきです。


すでにオブジェクト指向やモデル駆動を実践してきた方にとって、ドメイン駆動設計は、次に進むべき方向を示してくれる心強いガイドです。

「なぜドメイン駆動設計を学ぶのか?」という疑問は、あまり感じないかもしれません。

むしろ、DDD本に書かれていることの多くは、すでに実践中かもしれません。


しかし、これまで、オブジェクト指向やモデル駆動に馴染が無かったという方にとっては、「なぜドメイン駆動設計を学ぶのか?」が分かり難いかもしれません。

たぶん、その理由は、次に述べるようなアンチパターンのシステムが、実態として広く使われているからかもしれません。

そこで、まず、アンチパターンについて知っておくと、理解しやすいかもしれません。

アンチパターンを知る

「利口なUI」や「トランザクションスクリプト」と呼ばれるパターンがあります。

これらは、ドメイン駆動設計やオブジェクト指向では、アンチパターンの1つです。

しかし、実際には、利口なUIパターンやトランザクションスクリプトパターンで作られたシステムは、たくさん存在しています。

そのため、それがアンチパターンであるという指摘は受け入れ難いようです。(特に「オブジェクト思考」ではない技術者の場合)

※トランザクションスクリプトは、マーチン・ファウラー氏の著書「エンタープライズアプリケーションアーキテクチャパターン」に示されています。

※DDD本では、「利口なUI」 と「トランザクションスクリプト」は違うものとされていますが、どちらも同類のアンチパターンでしょう。


例として、Struts系のフレームワークを使ったWebアプリケーションを考えます。

もし、下図のような構造になっていれば、それは「利口なUI」パターンです。


下図は、「利口なUI」や「トランザクションスクリプト」で作られたアプリケーション構造の例です。

トランザクションスクリプトの例

上図の (A) や (B) では、JSPやアクションの中にSQL文が組込まれていて、そのSQL文で多くの業務ロジックを実現します。

そして、同じような、あるいは全く同じSQL文が、JSPやアクションの中に散在しています。

(C) では、Modelと称するクラスがありますが、実態は、DAOやDTOと呼ばれるような実装上の役割 (バケツリレーのバケツ) しか持っていません。

(A) (B) と同様にSQL文が重複したり散在します。

そして、ドメインの本質的な振る舞い (ビジネスロジック) は、ほぼ画面の都合に合わせたSQL文で実現されているでしょう。


オブジェクト指向の場合は、オブジェクトはそれにふさわしい名前と責務を持ちます。

そして、それらが協調することでビジネスロジックを実現します。

ふさわしい名前と適切に割り当てられた責務は、そのオブジェクトの役割を見通しやすくし、再利用と変更を容易にします。

しかし、SQLで実現されたロジックの多くには、オブジェクトの存在や役割に相当する概念は無く、いくつかのデータエンティティに跨った、画面都合の処理になっています。

そのため、目的が分かり難く、再利用も変更も難しい場合が多いです。

最初は大きな問題ではなかったとしても、すぐにソフトウェア・エントロピー (複雑度) が増大し、手に負えなくなるでしょう。


ドメイン駆動設計を始めるためには、ドメイン駆動設計的にもオブジェクト指向的にも、これらがアンチパターンであるという認識が必要です。


しかし、「利口なUI」には悩ましい利点もあります。

利口なUI の利点

※引用:ここから (DDD本の第4章 p.75)

   単純なアプリケーションの場合、生産性が高く、すぐに作れる。

   それほど有能でない開発者でも、この方法ならほとんど訓練しないで仕事ができる。

※引用:ここまで (引用元には箇条書きで他に5点示されています)


なぜ悩ましいかというと、この利点について疑問に思わない管理者や開発者が多いからです。

大量の開発者を一時的に集めて作業をするようなプロジェクトにおいては、都合の良い面もあるかもしれません。

ただし、プロジェクトの後半や仕様変更時、保守・改修といった局面で、これらが利点となっているケースは皆無に近いのではないでしょうか。

分析・設計やアーキテクチャのリファクタリング (洗練) 不足が表面化するのは、開発の初期局面ではなく後半です。

経験上、「生産性が高く、すぐに作れる」という現象は、開発の極めて初期の段階に限られます。


一般に、開発の後半で問題が生じてきても、開発者の人数不足などが原因とされることがほとんどです。

いつもの状況として、受け容れられているかのようです。

その原因が、手法やアーキテクチャの問題とされることは少ないように思われます。


ドメイン駆動設計を習得し実践していくためには、「利口なUI」の問題点を理解しておくことが必要かと思います。

「利口なUI」の欠点については、下にDDD本からの引用を示しましたが、これだけではすこし分かり難いかもしれません。

ただ、「利口なUI」に起因する問題点を実際に経験されている方は多いのではないでしょうか。

特に開発工程の後半や、保守や改修作業において、エントロピーの増大に悩まされた方は少なくないでしょう。

利口なUI の欠点

※引用:ここから (DDD本の第4章 p.75)

   アプリケーションの統合は困難で、データベースを経由させるしかない。

   ふるまいが再利用されことも、ビジネスの問題が抽象化されることもない。ビジネスルールは、適用先の操作それぞれで複製されることになる。

※引用:ここまで (引用元には箇条書きで他に2点示されています)


[目次に戻る]

ドメイン駆動設計の要点

ドメイン駆動設計を解説した情報は、書籍やネットでたんさん見つかります。

どれも同じことを言っているようですが、少しずつ違うように感じる方も少なくないでしょう。

やはり、ドメイン駆動設計を実践していく中で、自分なりの考えを作り上げていくものだと思います。

本記事では、次のように考えます。


ドメイン駆動設計の要点は、

   アプリケーションの本質はドメインである。(実装のためのフレームワークやアーキテクチャが本質ではありません)

   ドメインを抽象化したドメインモデルをアプリケーションの土台にする。

   ドメイン知識からユビキタス言語を導き出し、チーム内のコミュニケーションに使用する。

   ユビキタス言語の語彙は、ドメインモデルのクラス名やメソッド名、サービス名などと常に整合させる。

   ドメインモデル、実装コード、ユビキタス言語 の3つを常に一致させて、アプリケーションをイテレーティブに構築する。

   ドメイン駆動設計は、アプリケーションの設計・構築活動に有用なモデリングパターンやガイドラインを示す。

いきなり、DDD固有のキーワードを使いましたが、以降で説明します。


手法的には、すでに実績のある3つの手法と、そこで培われたノウハウを活用します。

   モデル駆動開発

   オブジェクト指向技術

   アジャイル開発


そして、いくつかの指針を追加します。

   「ドメインモデル貧血症」と言われるような、責務が欠落したクラスは作らない。(貧血症のクラス群をドメイン層とは呼びません)

   「分析モデル」や「設計モデル」のように、工程や担当によってモデルを分離しない。

   1つのモデルを作成し、それを継続的に洗練し、使い続ける。

   コミュニケーションや成果物の記述には、ユビキタス言語の使用を徹底する。

   ユビキタス言語、モデル、実装の間に整合性を保ち、相互に追跡可能にする。


[目次に戻る]

始め方

ドメイン駆動設計を始める時の基本方針として、次の点を推奨します。

・ドメイン駆動設計を必要以上に難解に解釈しようとしない。

・最初から多くのことを実践しようとしない。

・チーム内で (後述の)「最初の壁」を共通認識する。

・ドメインモデルは反復型で開発する。

・スキルアップも反復的に高めていく。

※最初の壁については「最初の壁」で説明します。

反復型開発で後述します。


そこで、最初はドメイン内の幾つかのコアモデルから始めることを推奨します。

例えば、対象ドメインが病院業務であれば、医師や病室などです。

できれば、主要なオブジェクトで、かつ、オブジェクト記述を書きやすいオブジェクトが良いと思います。

オブジェクト記述とは、そのオブジェクトが何ものかを定義した短い文章です。

オブジェクト名やオブジェクト記述に含まれる単語は、「ユビキタス言語」の語彙です。

オブジェクト記述は、設計開発が進捗するにつれて、より専門的で深くなっていくでしょう。

他のオブジェクトも次第に出現してきます。


ドメインモデルのリファクタリングを繰り返しながら、設計スキルとドメインモデルの両方を、段階的に洗練していきます。

いろいろなモデリングパターンやプラクティスを、一気に取り入れて使いこなすのは難しいことです。

それらは、段階的に取り入れ、体得し、ドメインモデルとともに深化させていくことが重要です。


一方で、開発が進むにつれて、イテレーション (繰り返し) は重くなる傾向があります。

主な原因は、ドメインモデルを変更 (リファクタリング) すると、ビュー層や永続化層にも影響が及ぶことです。

ドメインモデル以外のビュー層や永続化層の変更作業は、その多くは機械的なものですが、イテレーションを重くする要因になります。

その結果、現実的な工数では、イテレーションを繰り返せなくなってしまうプロジェクトもあります。

これについては、後述の「開発プロセス」で述べます。

[目次に戻る]

最初の壁

ドメイン駆動設計やオブジェクト指向を始めるときに遭遇しやすい、最初の壁について紹介します。

折角、ドメイン駆動設計やオブジェクト指向に取り組んだけれど、結局、何も変えられないということがあります。

原因の1つは、下図に示すような「立ち上がり期」の停滞感です。

ここでの停滞とは、チームが空回り気味で、具体的な成果物 (例えば、動作する画面など) が出てこないような状態です。

結局、打開策が見つからずに、次節に述べるようなアンチパターンに後戻りするチームもあります。

この「立ち上がり期」を通過すれば、ドメインモデルベースの方が良い結果につながる、という経験や確信が無ければ、ここで挫折してしまうことになります。

導入した時の立ち上がりの比較図

※注意:上のグラフは感覚的なものです。

この立ち上がり期の停滞感を乗り越えなければ、オブジェクト指向やドメイン駆動設計の効果を得られる前に、従来型に戻ってしまうことになります。

[目次に戻る]

求められる知識

やはり、ドメインモデリングの質がポイントになります。

優れたモデリングを行うには、次のような手法やパターンなどの知識は必要です。

  • オブジェクト指向モデリング技術 (考え方)
  • ドメイン駆動設計 (考え方)
  • イテレーティブ開発、インクリメンタル開発、アジャイル開発 (考え方)
  • モデル駆動設計 (考え方)
  • Javaプログラミング
  • Java EE JPA(Java Persistence API)入門レベル
  • Wicket 入門レベル
  • Eclipseの基本操作
  • アナリシスパターンは、ドメインモデルの具体例、パターンです。他のドメインでも参考になるようなドメインモデルの構造、パターンを示します。
  • デザインパターンは、オブジェクト指向設計パターン、実装パターンです。
  • ドメイン駆動設計は、モデリングについてのパターンです。
[目次に戻る]

主要なキーワード

この章では、ドメイン駆動設計の主要な概念について考えます。

アプリケーション

ドメインとは、システム化対象領域を指します。例えば、在庫管理業務などです。

ドメインモデルとは、ドメインに存在する概念などを抽象化 (オブジェクトモデリング) したものです。

多くの業務アプリケーションで採用されているレイヤ構成 (ビュー層/ドメイン層/永続化層) で言えば、ドメインモデルは、ドメイン層に存在するものです。

ただし、「ドメイン貧血症」と言われるような、アンチパターンな構成をイメージすると、出だしから勘違いしてしまうことになります。

そのようなアンチパターン構成のドメイン層にあるのは、ビュー層と永続化層の間でデータのバケツリレーをするだけのようなクラスであって、ドメインモデルとは呼べません。

ドメインモデルは、アプリケーションの本質的な責務を持った概念、オブジェクトの集まりです。

下図は、アプリケーションの構成です。

ドメイン駆動設計の実践では、ドメインモデル、実装コード、ユビキタス言語をアジャイルに、つまりイテレーティブに開発していきます。

アプリケーションの構成図

ドメインオブジェクトを見つけ、ドメインモデルを構築するためには、主に、オブジェクト指向によるモデリング技術が必要です。

ドメイン駆動設計を理解し、実践するためには、オブジェクト指向技術が必要です。

[目次に戻る]

開発チームと実践的モデラ

開発チームは、ユーザ、ドメインエキスパート (業務の専門知識をもつ人) 、ソフトウェア技術者で構成されます。

チーム内では、(後述の) ユビキタス言語を使ってコミュニケーションを行います。

実践的モデラ (パターン) とは、主に体制についての指針です。

分析、モデリング、設計、プログラミングというように、過度に役割を分離しません。

実践的モデラパターンでは、チームメンバー全員が、モデラであり、プログラマです。


例えば、分析モデルという名前は、他の手法でもよく使われますが、これは、主に業務分析工程で作成される、ビジネス視点のモデルです。

設計モデルは、ソフトウェアの土台となる、ソフトウェア技術視点のモデルです。

実装モデルは、プログラム・コードです。

これらを、担当者や役割を (過度に) 分けずに、全員が一通り実践できるチームが必要です。


もしも現実問題として、実践的モデラが実現困難な場合でも、全員がモデルと実装コードを理解し、関心と責任を持つことが求められます。

モデリングとプログラミングを分離すると、モデルと実装の不一致など、ドメイン駆動設計はうまくいきません。

例えば、モデリング時に新たな発見があって、モデルを変更した場合には、その変更は、ユビキタス言語と実装コードに、正確に反映されなければなりません。

また、実装時に気づいた問題は、ドメインモデルとユビキタス言語に反映されなければなりません。

同様に、コミュニケーション中に気づく問題もあるでしょう。それも、ドメインモデルと実装コードに反映されなければなりません。

ユビキタス言語に変更 (用語の意味の変更など) があった場合には、会話の中に正確に反映されなければなりません。

つまり、ユビキタス言語、モデル、実装の間に一貫性を保つためには、全員が (少なくとも主要なメンバーは) 実践的モデラであることが求められます。

[目次に戻る]

ユビキタス言語

どんなチームでもコミュニケーションは重要です。

しかし、人や役割によって使用する名詞や動詞の意味が、微妙に違うと感じたことはないでしょうか。

ユビキタス言語とは、ドメインエキスパートの知識やドメインモデルをもとに、単語の微妙な違いを排除し、より正確なコミュニケーションを行うためのものです。 ドメインモデルや実装モデルの要素と正確に対応付けができることがポイントです。


※DDD本 p.26 から引用:ここから

「モデルを言語の骨格として使用すること。 チーム内のすべてのコミュニケーションとコードにおいて、その言語を厳格に用いることを、チームに約束させること。 図やドキュメント、そして何より会話の中では同一の言語を使用すること。 言語を使う上で問題があれば、代わりの表現を用いて実験することで、問題を取り除くこと。 そうした表現は代りとなるモデルを反映している。 そこで、新しいモデルに合わせてコードをリファクタリングし、クラス、メソッド、モジュールの名前を変更すること。 会話の中で用語が混同されていたら、普通の単語の意味について認識を合わせるのと同じやり方で解決すること。 ユビキタス言語における変更は、モデルに対する変更であると認識すること。」

※DDD本から引用:ここまで


ソフトウェア技術者はクラスやメソッドなどに関心があり、それらを実世界の概念と結び付けて思考し会話します。

一方、ユーザやドメインエキスパートには、クラスなどの知識はありません。

もし「クラス」という単語を使っていたとしても、それば、ソフトウェア技術者が使うクラスとは別の何かである可能性があります。

ドメインモデルを作成するときは、チーム内でのコミュニケーションがとても重要です。

ドメイン駆動設計では、このコミュニケーションを正確にするために、共通言語として「ユビキタス言語」を明確に位置づけます。

そして、必ずユビキタス言語を使ってコミュニケーションするようにします。


ユビキタス言語があれば、例えば「見積書」という名前は、会話の中でも、モデルの中でも、実装コードの中でも、そのまま「見積書」と現され、同じ概念を指します。

アプリケーションユーザも、ドメインエキスパートも、ソフトウェア技術者も、頭の中で読み替えたりしないで、そのまま使えます。

ただし日本では、「見積書」はローマ字表記になるかもしれません。

英語表記になる場合は、読み替えが必要になるので、その点は検討が必要かもしれません。


ユビキタス言語の語彙は、モデルや実装コードのクラス名、メソッド名などと双方向に追跡可能 (紐付けられる) にします。

[目次に戻る]

ドメインモデル

ドメインモデルとは、あるドメイン (アプリケーション領域、業務領域) に存在する概念を抽象化したものです。

ドメインモデルは、ユビキタス言語や、UMLなどのモデリング言語、プログラミング言語で定義されます。

ソフトウェアで表現されたドメインモデルを構成するオブジェクトのパターン (主な種類) には、エンティティ、値オブジェクト、サービスがあります。

イメージとしては、ドメイン:書店在庫業務, エンティティ:本, 値オブジェクト:ISBN, サービス:在庫移動 のような感じです。

それぞれについて以下に示します。

[目次に戻る]

エンティティ

ドメインモデル内のオブジェクトは主に、エンティティ、値オブジェクト、サービスの3つに分類されます。

エンティティは、連続性と識別性 (同一性と同値は区別される) を持ちます。

少し乱暴ですが、データベースの論理設計で抽出された論理テーブルの1つ1つは、(かなりの確率で) 妥当なエンティティと言えます。

実装の観点では、エンティティは、テーブル名や列名を、そのクラス名や属性名として持つクラスです。

ただし、テーブルにはありませんが、エンティティはドメインにおける重要で本質的な責務をメソッドなどとして持ちます。

これは、重要な違いです。


ドメイン駆動設計はオブジェクト指向モデリングを前提とはしません。

しかし、現実的な手法として、オブジェクト指向モデリングが採用されます。

そこで、オブジェクトを見つけるときのヒントとして、少々、古典になりますが、「オブジェクト指向システム分析」シュレイアー、メラー著 にクラスの候補として以下が挙げられています。

  • 有形物
    • 人、商品、伝票。
  • 役割
    • 人や構成により演じられる役割。医師、患者、顧客、従業員。医師は患者にもなる。
  • 出来事
    • 飛行、事故、故障、サービス要求。
  • 相互作用
    • 買い入れ、結婚。
  • 仕様
    • 製品などの仕様。

DOA (データ中心アプローチ) でも、上に挙げたような概念やモノは、テーブルの候補となるでしょう。

そして、それらの概念やモノは、ドメイン駆動設計のエンティティの有力な候補です。

各エンティティの責務や協調者についても、分析、設計、実装を行うことで、ドメイン駆動設計のドメインモデルとなっていきます。


ドメイン駆動設計では、ドメインモデルが中心です。

ただし、実際には、優れたドメインモデルを開発することは容易ではありません。

出来上がったドメインモデルの洗練度などは、相当の差が生じてきます。

この辺は、ドメイン駆動設計と言うよりも、オブジェクト指向モデリングのスキルが求められます。

本記事では、オブジェクト指向については多くを記述していませんが、ドメイン駆動設計では、ドメインモデリングのスキルは、当たり前のように求められます。

[目次に戻る]

値オブジェクト

識別性を持たない、変更不可の不変 (immutable) オブジェクトで、その属性だけに関心があるようなオブジェクトです。

多くの場合、エンティティオブジェクトの状態を記述する属性として振る舞います。

例として、図形処理アプリケーションの座標点クラス (Point) があります。

多くの場合、エンティティの属性の状態を現すクラスは値オブジェクトとなります。

値オブジェクトには一意性は必要なく、同値性が重要です。


エンティティの属性の状態を示すためには、使用するプログラミング言語のプリミティブ型で十分なケースも多くあります。

例えば、Pointクラスではなくても、実数値を2つ持った2次元配列で十分と思われるケースもあります。

しかし、Pointクラスのような値オブジェクトをドメインモデルに追加することで、ドメインモデルをより洗練できることもあります。

ただし、過度に追加するとクラスの爆発と言われるような状況に陥ることもあります。

[目次に戻る]

エンティティと値オブジェクトの例

このサンプルは、正確な医療情報や知識に基づくものではありません。

集約のクラス図

このモデルでは、患者オブジェクトは、血糖値とヘモグロビンA1cの値を基に血糖コントロールの状況をメッセージ形式で応答します。

血糖値は、空腹時血糖値、食後血糖値など1日の中でも変動する検査値です。

ヘモグロビンA1c (HbA1c) は、おおよそ2カ月間の平均血糖値を推定できる検査値です。

血糖コントロールとは、運動や食事、薬などで、血糖値を適正範囲に保つことです。


患者オブジェクトが「血糖コントロール状況を応答する」という責務を持たないモデルもあるでしょう。

例えば、次図のように診療記録オブジェクトが「血糖コントロール状況を応答する」責務をもつモデルも考えられます。

集約のクラス図2

また、医師オブジェクトや診断サービスなどを追加すべきかもしれません。


ドメインモデルをすぐに決定できるケースは少ないかもしれません。

実際には、ドメインエキスパートの知識、ユースケース、DDD本のパターンや指針、アナリシスパターン、デザインパターンなどを参考に、ドメインモデルを繰り返し洗練していくことになります。

従って、ドメイン知識やモデリング技術は重要です。

そして、モデリングしたイメージを素早く実装し検証するスピードも重要です。

もしも、1回のイテレーション (モデリング → 実装 → 検証) が重くて時間がかかるようだと、ドメインモデルに対するチームの関心が薄れ、集中できなくなります。

[目次に戻る]

サービス

ドメインには、エンティティや値オブジェクトとして扱うには不自然なものが存在します。

GRASPパターンの純粋人工物 (Pure Fabrication)です。

ドメインには実在しないオブジェクトであり、サービスという形でユビキタス言語に組み込みます。

サービスは基本的に状態を持ちません。

エンティティや値オブジェクトではなく、アクションや操作といった概念として存在します。


例えば、在庫管理業務の中に、「倉庫間移動」という業務処理があります。

倉庫間移動とは、「ある倉庫の在庫商品を別の倉庫に移動する」ことです。

ここで、この倉庫間移動は、どのオブジェクトの責務でしょうか。

単独のオブジェクトの責務とする場合もあれば、複数のオブジェクトの相互作用とする場合もあるでしょう。

例えば、

(1) 倉庫クラスの静的メソッドとします。

     Warehouse#transferStock(倉庫1, 倉庫2, 商品, 数量)

(2) 倉庫クラスのインスタンスメソッドとします。

     warehouse.transferStock(別の倉庫, 商品, 数量)

などが考えられます。

しかし、ある責務を、あるエンティティオブジェクトや値オブジェクトの責務とすると、不自然な場合があります。

このようなときには、サービスオブジェクトを検討します。

そうして、次のように設計してみます。

(3) 倉庫サービスの倉庫間移動

     StockService#transferStock(倉庫1, 倉庫2, 商品, 数量)


ドメインモデルのクラス図サンプル


サービスオブジェクトを適切に追加することで、適切な責務割当てを実現できる場合があります。

サービスオブジェクトは、デザインパターンのファサード (Facade) としての役割もあります。

但し、色々な責務をサービスに詰め込んでしまうと、アンチパターンと同類になってしまうので、注意してください。

まずは、適切なエンティティや値オブジェクトを検討します。


例として、平面に図形描画する処理系を実現する場合を考えてみます。

円や矩形の描画処理は、どのように設計・実装すべきでしょうか。


ケース(1)

DrawingService.drawCircle(x, y, radius);

DrawingService.drawRectangle(x, y, width, height, angle);


ケース(2)

Circle circle = new Circle(x, y, radius);

circle.draw();

Rectangle rectangle = new Rectangle(x, y, width, height, angle);

rectangle.draw();


ケース(1)の場合、DrawingServiceはすぐに肥大化し、役割は不明瞭になるでしょう。

ケース(2)の方が適切でしょう。


なお、ここでは、在庫管理業務や描画処理系そのものについては議論していません。

業種や組織によっても最適なドメインモデルは違うでしょう。

[目次に戻る]

モジュール

Javaのパッケージと同義です。モジュール名もユビキタス言語に含まれる名前です。

モジュール名、モジュール構成もリファクタリングの対象です。

モジュール間は低結合、モジュール内は高凝集にします。

[目次に戻る]

集約

集約を見つけ出し適切にモデリングすることは深い問題です。 DDD本からの引用を挙げておきます。

※引用:ここから (DDD本 p.123)

関係を最小限に抑えるように設計することにより、 関連を辿る処理は単純化され、 関係性の爆発的増加もある程度は制限される。 しかし、ほとんどのビジネスドメインは非常に強く相互に結びついているので、 結局はオブジェクトの参照を通じて、長くて深い経路を辿ることになる。 ある意味で、こうしたもつれはこの世界の現実を反映している。 現実には、はっきりした境界が引いてもらえることはめったにないのだ。 これはソフトウェアの設計における問題である。

※引用:ここまで (DDD本 p.123)


次図は集約の例です。ドメインとしては架空の書店の書籍情報管理を想定しています。 実際のモデリング結果ではありません。 もし、出版社の業務であれば、集約ルートとしては、書籍よりもISBNの方が適切かもしれません。 また、同じ書店の中でも、業務が違えば、モデルも変わるかもしれません。 どんな業務でも完璧に振る舞うモデルを作るというのは、現実的ではありません。 ただし、変えたくなる原因が、業務用語の不統一や慣行の違い等であれば、まずその概念を整理・統合すべきかもしれません。

(DDD本の「境界づけられたコンテキスト」も参考になります)

実際の開発では、必要なユースケースを実行できるように、リファクタリングと検証を繰り返しながら、ドメインモデルを作り上げていきます。

価格やISBNは、JavaのBigDecimalやStringで十分な場合もありますが、ドメインモデルに価格クラスやISBNクラスを追加することで、より洗練された分かり易いモデルになることもあります。

集約のクラス図3

 ・集約ルートエンティティはグローバルな同一性を持ちます。

 ・境界内部のエンティティは境界内でのみ一意となるローカルな同一性を持ちます。

 ・境界外にあるオブジェクトは、ルートエンティティへの参照を保持できます。

 ・境界外にあるオブジェクトは、境界内部への参照を保持することはできません。集約ルートを介して参照します。

[目次に戻る]

開発プロセス

ドメイン駆動設計では、モデル駆動による反復型開発 (Iterative and Incremental Development) が基本です。

反復する中で、最も重要なタスクはドメインモデリングです。

反復型開発

※引用: 反復型開発「ウィキペディア日本語版」更新日時: 2016年1月3日 11:56 (UTC) ここから

反復型開発の基本的考え方は、ソフトウェアシステムを徐々に開発していき、ソフトウェア開発者が過去の開発から学んだことを生かして、使用可能なシステムを段階的にリリースしていくというものである。 開発者は、開発そのものと実際のシステムの使用から学ぶ。重要な点は、要求仕様の単純なサブセットから開発を始め、徐々に改良を加えていき、最終的に完全なシステムを実装するということである。 反復ごとに設計が修正され、新たな機能が追加されていく。

※引用: ここまで


ドメイン駆動設計のキーワードを加えると次のようになります。

「反復型開発は、リファクタリングを繰り返し、段階的にモデルの完成度を上げていく手法です。

繰り返す単位をイテレーションと呼び、1回のイテレーションの中で、分析から設計、実装、検証までを完結させます。

ドメイン駆動設計では、ドメインモデルと実装とユビキタス言語を、常に整合させながら繰り返すことが重要です。」


[反復型開発の流れ]

反復型開発の流れ図

反復型開発を順調に実践するためのカギは、イテレーションが軽量 (作業量が少ない) であることです。

そして、ドメイン駆動設計の観点からは、ドメイン以外の作業が少ないことです。

ドメインモデル中心

本記事では、ドメインの実装モデルを起点に反復することを「ドメインモデル中心」と呼ぶことにします。

ドメインモデル中心では、基本的に、モデル図よりも、実装を先行させます。(Java コードファースト)

ただし、先にモデル図を使って設計したい場面では、先にモデル図を作って分析すべきです。

コードファーストに固執する必要はありません。

1つのドメインの中にも、コードファーストが適した部分、モデルファーストが適した部分、それぞれ存在すると思います。

次のセクションで、ドメインモデル中心に実践する例を示します。

[目次に戻る]

ドメインモデルからアプリケーションを自動生成する

概要

反復型開発の成功のカギは、反復 (イテレーション) を、本質的な問題 (ドメイン) に集中して、軽快に繰り返すことができるか否かです。

本記事では、ツール (DDBuilder) を使って、Java ドメインモデルから、Java Web アプリケーションを自動生成します。

自動生成することで、ドメインモデル以外の実装などの、本質ではない問題を軽減できます。

また、素早くドメインモデルを動かして検証できるため、ドメインモデルの洗練 (リファクタリング) からモデルの検証までの時間と作業量を軽減できます。

下図は、その流れ図です。

自動生成ツールを使った開発の流れ

イテレーションの流れ図

自動生成処理の流れ

開発の流れ図

詳細はユーザーガイド(PDF)を参照ください。

自動生成の効果

次のような効果が期待できます。

  • 継続的テスト
  • 早い段階からのテスト (シフト レフト)
  • イテレーションの工数削減と期間短縮
  • イテレーションの質の向上
  • コード中心・実装一致
  • 永続化周りの煩雑なコードの削減
  • 手組み実装によるミスとロスの排除

特に、次の2つの効果が重要です。

効果1 継続的テストの工数軽減

ドメインモデルをいつでも、素早く (アジャイルに) 、動かして検証できるということは、スムーズな開発をする上で重要です。

例えば、UMLで表現されたドメインモデルは、そのままでは動かしてみることはできません。

ソフトウェアで表現されたドメインモデル (例: Javaで実装されたドメインモデル) も、それだけでは動かせません。

実際に動かすためには単体テストコードやドライバのようなものが必要です。

つまり、ドメインモデルを実際に動かして検証するためには、ドメインモデル以外の実装も必要になります。

本記事では、動作可能な実装モデルを、「動くソフトウェアモデル」と呼ぶことにします。

動くソフトウェアモデル (検証モデル) は次のような観点で必要です。

  • 動くソフトウェアモデル は、各イテレーションの成果物のひとつです。
  • 実際に動かすことで、ドメインモデルの検証をより正確にします。
  • 具体的に動かすことで、開発チーム内でのドメインモデルに対する知識や理解のバラつきを抑止します。
  • 過剰な机上分析状態に陥ることを予防します。
  • 技術寄りではないメンバーも、Webアプリケーションとして操作することで深く理解し検証できます。

もしも、動くソフトウェアモデルを作らずに、机上のUML図や単体テストレベルのテストコードだけでドメインモデルを検証しようとすると、 検証に手間がかかるうえに、メンバー間の齟齬も発生しやすくなります。 しかし、具体的なアプリケーションがあれば、UML図などに不慣れなメンバーでも、検証作業が容易になり、精度も上がります。

効果2 イテレーションの質の向上

イテレーションは反復型開発のコアプロセスです。

動くソフトウェアモデルを使って検証できれば、イテレーションの品質が上がります。

また、イテレーションを軽快に繰り返すことができれば、チームの関心事をドメインモデルに集中させることができます。

ただ現実には、動くソフトウェアモデルを ”いつでも動かせる状態” に維持することは、簡単ではありません。

ドメインモデルを動かすために、想定以上の時間を要するケースが多いからです。

例えば、Webアプリケーション型で検証しようする場合、ドメインモデルをリファクタリングする度に、ユーザインタフェース層やインフラストラクチャ層などの変更が必要になるからです。

イテレーションの本来の目的はドメインモデルのリファクタリング (洗練) です。

しかし、イテレーションの工数が増えて、簡単には繰り返せなくなることがあります。

1回1回のイテレーションが重くては、反復型開発のメリットは得られません。

この問題を解決するためには、開発プロセスの一部を自動化するなど、何らかの対策が必要です。

成果物

開発チームは、DDBuilderが生成するJava Web アプリケーションに縛られる必要はありません。

本当の成果物は、アプリケーションではなく、「ソフトウェアで表現されたドメインモデル」です。

ここでは、その表現手段として Java 言語、検証手段として Web アプリケーションを使用したにすぎません。

Webアプリケーションはドメインモデルを評価するための入れ物にすぎません。

ドメインモデルは DDBuilder に依存しません。

いつでも DDBuilder を使わないで、開発を継続できます。 (自作の「Wicket + Java + JPA Webアプリケーション」として開発できます)

従って、DDBuilderは、Java Web アプリケーション自動生成ツールというよりも、ドメインモデルのインキュベータ (育成器) と考えた方がより適切です。

もちろん、そのまま Webアプリケーションとして実運用することもできます。

自作のページも追加できます。再度自動生成しても追加したページは上書きされません。

自動生成ツール DDBuilder

このセクションでは、自動生成ツール DDBuilder について説明します。

DDBuilderは、当社が開発し公開している無償・無保証のソフトウェアです。

Java ドメインモデルから Java Web アプリケーションを自動生成します。

インストールは不要で、ダウンロードしたファイルを解凍すれば使用できる Java デスクトップアプリケーションです。

自動生成機能の入力と出力

入力と出力を例示します。

入力は、 Java で実装されたドメインモデルです。クラス図ではありません。

出力は、Java Webアプリケーションです。


例 ドメインモデルのクラス図

例 上図のドメインモデルのJava実装例 (DDBuilderの入力)


package mycom.domain;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import mycom.domain.ddb.DdBaseEntity;
/**
 * 製品
 */
@Entity
public class Product extends DdBaseEntity {

    /** 製品名 */
    private String name;
    
    /** 在庫リスト */
    @OneToMany(mappedBy="product")
    private List<Stock> stockList;
    
    /** コンストラクタ */
    public Product() {
        super();
        this.name = "";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Stock> getStockList() {
        return stockList;
    }

    public void setStockList(List<Stock> stockList) {
        this.stockList = stockList;
    }
    
    @Override
    public String getDDBEntityTitle() {
        return "タイトル: " + this.getName();
    }
}
[4つのクラスを全て表示]

なお、この簡単なドメインモデルは、自動生成機能を説明するためのものです。

そのため、ドメインモデルらしい振る舞いやサービスは含んでいません。つまり「ドメインモデル貧血」状態です。


DDBuilderは、上記のような Java実装コードを読み込んで解析し、Webアプリケーションとして必要な、ビュー層や永続化層を生成します。

DDBuilderは、Java Webアプリケーションとして、1つのフォルダを出力します。

そのフォルダは、そのまま Eclipse にインポートして、Webアプリケーションとして起動できます。

※出力フォルダは「Eclipse 動的 Web プロジェクト」の構成になっています。

Java Webアプリケーションの画面例

生成された Webアプリケーションの画面について説明します。

Webアプリケーションを起動すると、ブラウザからアクセスできます。

以下は、ブラウザからアクセスした時の画面です。

なお、詳細な手順は「開発の流れ」で説明します。


ホーム画面

ホーム画面

ドメインクラス (エンティティ) の一覧画面です。

リンクを辿ると、各ドメインモデルの新規作成、更新、削除ができます。

定義されているドメインクラスの一覧画面

新規登録・編集・削除画面

編集画面

定義されているサービスメソッドの一覧です。

定義されているサービスの一覧画面

上の画面の「実行」リンクをクリックすると、サービスメソッドの実行画面が表示されます。

サービスメソッドの実行画面

サービスメソッドに渡す引数を指定します。

サービスメソッドの引数を指定画面

サービス実行ボタンを押下すると、サービスメソッドが実行されて、結果が表示されます。

この例では、サービスメソッドは、現実のような実装ではなく、結果を無条件にString型で返却しているだけです。

下の画面の「完了。中央倉庫 → 西倉庫…」の部分が実行結果です。

サービスメソッドの実行結果画面

上の例では、最初にテスト用のデータ (インスタンス) が登録されています。(ベッド、イス、中央倉庫、西倉庫)

例は簡易的な実装なので、商品や在庫、倉庫を画面から登録するためには、操作順序に少し注意が必要です。

もしも、上の画面のように、実際に動かしたいという場合は、サービス層の TestDataService.java の内容を編集してください。

mycom.service.g.TestDataService.java は自動生成されていますので、メソッドの内容を下のソースコードと同じにします。

ホーム画面の「テストデータ追加」ボタンを押下すると、このサービスが実行されます。

実行すると、デモ動作に必要な最小限のテストデータとして、倉庫、在庫、商品のインスタンスが作成されます。

ホーム画面の「テストデータ追加」でIDとパスワードを求められた場合は、IDとパスワードともに「aaa」でログインできます。


[テストデータ登録サービスクラスのサンプルコード]

Webアプリケーションの構造

下図は、DDBuilderが自動生成する Java Web アプリケーションの構成図です。

DDD本 (p.70) のレイヤ化アーキテクチャに準じています。

開発者は、ドメインモデリングを行い、ドメインクラスを Javaで実装します。

DDBuilderは、この Javaの実装コードを読み込み、抽象構文木による解析を行い、ビュー層や永続化層のクラスを生成します。

※実装の前に、クラス図などを作成する場合もあれば、すぐに Javaコードで実装する場合があると思います。


DDBuilderが生成するアプリケーションのレイヤ化アーキテクチャ図


DDBuilder 固有のコンテナなどはなく、フレームワークとして次を使用しています。

ビュー層:Apache Wicket

永続化層 (インフラストラクチャ層):Java EE JPA/ Hibernate

また、上図中の「DDBuilder基底」部分には、DDBuilder固有のいくつかの基底クラスが存在しています。


Java Web アプリケーションは、1つの Eclipse プロジェクトになっていて、Eclipse にインポートして、編集・実行できます。

下図は、Java Web アプリケーションとして生成されたフォルダの内容です。

Eclipseプロジェクト構成

.settings, .classpath, .project は Eclipse 用の設定情報です。

src フォルダ配下に、開発者が実装するドメインモデル (Javaクラス) と、DDBuilderが生成したJavaクラスが作成されます。

lib フォルダの配下には、必要な OSS のライブラリが含まれています。

自作ページの追加

自動生成されたWebアプリケーションに自作のページを追加できます。

DDBuilderは、自作ページを上書きしません。

自作ページの作成は、自動生成されたページクラスを参考にすれば、効率よく自作できるでしょう。

ページサンプル : Wicket DataTable ソート列 アクション列 テーブル

ページサンプル : 改ページ付き・ソート列付き・1件複数行対応 テーブル

ロックインフリー

利用者チームは、開発時でも実行時でも、いつでもDDBuilderを切り離すことができます。

DDBuilderにロックインされることはありません。

ドメインモデルがある程度安定し、頻繁な繰り返しが必要ない段階になれば、DDBuilderは必要なくなるかもしれません。

そして、ドメインモデルを他の言語やアプリケーションフレームワークに移植することもあるでしょう。

DDBuilderはドメインモデルのインキュベータ (孵化器・育成器) です。

もちろん、そのまま運用することもできます。

Java のメリット

リファクタリングの中で、クラス名を変えたり、メソッド名を変えることは頻繁にあります。

Javaのような強い静的型付けの言語であれば、Eclipseなどのリファクタリング機能を使って安全に変更できます。

しかし (筆者の勉強不足かもしれませんが) 動的型付け言語では期待する結果を得られないのではないでしょうか。

予期せぬ名前まで置換えられたりしないでしょうか。

また、他の言語や他のフレームワークへ移植する場合にも、元の言語がJavaであればより安全に移植できるでしょう。

Apache Wicket のメリット

Wicketは、Java Web アプリケーションフレームワークです。

Struts系と違い、 オブジェクト指向プログラミングモデルを前提としたフレームワークです。

HTMLとの独立性が高く、基本的にすべてをJavaコードで実装するアーキテクチャは、 自動生成機能を実現するうえでも好都合で相性がよいと言えます。

ドメインモデルは利用者が実装しますが、Wicketを意識することはありません。

Wicketを意識するのは自作ページを追加する場合です。

Java JPA Hibernate のメリット

HibernateはJavaEE JPA実装の1つです。

DDBuilderが生成する動くソフトウェアは、デフォルトではJava標準のJavaDBを使用します。

Hibernateは、 PostgreSQL, MySQL, Oracle, SQLServer, DB2など代表的なデータベースをサポートしており、設定変更だけで他のデータベースに変更できます。

「動くソフトウェア」は、Hibernateを「Javaアプリケーションのスタンドアロン型」で使用します。Springなどのコンテナは不要です。

ドメインモデル層のクラスを実装するときには、JPA / Hibernateの知識が必要になります。

主に、関連を定義するためのアノテーションの書き方などの知識が必要になります。

自動生成されるクラス

DDBuilder利用者が実装するドメインクラス (エンティティ) と、DDBuilderが自動生成するクラスについて説明します。

例として、DDBuilder利用者が、Product.javaというドメインクラス (黄色の網掛けのクラス) を追加します。

次に、DDBuilderで自動生成を実行すると、下図ようなクラスとHTMLファイルが自動生成されます。(下図は、すべてではなく、主なファイルです)

view, service, domain, persistenceはパッケージ名でス。それぞれ、ビュー層、サービス層、ドメイン層、永続化層を構成します。

DDBuilder利用者は、Product.javaだけを実装すれば、他のクラスは自動的に生成できます。

自動生成されたものは、そのまま Java Web アプリケーションとして動作します。

Productの登録、更新、削除、一覧がWeb画面で操作できます。

Product.javaは、@Entityのような、JPAアノテーションを含みますが、POJO (Plain Old Java Object) です。

1つのドメインモデルから自動生成されるファイル

ビュー層の1つの画面は、同名のHTMLファイルとJavaクラスで構成されます。例: ProductPage.htmlとProductPage.java。

これは、ビュー層で使用している Apache Wicket フレームワークの仕様です。

Wicketは、JSP/Struts系のアーキテクチャではなく、Jave EE JSP 系のアーキテクチャです。

HTMLファイルは、独立していて、通常のHTMLと同様に編集できます。

つまり、JavaやJSPなどの知識が不要なので、デザイン専門のデザイナーが編集できます。

Wicketでは、画面は、完全に Java オブジェクト指向プログラミングで実装できます。

例えば、Productを使用するサービスが必要になった場合は、上図のSomeService.javaのように追加できます。もちろん、サービス名は適切な名前を付けます。数も制約されません。

自動生成された画面では不足する場合は、画面を追加できます。(上図では、CustomePage)

自動生成を再度実行しても、SomeServiceやCustomePageは上書きされません。

具体的な操作イメージは、次項の「DDBuilderを使った開発の流れ」を参照ください。

[目次に戻る]

トランザクション管理

Java EE JPA の永続化機能では、永続化コンテキスト (EntityManager) を使用します。

永続化コンテキストには、次の2種類があります。

(1) コンテナ管理

永続化コンテキストのライフサイクル (生成、破棄) は、EJBコンテナによって管理されます。

(2) アプリケーション管理

永続化コンテキストのライフサイクルは、アプリケーションによって管理されます。

EJBコンテナは必要ありません。


DDBuilderが生成するアプリケーションでは、アプリケーション管理を使用します。

従って、特別なコンテナを必要としません。

永続化コンテキストのライフサイクルは、自動生成されたコードによって行われます。

DDBuilder利用者は、特に意識する必要はありません。


トランザクションを管理するためには、トランザクションマネージャを使用します。

トランザクションマネージャには、次の2種類があります。

(1) JTAトランザクション

EJBコンテナが必要です。トランザクション管理は、EJBコンテナによって自動的に行われます。

(2) リソースローカルトランザクション


EJBコンテナは必要ありません。

DDBuilderが生成するアプリケーションでは、リソースローカルトランザクションを使用します。

従って、特別なコンテナを必要としません。

トランザクション管理は、自動生成されたコードによって行われます。

DDBuilder利用者は、特に意識する必要はありません。


永続化コンテキストのライフサイクル、トランザクション管理の流れを下図に示します。

トランザクション管理

[目次に戻る]

クラス図の扱い

DDBuilderにはクラス図をサポートする機能はありませんが、ドメイン駆動設計を実践するうえで、クラス図やそれに相当するものは必要です。

本記事では、分析時のクラス図は手書きラフスケッチとし、正式なクラス図はUMLツールなどで Java ソースからリバースエンジニアリングされることを推奨します。 リバースエンジニアリングであれば常に実装と一致させることができます。

もしも、表計算ソフトなどで作成してしまうと、不一致の原因や、イテレーションが回らなくなる原因にもなるでしょう。

[目次に戻る]

関連のタイプと属性型

このセクションでは、DDBuilderがサポートする関連の種類、インスタンス属性型の種類を示します。

そのため、サンプルのモデルには、ドメイン駆動設計のエンティティらしいメソッドが無いことに注意してください。

また、この例では、エンティティ間の関連をJPAアノテーションを使って実装していますが、必須ではありません。

実際のドメインモデリングでは、関連を決めることが大変難しい業務や局面があります。

関連を確実に定義できるところは、この例のように実装して、

あいまいさが残る部分は、JPQLやネイティブSQLを使って、関連を実装することも検討すべきです。

[サンプルコードをダウンロード]


UMLクラス図

関連の例


サンプル コードには次の5つのクラスが含まれています。

(1) 著者 @Entity

public class Author extends DdBaseEntity

(2) 書籍 @Entity

public class Book extends DdBaseEntity

(3) 版 @Entity

public class Edition extends DdBaseEntity

(4) ISBN @Entity

public class Isbn extends DdBaseEntity

(5) 書店 @Entity

public class Store extends DdBaseEntity

関連タイプと属性型のサンプルコード


/*
 * DDBuilderで使える関連タイプと属性型に関する例です。ドメイン駆動設計的な観点の例ではありません。
 */
package jp.co.nextdesign.domain;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
import jp.co.nextdesign.domain.ddb.DdBaseEntity;

/**
 * 著者
 */
@Entity
public class Author extends DdBaseEntity {
    private static final long serialVersionUID = 1L;

    /** 名前 */
    private String name;
    
    /** 書籍リスト owning/parent */
    @OneToMany(mappedBy="author", cascade=CascadeType.ALL, orphanRemoval=true)
    private List<Book> bookList;

    /** 書籍リスト owning/parent */
    @OneToMany(mappedBy="author2", cascade=CascadeType.ALL, orphanRemoval=true)
    private List<Book> bookList2;

    /** コンストラクタ */
    public Author(){
        super();
        this.name = "---";
        this.bookList = new ArrayList<Book>();
        this.bookList2 = new ArrayList<Book>();
    }
    
    //OneToManyで双方向関連を維持するためのコードを含むgetBookList(),
    //setBookList(List<Book> bookList)の例
    @Transient
    private ArrayList<Book> latestBookList = new ArrayList<Book>();
    public List<Book> getBookList() {
        return this.bookList;
    }
    public void setBookList(List<Book> bookList) {
        for(Book newBook : bookList){
            if (!latestBookList.contains(newBook)){
                newBook.setAuthor(this);
            }
        }
        for(Book oldBook : latestBookList){
            if (!bookList.contains(oldBook)){
                oldBook.setAuthor(null);
            }
        }
        this.bookList = bookList;
        latestBookList = new ArrayList<Book>(this.bookList);
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<Book> getBookList2() {
        return bookList2;
    }
    public void setBookList2(List<Book> bookList2) {
        this.bookList2 = bookList2;
    }
    
    @Override
    public String getDDBEntityTitle(){
        return this.name;
    }
    
    /** debug */
    public String getDebugInfo(){
        String info = "<" + this.getClass().getSimpleName() + ">";
        info += "\nname=" + this.getName();
        info += "\n</" + this.getClass().getSimpleName() + ">";
        return info;
    }
}
[すべてのクラスを表示]

【重要】ドメイン駆動設計 ドメインモデルのサンプルとしての注意点

この例は、DDBuilderがサポートする属性型と関連の型を示すためのものです。

そのため、ドメインモデルとしての重要な責務 (メソッド) が欠けています。


【重要】このサンプルモデルはシンプルですが、現実には、集約 (AGGREGATES) についても注意深くモデリングする必要があります。

JPAのアノテーションを使って、すべての関連を実現しようとしないことです。


以下にDDD本から引用します。

※引用:ここから (DDD本 p.123)

関係を最小限に抑えるように設計することにより、 関連を辿る処理は単純化され、 関係性の爆発的増加もある程度は制限される。

しかし、ほとんどのビジネスドメインは非常に強く相互に結びついているので、 結局はオブジェクトの参照を通じて、長くて深い経路を辿ることになる。

ある意味で、こうしたもつれはこの世界の現実を反映している。

現実には、はっきりした境界が引いてもらえることはめったにないのだ。

これはソフトウェアの設計における問題である。

※引用:ここまで (DDD本 p.123)

DDBuilderを使った開発の流れ

詳しく見る
[目次に戻る]

ダウンロード

ダウンロードページへ...

動作確認済み環境

  • Java 8
  • Windows7 pro 32bit/64bit, Windows10 pro 64bit
  • Eclipse IDE for Java EE Developers 4.4, 4.3
  • Apache Tomcat 7.0, 8.0, 8.5, 9.0

インストールとアンインストール

インストールやアンインストールは不要です。

最初に、ダウンロードしたzipファイルを適当な場所に解凍してください。

不要になった場合は、 解凍結果をエクスプローラなどで削除してください。

※ ダウンロードしたファイルを解凍すると次の説明ファイルが含まれていますので、参考にしてください。

「はじめにお読みください(使い方).txt」

「DDBuilder_Guide_Ver2.pdf」

ダウンロードページへ

ユーザガイド

ユーザガイド [PDF] [2.5MB]

サポート

使いはじめ等で、ご不明な点がありましたら「お問合せフォーム」からご連絡ください。 (無料)

弊社の都合で返信が遅くなる場合がありますが、ご了承ください。

また、有料でのサポートも別途用意しております。詳しくはお問合せください。

オープンソースで公開

GiHubでオープンソースとして公開しています。 [Apache License Version 2.0]

- DDBuilder (ツール本体)

https://github.com/nextdesign-co-jp/DDBuilder.git

- DDBuildertemplate (テンプレート)

https://github.com/nextdesign-co-jp/DDBuilderTemplate.git

謝辞

DDBuilderは次のソフトウェアを利用しています。

DDBuilderを入門や実習に活用

DDBuilderは、ドメイン駆動設計の入門用や学習用として役立ちます。

例えば、入門者の場合は、ドメインモデルをイメージできるまでに、時間がかかることがあります。

DDBuilderを活用すれば、簡単なドメインオブジェクトを実装して、それを動かしてみることができるので、イメージしやすくなるでしょう。

簡単なドメインオブジェクトとは、例えば、病院システムの患者クラスや、在庫管理システムの倉庫クラス等です。

1つのクラスで構いません。

ドメインモデルを動かしてみるまでのハードルは、高くありません。

オブジェクト指向、モデル駆動設計、アジャイル開発、ドメイン駆動設計などの入門者にとって、机上だけで、ドメイン駆動設計やドメインモデルを理解することは、簡単ではありません。

しかし、実際に実装して、具体的に動かしてみれば、理解しやすくなります。

DDBuilderが生成した Java Web アプリケーションを見れば、「利口なUI」や「トランザクションスクリプト」などのアンチパターンとの違いも分かりやすいと思います。

ドメインがアプリケーションの本質であるという考え方や、ドメインモデルを中心にした開発方法、イテレーティブな開発についても理解いやすくなるでしょう。

抽象的な議論ばかりしていると、時間ばかりが経ってしまいます。

具体的にイテレーションを繰り返しながら、段階的にドメイン駆動設計を理解し、習得していかれることを推奨します。

ドメイン駆動設計が示す内容は広く深いです。

その内容を深掘りしすぎて、何も始められないといったケースも少なくありません。

例えば、オブジェクト指向の基礎とDDD本の第5章位までを読んだら、後は、実際に試しながら理解を深めていく、といった方法を推奨します。

[目次に戻る]

他の手法との関係

ドメイン駆動設計では、オブジェクト指向、モデル駆動開発、アジャイル開発を活用します。

それらの手法とドメイン駆動設計の立ち位置を考えてみます。

他にも、ドメインモデリングで役に立つ概念やパターンを簡単に紹介します。

オブジェクト指向

ドメイン駆動設計では、実績のある既存の手法を活用します。

特に、モデル駆動開発、オブジェクト指向、アジャイル開発です。

ドメイン駆動設計において、オブジェクト指向モデリングやオブジェクト指向プログラミングは必須ではありません。

しかし、実績やモデル駆動開発との相性を考えると、事実上必須のパラダイムと言えます。

ドメインモデルのモデリングやプログラミングに、オブジェクト指向を活用します。

もちろん、ドメインモデル以外のビュー層やインフラストラクチャ層などにも適用します。

[目次に戻る]

モデル駆動開発

モデル駆動開発 (Model-Driven Development, MDD) は、 OMG (Object Management Group) が提唱するモデル駆動アーキテクチャ (Model-Driven Architecture, MDA) に則ったソフトウェア開発手法です。

MDDでは、分析・設計・実装・テストといった開発の成果をモデルとして作成し、 モデル変換を繰り返すことでアプリケーションを開発 (実装ソースコードを自動生成) する手法です。

ドメイン駆動設計では、分析モデルと設計モデルといった分け方はしません。両方の目的で使える唯一のモデルを作成します。

分析モデルと設計モデルを分けて作成すると、担当者や工程でモデルが分離されたり、実装と乖離してしまうことがあります。

ドメイン駆動設計では、このような分断をしないで、1つのモデルだけを作成して、そのモデルと一致した実装を行います。

モデルは、ドメインに存在する概念やドメインエキスパートが使う言葉などを、ソフトウェア設計の土台にできるように整理したものです。

[目次に戻る]

アジャイル開発

ドメイン駆動設計はイテレーティブな開発を基本としています。

ウォータフォール的な発想や計画では、ドメイン駆動設計は成功しないでしょう。

また、最初から多くのプラクティスやパターンを取り入れて、うまく実践できたという事例も稀でしょう。

パターンやプラクティスを段階的に取り入れながら、ドメインモデルを高度化し深化させていく、アジャイルな開発スタイルです。

同様に、ドメイン駆動設計スキルも段階的に向上させていければよいわけです。

※ 本記事では、アジャイル開発とイテレーティブ開発、反復型開発を区別しないで混用します。

[目次に戻る]

アナリシスパターン

マーチン・ファウラー氏の著書「アナリシスパターン」には、再利用可能なオブジェクトモデルがパターンとして示されています。 これらのオブジェクトモデルは、例題となった業務 (ドメイン) だけでなく、他のドメインにも適用できるものです。 自分たちのアプリケーションのドメインモデルとして、そのまま適用できなかったとしても、 ドメインモデルを作成するときの貴重な手本になるでしょう。 アナリシスパターンで示されているパターンは、よく洗練されたものであり、深いモデルです。 時として、深すぎて難しく感じるものも少なくないかもしれませんが、 深さのレベルを少し落として取り入れたり、ドメインモデリングのヒントにするだけでも、とても有益なパターン集です。

[目次に戻る]

デザインパターン

GoFと呼ばれる4人による共著「オブジェクト指向における再利用のためのデザインパターン」では、 オブジェクト指向設計、実装に関する23個のパターンを示しています。 各パターンは主に次の4つに分類されます。

(1) 生成に関するパターン

(2) 構造に関するパターン

(3) 振る舞いに関するパターン

(4) マルチスレッドプログラミングに関するパターン

実装の観点からの設計パターンです。ドメイン駆動設計のドメインモデルを作成する際や、リファクタリングする際の有用な指針となるでしょう。そのまま適用できるケースも少なくないと思われます。 GoFとは、エーリヒ・ガンマ、リチャード・ヘルム、ラルフ・ジョンソン、ジョン・ブリシディースの4人です。

アナリシスパターンやデザインパターンを知ると、パターンを使いたくなりますが、パターンを使うことを優先しないように注意してください。

[目次に戻る]

Naked Objects パターン

ここで、ドメイン駆動設計に通じるコンセプトを持つ Naked Objects パターンを紹介します。

Naked Objects パターンでは、ドメイン駆動設計と同様に、ドメインモデルを中心に置きます。

アプリケーションを開発する時には、ドメインオブジェクトだけを作成します。

ユーザインタフェース層やデータアクセス層は、ドメインオブジェクトから自動で作成します。

十分に洗練され深化したドメインモデルがあれば、 ドメインモデルの各インタフェースをビューとしてユーザに公開するだけで、アプリケーションとして機能する、という考えです。

ドメインモデルの各インタフェースとは、サービスやクラスのメソッド、プロパティのことです。

ビューは、画面のことです。


「Naked Objects for .NET - 生産性の高い.NETフレームワーク- InfoQ」から引用します。

※引用:ここから

ユーザインタフェースのレイヤやデータアクセスのレイヤを書く必要がないだけでなく、naked objectsパターンは良いオブジェクトモデリングも促します。

なぜならドメインモデルのプロトタイプを直ちにエンドユーザが評価できるアプリケーションにすることができるからです。

これらのことを聞いた時にほとんどの人は、大規模で複雑なビジネスアプリケーションではおそらく有効でないだろう、という反応を示します。

※引用:ここまで

元記事の中で、大きなアプリケーションでの事例も紹介されています。


ドメイン駆動設計で行うリファクタリングの本質的な対象は、ドメインモデルです。

ドメインモデルのサービスやクラスのメソッド、プロパティを更新 (リファクタリング) すると、ユーザインタフェースのレイヤやデータアクセスのレイヤの変更も必要です。

それは、単純ですが、軽量ではありません。

単純ミスも起きやすい部分です。

ドメインモデルに集中できなくなることもあります。

本質的ではない部分を自動化することで、「naked objectsパターンは良いオブジェクトモデリングも促します。」


なお、本記事で紹介しました「自動生成ツール DDBuilder」は、 Naked Objects パターンにインスパイア (触発) されたものです。

[目次に戻る]

CRC (Class Responsibility Collaborator)

ドメイン駆動設計とは直接関係しませんが、オブジェクト指向分析ツールにCRCカードがあります。 CRCカードは、オブジェクトを発見するためのツールです。 また、オブジェクト指向の初学者のための演習用としても使用されます。 CRCでは、同じ大きさの小さなカード (主に紙のカード) を使用します。 1枚のカードにオブジェクトの候補を1つ記入し、クラス名、責務、協調者を記入します。 実際にオブジェクトの候補を挙げながら、その責務や、(責務を果たすために) 相互作用しなくてはならない協調者 (他のオブジェクト) を実際に書いてみることで、 オブジェクトの発見や、発見するためのアプローチを理解できます。 CRCでは、分析チームのメンバーや演習の参加者同士が、机上と口頭で相互作用してみて、候補に挙げたオブジェクトに正しい責務が割り当てられ、 期待する振る舞い (ユースケース) を実現できるか等を検証します。 ドメイン駆動設計においても、もし、ドメインオブジェクトの見つけ方で悩まれているならば、CRCカードを使ってみる価値があると思います。

[目次に戻る]