無限大な夢のあと

テニスとアニメが大好きな厨二病SEのブログ

「エリック・エヴァンズのドメイン駆動設計」を読んで(自分用メモ) 第2部 モデル駆動設計の構成要素(前半 4章-5章)

DDD導入研修の課題として、下記の書籍「エリック・エヴァンズのドメイン駆動設計」を読むことになりました。

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

本文章は上記の書籍を引用させて頂きます。


ただ漠然と読んでいるだけだと、頭を通りすぎていきそうなので、自分なりに要点や響いた箇所、メモを残しながら読んでいこうと思います。
「Domain-Drive Design Quickly」は約80ページしかありませんでしたが、こちらはボリュームが大きいので、覚悟しながら読もうと思います。

Kindle書籍からだとコピーできないため、簡単にまとめていきます。

☆第2部 モデル駆動設計の構成要素

・introduction

f:id:noimpslmtbrk:20160915132551p:plain

モデル駆動設計を構成する言語のナビゲーションマップとのことです。
まだ、中身の用語の定義が曖昧なままなので、ここは読んでいく上で何度も立ち戻りたい。


・第4章 ドメインを隔離する。

レイヤ化アーキテクチャ
f:id:noimpslmtbrk:20160915152220p:plain

・ユーザインタフェース(プレゼンテーション層)
 ユーザに情報を表示して、ユーザのコマンドを解釈する責務を負う。外部アクタは人間のユーザではなく、別のコンピュータシステムのこともある。


・アプリケーション層
 ソフト雨ケアが行うことになっている仕事を定義し、表現力豊かなドメインオブジェクトが問題を解決するように導く。このレイヤが責務を負う作業は、ビジネスにとって意味があるものか、あるいは他システムのアプリケーション層と相互作用するのに必要なものである。
 このレイヤは薄く保たれる。
 ビジネスルールや知識を含まず、やるべき作業を調整するだけで、実際の処理は、ドメインオブジェクトによって直下のレイヤで実行される共同作業に移譲する。ビジネスの状況を反映する状態は持たないが、ユーザやプログラムが行う作業の進捗を反映する状態を持つことはできる。


ドメイン
 ビジネスの概念と、ビジネスが置かれた状況に関する情報、およびビジネスルールを表す責務を負う。ビジネスの状況を反映する状態はここで制御され、使用されるが、それを格納するという技術的な詳細は、インフラストラクチャに移譲される。この層がビジネスソフトウェアの核心である。


・インフラストラクチャ層
 上位のレイヤを支える一般的な技術的機能を提供する。これには、アプリケーションのためのメッセージ送信、ドメインのための永続化、ユーザインターフェースのためのウィジェット層などがある。インフラストラクチャ層は、ここで示す4層間における相互作用のパターンも、アーキテクチャフレームワークを通じてサポートすることもある。


プロジェクトによっては、ユーザインタフェースそうとアプリケーション層を厳密に区別しないこともある。また、複数のインフラストラクチャ層を持つこともある。しかし、ドメイン層を分離して初めて、モデル駆動開発が可能になるのだ。

ここは各レイヤの説明と共に残しておく。

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

ここも実際に適用する際のメモとして、残しておく。

レイヤを関係づける

レイヤ同士は疎結合であるべきで、設計の依存関係は1方向にだけ向けられる。
上位のレイヤは下位のレイヤにある要素を直接使用した入り、操作したりできる。

下位のレイヤにあるオブジェクトが上方と通信が必要な場合は、コールバックやオブザーバといったようなレイヤ同士を関係づけるためのアーキテクチャーパターンである。

ここも原理原則ではあるが、メモ。

利口なUI「アンチパターン

アプリケーション処理をドメイン層から分離したくないパターン

■利点
・ 単純なアプリケーションの場合、生産性が高く、すぐに作れる。
・ それほど有能でない開発者でも、この方法ならほとんど訓練しないで仕事ができる。
・ 要求分析が不足していても、プロトタイプをユーザに公開し、その要望を満たすように製品を変更することで、問題を克服できる。
・ アプリケーションが互いに分離しているので、小さなモジュールの納品スケジュールは比較的正確に計画できる。単純な振る舞いを付け加えるようなシステムの拡張であれば、容易に対応できるだろう、
・ 関係データベースはうまく機能し、データレベルでの統合が実現される。
・ 4GL ツールが実にうまく機能する。
・ アプリケーションが引き継がれた場合、保守プログラムは自分が理解できない部分を素早く作り変えられる。変更による影響が、それぞれ特定のユーザインタフェースに限定されるからだ。

■欠点
・ アプリケーションの統合は困難で、データベースを経由させるしかない。
・ 振る舞いが再利用されることも、ビジネスの問題が抽象化されることもない。ビジネスルールは、適用先の操作それぞれで複製されることになる。
・ 迅速なプロトタイピングやイテレーションを行おうとしても、自然と限界に行き当たる。抽象化が欠けているために、リファクタリングの選択肢が制限されるからだ。
・ 複雑さによって、すぐに覆い尽くされてしまうので、成長しようとしても、単純なアプリケーションを追加することしかできない。より豊かな振る舞いが実現できるようになるといった、優雅な道は存在しない

Viewにロジックが混ざったみたいな状況のことを指しているということみたい。
ドメイン駆動設計とは反対の思想で大規模で複雑なものには採用するべきではない。


・第5章 ソフトウェアで表現されたモデル 

あるオブジェクトは、状態が異なったり、さらに別々の実装をまたいだ入りしたとしても追跡されるような、連続性と一意性を持ったものを表現しているのか?
それとも、他の何かの状態を記述する属性なのか?
これがエンティティと値オブジェクトとの基本的な区別である。
なんらかのパターンに従うオブジェクトを定義することで、そのオブジェクトは曖昧ではなくなり、強固な設計を行うための具体的な選択に向かう道筋が整えられる。

エンティティと値オブジェクトの話は、後でも説明は出ると思うけど、ここは押さえておく。

次に、ドメインの側面によっては、オブジェクトとしてよりも、アクションや操作として表現した方が明確になるものもある。
オブジェクト指向モデリングの伝統からやや外れるが、これらについてはサービスで表現して、操作を行う責務をエンティティや値オブジェクトに押し付けない方が適切であることも多い
サービスとは、要求に応じてクライアントのために行われる何かである。ソフトウェアの技術的なレイヤーには多くのサービスがある。また、サービスはドメインにも登場する。その際にモデル化されるのは、ソフトウェアが実行すべきことに対応し、状態には対応しないような活動だ。

まだここはピンとこない。

最後に、モジュールに議論することによって、設計上のあらゆる意志決定は、ドメインについてのなんらかの洞察によって動機付けられないければならないという点を強調する。
高凝集と低結合という考え方は、しばしば技術的な指標と考えられているが、概念そのものにも適用できる。モデル駆動設計においては、モジュールはモデルの一部であり、ドメインにおける概念を反映していなければならない。

ここは一旦メモ。

■関連
関連をもっと扱いやすくするには、少なくとも3つの方法がある。
1.関連をたどる方向を強制する。
2.限定子を付加して、多重度を効果的に減らす。
3.本質的ではない関連を除去する。

ここも一旦メモ。

■エンティティ(参照オブジェクト)

オブジェクトモデリングを行うと、我々はオブジェクトの属性に集中しがちだが、エンティティの根本的な概念は抽象的な連続性である。
この連続性はエンティティのライフサイクルを通じて続き、エンティティが多様な形を取っても変わることがない。

オブジェクトの中には、主要な定義が属性によってなされないものもある。そういうオブジェクトは同一性のつながりを表現するのであり、その同一性は、時間が経っても、異なる形で表現されても変わらない。そういうオブジェクトは属性が異なっていても、他のオブジェクトと一致しなければならないことがある。
また、あるオブジェクトは、同じ属性を持っていたとしても、他のオブジェクトと区別しなければならない。同一性を取り違えるとデータの破損につながりかねない。

同一性が一つのキーワードかな。

他方、モデル中の全てのオブジェクトが、意味のある同一性を持ったエンティティであるとは限らない。この問題を複雑にしているのは、オブジェクト指向言語が、あらゆるオブジェクトに「同一性」の演算を組み込んでいるという事実である。(Javaの=演算子など)
これはメモリ中の位置の比較やその他の仕組みによって実現される。その意味で、全てのオブジェクトインスタンスは同一性を持っている。
例えば、Javaの実行環境を作成するドメインや、リモートオブジェクトをローカルでキャッシュする技術的なフレームワークドメインであれば全てのオブジェクトインスタンスがまさにエンティティになるだろう。
しかし、この同一性の仕組みはほかのアプリケーションドメインでは意味をなさない。
同一性は、エンティティの持つ巧妙な意味のある属性であり、プログラミング言語の持つ自動化された機能は引き継げないのである。

最後の1文だけ頭に残しておく。

あるオブジェクトが属性ではなく、同一性によって識別されるのであれば、モデルでこのオブジェクトを定義する際には、その同一性を第一とすること。クラスの定義をシンプルに保ち、ライフサイクルの連続性と同一性に集中すること。クラスの定義をシンプルに保ち、ライフサイクルの連続性と同一性に集中すること。形式や履歴に関係なく、各オブジェクトを識別する手段を定義すること。オブジェクト同士を突き合わせる際に、属性を用いるよう求めてくる要件には注意すること。各オブジェクトに対して結果が一意となることが保証される操作を定義すること。これは一意であることが保証された記号を添えることで、おそらく実現できる。この識別手段は外部に由来する場合もあれば、システムによってシステムのために作成される任意の識別子の場合もあるが、モデルにおける同値性の区別とは一致しなければならない。モデルは同じものであるとうことが何を意味するかを定義しなければならない。

ライフサイクルの連続性というのが頭に?が浮かんでいる。

・エンティティをモデル化する。
オブジェクトをモデル化する時に、属性について考えるのは自然なことであり、その振る舞いについて考えることにも極めて重要だ。
しかし、エンティティにとって最も基本的な責務は、振る舞いが明確で予測可能になるよう、連続性を確立することである。
これが一番うまくいくのは、余計なものがない状態が保たれている時だ。
属性や振る舞いに集中するよりは、エンティティオブジェクトの定義を最も本質的な特徴にまで削ぎ落とすこと。

連続性を確立することというのが、いまいちピンとこない。
また、同一性のための操作を設計するというのは現実の問題と照らしわせると難しい。


■値オブジェクト(VALUE OBJECTS)

多くのオブジェクトには概念的な同一性がない。そういうオブジェクトは、物事の特徴を記述する。

モデルで最も目立つオブジェクトが、通常はエンティティであり、また各エンティティの同一性を追跡することが非常に重要であることから、あらゆるドメインオブジェクトに同一性を割り当てようと考えるのは自然なことである。実際、フレームワークの中には、あらゆるオブジェクトに一意のIDを割り当てるものもある。

エンティティの同一性を追跡するのは本質的なことだが、それ以外のオブジェクトに同一性を与えてしまうと、システムの性能を損なうことにアンリ、分析作業が増え、さらに、全てのオブジェクトの見た目が同じになってしまうことでモデルが台無しになりかねない。
ソフトウェア設計は、複雑さとの恒常的な戦いである。
特別な処理が必要な場所だけで行われるように、区別しなければならない。
しかし、このオブジェクトのカテゴリを、単に同一性のないものとみなしてしまうと、我々の使えるツールや語彙は大して増えない。
実のところ、これらのオブジェクトには、独自の特徴とモデルに対する独自の意味がある。これは物事を記述するオブジェクトなのだ。

あるオブジェクトが、ドメインにおける記述的な側面を表現し、概念的な同一性を守らない場合、そういうオブジェクトは値オブジェクトと呼ばれる。
値オブジェクトがインスタンス化される際に表現しようとするのは、何であるかだけが問題と成り、誰であるか、あるいはどれであるかは問われないような設計の要素である。

本書の中に例があったので、そこで何とか理解。

値オブジェクトは、しばしば、オブジェクト間のメッセージでパラメータとして渡される。一過性のことも多く、操作のために生成されては破棄される。
また、エンティティ(および他の値オブジェクト)の属性として使用される。人は同一性のあるエンティティとして、モデル化されるかもしれないが、その人の名前は値オブジェクトである。

あるモデル要素について、その属性しか関心の対象とならないのであれば、その要素を値オブジェクトとして分類すること。値オブジェクトに、自分が伝える属性の意味を表現させ、関係した機能を与えること。値オブジェクトを不変なものとして扱うこと。
同一性を与えず、エンティティを維持するために必要となる複雑な設計を避けること。

エンティティか値オブジェクトかを決めるための説明って感じ。

値オブジェクトを可変であることを許可する方が良い場合

・値が頻繁に変化する場合
・オブジェクトの生成や削除が高くつく場合
・置き換えによって(修正ではなく)クラスタリングが妨げられる場合(前述の例で説明)
・値が共有することがあまりない場合、またはクラスタリングを改良するためや他の技術的理由からそういう共有を見合わせる場合

今後、自分で設計するにあたってのメモ。

・値オブジェクトを含む関連を設計する

値オブジェクト同士の双方向の関連は完全に取り除くように試みること

ここはメモ。

■サービス

時には、単純に「物」とはできないこともある。
場合によっては、設計をできる限り明確にしつつ、実践的に進めて行くと、概念的にどのオブジェクトにも属さないような操作が含まれることがある。
強引に決着をつけるのではなく、問題領域にひかれる自然な輪郭に従って、モデルの中に明確にサービスを含めれば良い。

サービスの冒頭の説明

ドメインから生まれる概念の中には、オブジェクトしてモデル化すると不自然なものもある。
こうしたドメインで必要な機能をエンティティや値オブジェクトの責務として押し付けると、モデルに基づくオブジェクトの定義を歪めるか、意味のない不自然なオブジェクトを追加することになる。

サービスとは、モデルにおいて独立したインターフェースとして提供される操作で、エンティティと値オブジェクトのようには状態をカプセル化しない。
サービスは技術的なフレームワークでは一般的なパターンだが、ドメイン層にも適用できる。

サービスという名前は他のオブジェクトとの関係性を強調している。
エンティティや値オブジェクトとは異なり、純粋にクライアントに対して何が実行できるかという観点から定義されるのだ。
サービスは、実体よりも活動、つまり名詞よりも動詞にちなんで命名される傾向がある。

サービスは節度を持って使用すべきで、エンティティと値オブジェクトから全ての振る舞いを奪ってはならない。
しかし、実際に、操作が重要なドメインの概念なのであれば、サービスはモデル駆動設計の自然な一部を形成する。

サービスとはモデルを持たない振る舞いを持つもので、純粋にクライアントに対して何が実行できるかという観点から定義されるもの。

優れたサービスには3つの特徴がある
1. 操作がドメインの概念に関係しており、その概念がエンティティや値オブジェクトの自然な一部ではない。
2.ドメインモデルの他の要素の観点からインターフェースが定義されている。
3.操作に状態がない。

ここで状態がないというのは、どのクライアントでも得てのサービスのインスタンスを使うにあたって、インスタンスの持つ個々の履歴を気にする必要がない。という意味である。
サービスを実行すると、グルーバルにアクセス可能な情報を使用し、そのグローバルな情報を変更することもあるかもしれません。(つまり副作用がある。)
しかし、ほとんどのドメインオブジェクトが持っているような、オブジェクトの内部にあって、自身の振る舞いに影響を与える状態は、サービスには存在しない。

ドメインにおける重要なプロセスや変換処理が、エンティティや値オブジェクトの自然な責務ではない場合、その操作はサービスとして宣言される独立したインターフェースとしてモデルに追加すること。
モデルの言語を用いて、インターフェースを定義し、操作名が必ずユビキタス言語の一部になるようにすること。
サービスには状態を持たせないこと。

うん、何となくわかってきた。

・サービスと隔離されたドメイン
このパターンは、ドメインにおいてそれ自体が重要な意味を持つサービスに焦点を絞っているが、もちろん、サービスはドメイン層だけで使用されるのではない。
ドメイン層に属するサービスを他のレイヤーから区別することと、その区別をはっきり保つように責務を分解することには、注意が必要である。

多くのドメインサービスやアプリケーションサービスは、エンティティと値オブジェクトで構成される集合体の上に構築され、ドメインに本来備わっている能力をまとめあげて、実際に何らかの処理を行うスクリプトのように振る舞う。

ドメイン層だけで使用されるものではないこともメモ。

・粒度
このパターンの議論では、概念をサービスとしてモデル化することで得られる表現力を強調しているが、このパターンはクライアントをエンティティと値オブジェクトから分離する手段としても、ドメイン層のインターフェースの粒度を制御する手段としても価値がある。

中粒度で状態を持たないサービスは、巨大なシステムで再利用しやすい。
これは、重要な機能をシンプルなインターフェースの後ろにカプセル化しているためだ。
また、細粒度のオブジェクトは、分散システムにおいては、非効率的なメッセージングにつながるかもしれない。

前述した通り、細粒度のドメインオブジェクトを用いると、ドメイン層からアプリケーション層は、ドメインオブジェクトの振る舞いが組み合わされる場所だからだ。
極めて詳細なレベルでの相互作用が複雑であるため、結局アプリケーション層で処理されることになり、ドメインの知識がアプリケーションやユーザインタフェースコードに這い出るのを許して、その知識はドメイン層から失われてしまう。
ドメインサービスを慎重に導入すれば、複数のレイヤ間で境界を鮮明に維持できる。
このパターンでは、クライアントの操作や用途の広さよりも、インタフェースの単純さが優先される。
また、このパターンより、巨大なシステムや分散システムでコンポーネントをパッケージングするのに、非常に便利な中粒度の機能が提供される。
そして、サービスが、ドメインの概念を表現するのに最も自然な方法であることもある。

中粒度で定義されるべきって感じで良いかな?
ここは何度も自分で設計して経験していかないと実感していけない。


■モジュール(パッケージ)

モジュールを選択する際には、システムに関する物語を伝え、概念の凝集した集合を含んでいるものを選ぶこと。
こうすることで、モジュール間は低結合になることが多い。

モジュールには、ユビキタス言語の一部になる名前をつけること。
モジュールとその名前はドメインに対する洞察を反映していなければならない

当たり前のことだけど、低結合、高凝集がキーワード。

大量のリファクタリングを行う開発者でも、プロジェクトの初期に考え出したモジュールで満足する傾向にある。

今後、ここを見直すというのも視野に入れていこう。

・インフラストラクチャ駆動パッケージングの落とし穴
ティア化アーキテクチャーでは、モデルオブジェクトの実装が断片化されるかもしれない。

別々のサーバにコードを分散させようという意図が実際にない限り、単一の概念オブジェクトを実装するコードは全て、同一のオブジェクトにならなくても、同一のモジュールにまとめること。

ドメイン層を他のコードから分離するためにパッケージングを使用すること。そうでなければ、ドメインの開発者にできる限り選択の余地を残し、モデルと設計上の選択をサポートするように、ドメインオブジェクトをパッケージングできるようにすること。

ティア化とは、責務が断片化された状態のこと。
中規模Web開発のためのMVC分割とレイヤアーキテクチャ - Qiita


モデリングパラダイム

オブジェクト指向が主流になっているシステムに、非オブジェクトの要素を混ぜ合わせるための経験則を4つあげよう。
・実装パラダイムと対立しないこと
  ドメインに関する別の考えは常にある。パラダイムに合うモデルの概念を見つけること。
ユビキタス言語に頼ること
ツール間に厳格なつながりがない場合でも、言語を一貫して使用すれば、設計の各部分が分かれて行ってしまうことはない。
UMLにこだわらないこと
UML図のようなツールに固執すると、容易に描けるものに合わせてモデルがゆがめられることがある。
 例えば、UMLには制約を表現する機能が確かにあるが、常にそれで十分とは限らない。
 別の作図スタイル(他のパラダイムでは一般的かもしれない)を選んだり、単純な自然言語で記述したりした方が、オブジェクトの特定の見方を示すことを意図された作図スタイルを、無理に適合させるよりは良い。
・懐疑であること
 ツールは本当に相応の働きをしているか?ルールがあるからといって、ルールエンジンを使うオーバーヘッドが必要とは限らない。
 ルールは多少わかりにくくはなるにしても、オブジェクトとして表現できるが、パラダイムを複数持つことで、事態は極めて複雑になるのだ。

ここはメモ。


脳が疲れる泣

続いて、第2部 モデル駆動設計の構成要素(後半 6章-7章) 頑張ります。

アナリシスパターン―再利用可能なオブジェクトモデル (Object Technology Series)

アナリシスパターン―再利用可能なオブジェクトモデル (Object Technology Series)

  • 作者: マーチンファウラー,Martin Fowler,堀内一,友野晶夫,児玉公信,大脇文雄
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2002/04
  • メディア: 単行本
  • 購入: 7人 クリック: 89回
  • この商品を含むブログ (70件) を見る
実践ドメイン駆動設計 (Object Oriented SELECTION)

実践ドメイン駆動設計 (Object Oriented SELECTION)

ドメイン駆動 (Programmer’s SELECTION)

ドメイン駆動 (Programmer’s SELECTION)

ビジネスパターンによるモデル駆動設計

ビジネスパターンによるモデル駆動設計