Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
エリック・エヴァンスのドメイン駆動設計_読書メモ

1. ドメインモデルを機能させる

ドメインモデルとは特定の図ではなく、図が伝えようとしている考え方
ドメインエキスパートの頭の中にある単なる知識ではなく、その知識が厳密に構成され、選び抜かれて抽象化されたもの
ドメイン駆動設計では、次に示すモデルの3つの基本的用法によって、どのモデルを選択するかが決定される

  • モデルと設計の核心が相互に形成し合う
  • モデルは、チームメンバ全員が使用する言語の基盤である
  • モデルとは、蒸留された知識である

Chapter1. 知識を噛み砕く

知識の噛み砕き

有能なドメインモデラは知識を噛み砕く

知識の噛み砕きは一人で行う作業ではない
開発者とドメインエキスパートからなるチームが共同して行うもので、たいていは開発者が率いる

チームメンバ間のやりとりは、メンバ是認がモデルを一緒に噛み砕くことで変化する
ドメインモデルを絶えず改良すると、開発者は、自分が力を貸しているビジネスにおける重要な原理を習得するように強いられ、機械的に機能を作り出すことがなくなる
一方、ドメインエキスパートは、自分の知っていることを蒸留して本質を抽出するように強いられることによって、しばしば自分の理解を精緻にし、ソフトウェアプロジェクトが必要とする概念の正確さを理解するようになる

継続的学習

ソフトウェアを書き始める時、我々は対象を十分に理解しているわけではない

高度に生産的なチームは、自分たちの知識を意識的に育てて、継続的学習を実践する
開発者にとって、これが意味するのは、一般的なドメインモデリングのスキルと合わせて、技術的な知識を向上させるということだ
ただし、その時に取り組んでいる具体的なドメインについて真剣に学習することも、ここに含まれる
こうして自ら学んだチームメンバは、もっとも重要な領域を含む開発作業に集中するにあたって、メンバの中で信頼できるコアとなる
このコアチームの頭の中に知識が蓄積されることで、彼らは知識をうまく噛み砕けるようになる

知識豊富な設計

より明示的な設計には、次のような利点がある

  • プログラマやその他の関係者の誰もが、複雑な計算処理等を、明確な重要なビジネスルールだと理解するようになる
  • プログラマはビジネスエキスパートに技術的な成果物を見せることができる
    • こうした成果物は、ドメインエキスパートに(開発者の手助けがあれば)理解できるはずで、それによってフィードバックループが完結する

深いモデル

役に立つモデルがすぐに見つかる表層にあることは滅多にない
ドメインとアプリケーションがやるべきことを我々が理解するようになるにつれて、たいていの場合、表層にあり最初は重要と思われたモデル要素を破棄するか、それらのモデル要素を違った視点で見ることになる すると、最初は考えつかなかった、それでいて問題の核心をつくようなうまい抽象があらわれてくる

知識の噛み砕きは探究だから、最終的にどこに行き着くかはわからない(!)

Chapter2. コミュニケーションと言語の使い方

ユビキタス言語(UBIQUITOUS LANGUAGE)

ドメインモデルを取り巻いて構築され、チームのあらゆる活動をソフトウェアと結びつけるために、チームメンバ全員によって使用される言語のこと

問題の要約:

言語に亀裂があると、プロジェクトは深刻な問題に直面する
ドメインエキスパートが自分たちの専門用語を使用するのに対して、技術チームのメンバも独自の言語を持っている
この言語は、設計の観点からドメインを議論するために調整されたものだ

日々の議論で使う用語法が、コードに埋め込まれる用語法から切り離されている(だが、コードはソフトウェアプロジェクトにおいて最終的にもっとも重要な成果物である)
同一人物でさえ話し言葉と書き言葉で違いがあるので、ドメインについてのもっとも鋭い表現は、たいてい一時的な形でしか現れず、コードや文章では捉えられることがない

通訳はコミュニケーションを鈍らせ、知識の噛み砕きを沈滞させる

しかも、これらの方言はどれも共通語になれない
どの方言も全ての要求には応えられないからだ

解決策の要約:

モデルを言語の骨格として使用すること
チーム内の全てのコミュニケーションとコードにおいて、その言語を厳格に用いることを、チームに約束させること
図やドキュメント、そして何より会話の中では同一の言語を使用すること

言語を使う上で問題があれば、代わりの表現を用いて実験することで、問題を取り除くこと
そうした表現は代わりとなるモデルを反映している
そこで、新しいモデルに合わせてコードをリファクタリングし、クラス、メソッド、モジュールの名前を変更すること
会話の中で用語が混同されていたら、普通の単語の意味について認識を合わせるのと同じやり方で解決すること

ユビキタス言語における変更は、モデルに対する変更であると認識すること

ドメインエキスパートは、ドメインについての理解を伝えるには使いにくかったり不適切だったりする用語や構造には意義を唱えるべきであり、開発者は、設計を妨害することになる曖昧さや不整合に目を光らせるべきである

声に出してモデリングする

モデルを改良する最適な方法の一つは、話してみることだ
考えられるモデルのバリエーションから生じる様々な概念を、声に出して構成してみる
荒削りな表現は聞けばすぐにわかる

  • 悪い例・・・経路サービスに荷受け地と荷出し地及び到着時間を与えた場合、それが貨物に必要な停泊箇所を調べて、ええと、それらをデータベースに入れておけばいい
  • 良い例・・・経路選択サービスは、経路仕様を満たしている輸送日程を見つける

システムについて語る際には、モデルを色々と試してみること
モデルの要素と相互作用を使い、モデルに許された方法で概念を結びつけながら、シナリオを声に出して描写すること
表現すべきことをより簡単に言う方法を見つけ、その新しい考え方を図とコードに再び反映させること

1つのチームに1つの言語

ドメインエキスパートとは関係ない設計上の技術的なコンポーネントはあるが、モデルのコアは、彼らの関心を引くべきである
豊富な知識を持つドメインエキスパートがモデルを理解できないとしたら、モデルに何か問題がある

ドメインエキスパートが、開発者との議論や、自分たちの中での議論にユビキタス言語を使用すると、モデルが自分たちの要求を満たすのに不十分であったり、誤っていると思われたりする領域を素早く発見する
また、モデルに基づく言語が厳密であるため、ドメインエキスパートは(開発者の手を借りて)、自分たちの思考の矛盾や曖昧さが明らかにされる領域があることにも気づく

ドキュメントと図

図の目的は、モデルについてコミュニケーションし、説明するのを助けることにある
図を注意深く選び抜いて構築すれば、意識を集中して話を進めるのに役立つ
ドキュメントを評価するための一般的な指針を2つ提案する

  • ドキュメントはコードや会話での表現を補わなければならない
    • すでにコードがうまくやっていることを、ドキュメントでもやろうとすべきではない
    • 書かれたドキュメントは、コードと会話を補足するべきである
  • ドキュメントは活動の役に立たなければならず、最新の状態を保たなければならない

Chapter3. モデルと実装を結びつける

モデル駆動設計(MODEL-DRIVEN DESIGN)

ソフトウェア要素のサブセットがモデル要素と密接に対応している設計
また、相互に一致した状態を保ちながら、モデルと実装を共に開発するプロセス

問題の要約:

設計が、あるいは設計の中心となる部分が、ドメインモデルに紐づいていないならば、そのモデルにほとんど価値はなく、ソフトウェアが正確であるかどうかも疑わしい
同じように、モデルと設計された機能との紐づけが複雑だと理解するのが難しく、実際には、設計が変更された時に紐づけを維持できなくなる
分析と設計の間に致命的な亀裂が生じるため、それぞれの作業で得られる洞察は互いに生かされることがないのだ

解決策の要約:

ソフトウェアシステムの一部を設計する際には、紐付けが明らかになるように、ドメインモデルを文字通りの意味で忠実に反映させること
モデルについて再検討し、より自然にソフトウェアに実装されるように修正すること
これは、ドメインに対するより深い洞察を反映させようとする時にも言える
強固なユビキタス言語を支えることに加えて、ドメインと実装両方の目的に使える単一のモデルを要求すること

設計で使用する用語法と責務の基礎的な割り当てをモデルから引き出すこと
コードはモデルの表現となるから、コードに対する変更はモデルに対する変更になるかもしれない
その影響は、プロジェクトの他の活動全体へと適宜伝わっていかなければならない

実装を一分の狂いもなくモデルに結びつけるには、通常、オブジェクト志向プログラミングのようなモデリングパラダイムをサポートする、ソフトウェア開発のためのツールと言語が必要である

骨格を見せる:なぜモデルがユーザにとって重要なのか?

設計に基づくモデルが、ユーザとドメインエキスパートの基本的な関心ごとを反映していれば、他の設計アプローチを用いた場合に比べて、その設計の骨格をよりはっきりとユーザにさらけ出すことができる
モデルが明らかになれば、ユーザはソフトウェアの潜在能力にもっと触れられるようになり、振る舞いは一貫した予測可能なものになる

実践的モデラ(HANDS ON MODELERS)

問題の要約:

コードを作成する人々がモデルに責任を感じていない場合や、アプリケーションのためにモデルを機能させる方法を理解していない場合、そのモデルはソフトウェアと無関係になってしまう
コードを変更するとモデルも変わることを、開発者が認識していない場合は、開発者によりリファクタリングによって、モデルは力を増すことなく、むしろ力を失うことになる
一方、モデラが実装プロセスから切り離されている場合、実装に伴う制約に対する感覚を、モデラは習得することがないか、できてもすぐに失ってしまう
モデル駆動設計においては、モデルが、効果的な実装を支えながら、ドメインについての主要な知識を抽象化する
だがこのような場合には、その基本的な制約の半分は失われ、結果としてできるモデルは実用的ではなくなる
最後に、仕事が分割されることで、モデル駆動設計のコーディングに伴う機微を伝えるような共同作業が妨げられてしまうと、熟練の設計者が持つ知識とスキルが、他の開発者に伝達されることがなくなってしまう

解決策の要約:

モデルに貢献する技術的な人は誰でも、一定の時間をコードに触れることに費やさなければならない
プロジェクトで主に果たしている役割がなんであれ、そうしなければならないのだ
コードの変更に対して責任を負う人は誰でも、コードを通してモデルを表現することを習得しなければならない
全ての開発者は、モデルに対する議論にいずれかの段階で参加して、ドメインエキスパートと話をしなければならない
その他の方法で寄与する人々は、ユビキタス言語を通じてモデルに対する考え方をダイナミックに交換する際に、コードに触れる人々を意識して巻き込まなければならない

2. モデル駆動設計の構成要素

Chapter4. ドメインを隔離する

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

ソフトウェアシステムの関心ごとを切り離し、ドメイン層を他から分離するテクニックのこと

問題の要約:

オブジェクト志向プログラミングでは、ユーザインタフェース(UI)、データベースおよびその他の補助的なコードが、ビジネスオブジェクトに直接書かれることはしばしばある
また、ビジネスロジックが新たに追加される時には、UIウィジェットやデータベーススクリプトの振る舞いに組み込まれてしまう
こういうことが起きるのは、短期的にみると、動くようにするには最も簡単な方法だからだ

ドメイン関連のコードがそうした膨大な他のコードの中に拡散してしまうと、コードを見て意味を理解するのが極めて困難になる
ユーザインタフェースに対する表面的な変更が、実はビジネスロジックを変更することもある
ビジネスルールを変更するために、ユーザインタフェースコードやデータベースコード、その他のプログラム要素を丹念に追跡しなければならないかもしれない
これでは、凝集度の高いモデル駆動のオブジェクトを実装することが現実的ではなくなる
また、自動化されたテストはぎこちないものになってしまう
全ての技術とロジックがそれぞれの活動に関係しているので、プログラムを非常にシンプルに保たなければ、理解できなくなってしまう

解決策の要約:

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

うまくいっているアーキテクチャのほとんどは、以下に示すレイヤを基にしている

  • ユーザインタフェース(またはプレゼンテーション)層・・・ユーザに情報を表示して、ユーザのコマンドを解釈する責務を負う(Controllerとか)
  • アプリケーション層・・・ソフトウェアが行うことになっている仕事を定義し、表現力豊かなドメインオブジェクトが問題を解決するように導く
  • ドメイン(またはモデル)層・・・ビジネスの概念と、ビジネスが置かれた状況に関する情報、およびビジネスルールを表す責務を負う
  • インフラストラクチャ層・・・上位のレイヤを支える一般的な機能を提供する(DBへの永続化とか)

ドメインはモデルが息づく場所

ドメインモデルは概念の集合である
「ドメイン層」は、モデルと、モデルに直接関係する設計上の全ての要素が現れる場所である
ビジネスロジックの設計と実装によって、ドメイン層が構成される
そして、モデル駆動設計においては、モデルの概念を映し出すドメイン層によって、ソフトウェアが構成される

ドメインの実装を隔離することは、ドメイン駆動設計の必要条件

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

問題の要約:

洗練されていないチームが、単純なプロジェクトを担当するに当たって、レイヤ化アーキテクチャを伴うモデル駆動設計に挑戦しようとすると、習得の難しさに苦労することになる
チームメンバは複雑な新しい技術を習得し、オブジェクトモデリングを学ぶ過程を、躓きながら通らなければならない
インフラストラクチャと各レイヤを管理するオーバヘッドにより、非常に単純な作業にも、より時間がかかる
単純なプロジェクトはたいていスケジュールが短く、期待も控えめである
チームが割り当てられた作業を完了させるよりもはるか前、ましてやこのアプローチの持つ刺激的な可能性を実演するよりも前に、プロジェクトはキャンセルされることになるだろう

チームにもっと時間が与えられたとしても、チームメンバは、専門家の手を借りなければ、この技術を習得できそうもない
最終的に、これらの難題を本当に克服したとしても、作られるのは単純なシステムである
豊富な機能が望まれることはない

解決策の要約:

全てのビジネスロジックをユーザインタフェースに入れること
アプリケーションを小さな機能に切り刻み、それを独立したユーザインタフェースとして実装し、ビジネスルールもその中に埋め込むこと
関係データベースを、データの共有リポジトリとして使用すること
ユーザインタフェースの構築と視覚的なプログラミングのためのツールについては、手に入る中で最も自動化が進んでいるものを使用すること

その他の隔離

例えば、 Fowler が提唱するトランザクションスクリプト(TRANSACTION SCRIPT)がある
ユーザインタフェースをアプリケーションから分離はするが、オブジェクトモデルは提供しない、というパターン

Chapter5. ソフトウェアで表現されたモデル

エンティティと値オブジェクトを区別すること

  • エンティティ・・・状態が異なったり、さらに別々の実装を跨いだとしても追跡されるような、連続性と一意性を持ったものを表現している
  • 値オブジェクト・・・他の何らかの状態を記述する属性である

関連

関連をもっと扱いやすいするには、少なくとも3つの方法がある

  • 関連を辿る方向を強制する
  • 限定子を付加して、多重度を効果的に減らす
  • 本質的ではない関連を除去する

エンティティ(ENTITIES)

本質的に、属性によってではなく、連続性と同一性の連なりによって定義されるオブジェクト

問題の要約:

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

解決策の要約:

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

値オブジェクト(VALUE OBJECTS)

ある特徴や属性を記述するが、同一性の概念を持たないオブジェクト

問題の要約:

エンティティの同一性を追跡するのは本質的なことだが、それ以外のオブジェクトに同一性を与えてしまうと、システムの性能を損なうことになり、分析作業が増え、さらに、全てのオブジェクトの見た目が同じになってしまうことでモデルが台無しになりかねない

ソフトウェア設計は、複雑さとの恒常的な戦いである
特別な処理が必要な場所だけで行われるように、区別しなければならない

しかし、このオブジェクトのカテゴリを、単に同一性のないものとみなしてしまうと、我々の使えるツールや語彙は大して増えない
実のところ、これらのオブジェクトには、独自の特徴とモデルに対する独自の意味がある
これは物事を記述するオブジェクトなのだ

解決策の要約:

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

サービス(SERVICES)

インタフェースとして提供される操作
このインタフェースはモデル内で独立していて、カプセル化された状態を持たない

問題の要約:

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

解決策の要約:

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

モジュール(MODULES)

問題の要約:

誰もがモジュールを使用するが、モデルのれっきとした一部として扱う人はほとんどいない
コードは技術的アーキテクチャの側面から開発者の仕事の分担に至るまで、あらゆるカテゴリに分類される
大量のリファクタリングを行う開発者でも、プロジェクトの初期に考え出したモジュールで満足する傾向がある

モジュール間では低結合、モジュール内では高凝集が必要なことは自明の理だ
結合と凝集について説明すると、技術的な指標のように聞こえがちで、関連と相互作用の分布に基づいて判断されやすい
しかし、モジュールに分割されるのはコードだけではない。概念も分割される
人が一度に考えられる物事の数には限りがあるし、首尾一貫していない思考の断片は、思考がバラバラに溶け合ったスープのようなもので、理解するのが難しい

解決策の要約:

モジュールを選択する際には、システムに関する物語を伝え、概念の業種した集合を含んでいるものを選ぶこと。こうすることで、モジュールは低結合になることが多い
だが、そうでない場合は、概念のもつれをほぐすようにモデルを変更する方法を探すか、意味のある方法で要素をまとめられるような、モジュールの基礎となる概念を見逃していないか模索すること
相互に独立して理解でき、理論づけることのできる概念という意味での低結合を実現するよう試みること
モデルがドメインの高次の概念にしたがって分割され、対応するコードも同じように分離されるようになるまで、モデルを改良すること

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

Chapter6. ドメインオブジェクトのライフサイクル

まず集約が、明確な所有権と境界を定義することで、モデルそれ自体を引き締める
こうすることで、オブジェクトのネットワークが混沌としてもつれたものになるのを避けられる

次に、焦点をライフサイクルの始まりに合わせ、ファクトリを利用して、複雑なオブジェクトや集約を生成したり再構成したりする
そうすることで、内部構造はカプセル化されたままとなる

最後に、リポジトリがライフサイクルの中期と終わりに対応して、永続化されたオブジェクトにアクセスする手段を提供しつつ、アクセスに伴って必要となる巨大なインフラストラクチャをカプセル化する

集約(AGGREGATES)

関連したオブジェクトの集合で、データを変更する目的で1つの単位として扱われるもの
外部から参照できるのは、集約でルートに指定されたメンバ1つに限られる
一貫性に関するルールの集合が、集約の境界内に適用される

問題の要約:

複雑な関連を伴うモデルでは、オブジェクトに対する変更の一貫性を保証するのは難しい
維持すべき不変条件には、個々のオブジェクトに適用されるものだけでなく、密接に関連するオブジェクトのグループに適用されるものもある
だが、慎重にロックしすぎると、今度は複数のユーザが指針もなく相互に干渉しあい、システムが使い物にならなくなる

解決策の要約:

エンティティと値オブジェクトを集約の中にまとめ、各集約の周囲に境界を定義すること
各集約に対してルートとなるエンティティを1つ選び、境界の内部に存在するオブジェクトへのアクセスは、そのルートを経由して制御すること
外部のオブジェクトが参照を保持できるのは、ルートのみとすること
内部のメンバに対する一時的な参照を渡して良いのは、単一の操作で使用するときだけだ
ルートがアクセスを制御するので、内部が知らないうちに変更されることはなくなる
この取り決めにより、どんな状態変化においても、集約内にあるオブジェクトと集約全体に対して、不変条件を全て強制することが現実的になる

ファクトリ(FACTORIES)

クライアントのために複雑な生成ロジックをカプセル化し、生成されたオブジェクトの型を抽象化するための仕組み

問題の要約:

オブジェクトの生成は、それ自体が主要な操作になりうるが、複雑な組み立て操作は、生成されるオブジェクトの責務には合わない
そういう責務を組み合わせてしまうと、理解しにくく不恰好な設計が作り出されるかもしれない
そうかといって、クライアントに直接構築させると、クライアントの設計を混乱させ、組み立てられるオブジェクトや集約のカプセル化にも違反する上に、生成されるオブジェクトの実装とクライアントが過度に結合することになる

解決策の要約:

複雑なオブジェクトと集約のインスタンスを生成する責務を、別のオブジェクトに移すこと
その別のオブジェクトは、それ自体ではドメインモデルにおいて何の責務も負っていないかもしれないが、それでもドメイン設計の一部であることには変わりはない
複雑な組み立てを全てカプセル化するインタフェースを提供すること
その際に、インスタンス化されるオブジェクトの具象クラスを、クライアントが参照しなくても良いようにすること
集約全体をひとまとまりとして生成し、その不変条件を強制すること

リポジトリ(REPOSITORIES)

格納、取り出し、及び検索の振る舞いをカプセル化し、オブジェクトのコレクションをエミュレートする仕組み

問題の要約:

永続化されたオブジェクトのサブセットの中には、オブジェクトの属性に基づいた検索を通じて、グローバルにアクセスできなければならないものもある
そういうアクセスを必要とするのは、集約のルートのうち、関連を辿って到達しようとすると都合の悪いものだ
こうした集約ルートは通常エンティティだが、複雑な内部構造を持つ値オブジェクトのこともあれば、列挙された値のこともある
集約ルート以外のオブジェクトにグローバルなアクセスを提供してしまうと、重要な区別が台無しになる
データベースクエリを自由に行うと、実はドメインオブジェクトと集約のカプセル化に違反しかねないのだ
技術的なインフラストラクチャやデータベースアクセスの仕組みを露呈させてしまうと、クライアントが複雑になり、モデル駆動設計が不明瞭になってしまう

解決策の要約:

グローバルアクセスを必要とするオブジェクトの各型に対して、あるオブジェクトを生成し、その型の全てのオブジェクトで構成されるコレクションが、メモリ上にあると錯覚させることができるようにすること
よく知られているグローバルインタフェースを経由してアクセスできるようにすること
オブジェクトの追加と削除を行うメソッドを提供し、データストアにおける実際のデータの挿入や削除をカプセル化すること
また、ある条件に基づいてオブジェクトを選択し、属性値が条件に一致するような、完全にインスタンス化されたオブジェクトかオブジェクトのコレクションを戻すメソッドを提供すること
それによって、実際のストレージや問い合わせの技術をカプセル化すること
実際に直接的なアクセスを必要とする集約ルートに対してのみ、リポジトリを提供すること
クライアントをモデルに集中させ、あらゆるオブジェクトの格納とアクセスをリポジトリに移譲すること

Chapter7. 言語を使用する:応用例

省略

3. より深い洞察へ向かうリファクタリング

深いモデルは、ドメインエキスパートの主要な関心ごとと、それにもっとも深く関連した知識に関する明快な表現を提供するが、一方で、ドメインの表面的な側面は捨て去る

Chapter8. ブレイクスルー

継続的なリファクタリングをすることによって、より不規則なものが生まれてくる土壌が整えられる
コードとモデルを改良するたびに、開発者の視界は明確になってくる
視界が明確になったことにより、洞察のブレイクスルーをもたらす可能性が作り出される
立て続けに変更が行われた結果として現れるモデルは、実際に起きていることやユーザが重要視するものと、より深いレベルで一致する
複雑なが消滅するまさにその時に、用途の広さや説明する力が急激に増大する

この種のブレイクスルーは、テクニックではなく、出来事である

ブレイクスルーの舞台を整える為に必要なことは以下の通り

  • 知識を噛み砕き、強固なユビキタス言語を育成するのに集中すること
  • 重要なドメインの概念を探求して、それをモデルで明示すること
  • 設計をよりしなやかになるように改良すること
  • モデルを蒸留すること

Chapter9. 暗黙的な概念を明示的にする

ドメインモデルとそれに対応したコードが大きく変化するのは、議論で示唆されたり、設計の中に暗に存在したりする概念に開発者が気づき、それを1つあるいは複数のオブジェクトや関係性を使って、モデルの中で明示的に表現した時である

概念を掘り出す

ドメインエキスパートの使う言葉に耳を傾けること
以下は、モデルにとって有益になりうる概念を示す手掛かりである

  • 何か複雑なものを簡潔に述べている用語がないだろうか?
  • ドメインエキスパートに言葉の選び方を(たぶん、角が立たないように)正されていないか?
  • あなたが特定のフレーズを使った時に、ドメインエキスパートたちの困惑した表情が消えることはないか?

仕様(SPECIFICATION)

問題の要約:

ビジネスルールは、明らかなエンティティや値オブジェクトの責務のどれとも合致しないことがしばしばあり、その多様性と組み合わせによって、ドメインオブジェクトの基本的な意味を圧倒しかねない
しかし、ルールをドメイン層から取り出してしまうのはさらに悪い
ドメインコードがモデルを表現しなくなってしまうからである

論理プログラミングは、「述語」と呼ばれる、独立した結合可能なルールオブジェクトの概念を提供するが、この概念をオブジェクトで完全に実装するのは面倒である
また、あまりにも一般的なため、より特殊な設計と同様に、多くの意図を伝えることもない

解決策の要約:

特殊な目的を持った述語的な値オブジェクトを明示的に作成すること
仕様とは、あるオブジェクトが何らかの基準を満たしているかどうかを判定する述語である

仕様の価値の多くは、全く異なるように見えるアプリケーションの機能を統一することにある
以下に挙げる3つの目的のうち、1つでも当てはまれば、オブジェクトの状態を定義する必要があるだろう

  • オブジェクトを検証して、何らかの要求を満たしているか、何らかの目的のための用意ができているかを調べる
  • コレクションからオブジェクトを選択する(期限が超過した請求書を問い合わせる場合など)
  • 何かの要求に適合する新しいオブジェクトの生成を定義する

仕様パターンを適用することで、実装が異なってしまう場合でも、一貫性のあるモデルを使用できるようになる

Chapter10. しなやかな設計

深いモデルに本来備わっている力をクライアント開発者に渡し、明確で柔軟な表現をすることで、期待される結果を確固たるものにする設計のこと
また、しなやかな設計は、同じ深いモデルを利用することで、新しい洞察に設計を適合させるため、実装者が設計自体を作り直して新しい形にすることを容易にする

意図の明白なインタフェース(INTENTION-REVEALING INTERFACE)

クラス、メソッド、及びその他の要素の名称が、元々の開発者が作成した目的と、クライアント開発者に対して持つ価値の療法を伝えている設計

問題の要約:

ある開発者があるコンポーネントを使用するために、その実装についてじっくり考えなければならないのであれば、カプセル化の価値は失われる
元々そのコンポーネントを開発した人とは別の人がオブジェクトや操作の目的を推測する上で、実装を確認しなければならないとしたら、その新しい開発者は、操作やクラスが偶然満たしているだけのものを目的だと思ってしまうかもしれない
そうして推測された目的が本来の意図と異なっていたら、コードは、さしあたりは動くかもしれないが、設計の概念的な基盤が崩壊し、2人の開発者は互いに矛盾した目的に向けて仕事をすることになるだろう

解決策の要約:

クラスと操作には、その効果と目的を記述する名前をつけ、約束したことを実行する手段には言及しないこと
そうすることで、クライアント開発者はインタフェースの内部を理解しなくてよくなる
こうした名前はユビキタス言語に従っていなければならない
そうすることで、チームメンバがすぐ意味を理解できるようになるからだ
振る舞いを作成する前にテストを書いて、自分がクライアント開発者の視点で考えられるようにすること

副作用のない関数(SIDE-EFFECT-FREE-FUNCTIONS)

目に見える副作用なしに、処理をおこなって結果を戻す操作

問題の要約:

複数のルール間に存在する相互作用や、演算の合成は、予測するのが極端に困難になる
操作を呼び出す開発者は、結果を予測するために、呼び出し先の実装とそれが移譲する実装を全て理解しなければならない
開発者がインタフェースによって隠されたものを見る必要があるのだとしたら、そのインタフェースによる抽象化の効用は限定されてしまう
完全に予測できるように抽象化されていないと、開発者は組み合わせの爆発を制限しなければならなくなり、現実に構築できる振る舞いの豊かさを低く抑えることになる

解決策の要約:

プログラムロジックのうち、できる限り多くの部分を関数に置くこと
関数とは、目に見える副作用なしに結果を戻す操作である
コマンド(目に見える状態を変更することになるメソッド)は厳密に分離して、ドメインについての情報を戻さない、非常に単純な操作にすること
ある概念が、値オブジェクトの担う責務に合致する場合には、複雑なロジックをその値オブジェクトに移すことによって、副作用をさらに制御すること

表明(ASSERTIONS)

ある時点におけるプログラムの正しい状態を、どのようにそうなるかとは独立して表した文
表明は、操作の結果や設計要素の普遍条件を定義するのが通例である

問題の要約:

操作の副作用が実装によって暗黙的にしか定義されていない場合、移譲が多く行われている設計では、原因と結果がもつれてしまう
あるプログラムを理解するには、分岐したパスを辿って実行を追跡するしかない
カプセル化の価値は失われる
具体的な実行を追跡する必要があるせいで、抽象化も打ち負かされる

解決策の要約:

操作の事後条件と、クラス及び集約の不変条件を宣言すること
プログラミング言語で表明を直接コーディングできない場合は、その代わり、自動化されたユニットテストを書くこと
プロジェクトの開発プロセスのスタイルに合う場合には、表明をドキュメンテーションや図の中に記述すること

凝集した概念が集まったモデルを探し求めること
それも、意図された表明を開発者に推測させ、学習効率をあげながら、矛盾したコードが作られるリスクを小さくするものでなければならない

概念の輪郭(CONCEPTUAL CONTOURS)

ドメイン自体の根底にある一貫性
モデルに反映されれば、設計がさらに自然に変更に対応できるようになる

問題の要約:

モデルや設計の要素が一枚岩の構造に埋め込まれていると、機能は重複する
外部インタフェースは、クライアントが重要だと思うことを全て伝えるとは限らない
そのような要素の意味を理解するのは、様々な概念が混在しているため、難しい

その一方で、クラスやメソッドを分割すると、クライアントを無意味に複雑にしてしまうかもしれない
細々とした要素の組み合わせ方を理解することを、クライアントオブジェクトに矯正するからだ
さらに悪いことに、概念が完全に失われかねない
ウランの原子を半分に分けたら、それはウランではない
もちろん、重要なのは単なる粒度でなく、その粒がどこで活動するかである

解決策の要約:

設計要素(操作、インタフェース、クラス、集約)を凝集した単位に分割すること
その際、ドメインにおける重要な分割に対する自分の直感を考慮に入れること
連続的なリファクタリングを通して変化と安定の軸を観察し、設計の根底にある概念の輪郭の中で、こうした分割のパターンを説明しているものを探すこと
ドメインのもつ一貫したいくつかの側面の中には、そもそもモデルを知識の息づく領域にしているものがある
モデルを、そうした側面と揃えること

独立したクラス(STANDALONE CLASSES)

システムプリミティブと基本ライブラリを除き、他のクラスを参照することなく理解し、テストできるクラス

問題の要約:

1つのモジュールの中であっても、設計を解釈することは、依存関係が加わるにつれて無秩序に難しくなる
これによって精神的な負荷が大きくなり、開発者が処理できる設計の複雑さが制限される
暗黙的な概念の方が、明示的な参照よりも負荷を大きくする

解決策の要約:

低結合はオブジェクト設計の基本である
できる時には徹底的にやること
オブジェクトのイメージの中から他の概念を全て取り除くこと
そうすれば、クラスは完全に自己完結し、単独で調べて理解できるようになる
そういう自己完結型のクラスは、どれもモジュールを理解する際の負担を軽減してくれる

閉じた操作(CLOSURE OF OPERATIONS)

問題の要約:

たいていの興味深いブジェクトは、最終的に、プリミティブだけでは特徴づけることができない処理を実行することになる

解決策の要約:

戻り値の型が引数の型と同じにできる場合は、そのように操作を定義すること
実装クラスが処理で使われる状態を持っていれば、そのクラスは事実上操作の引数となるから、引数と戻り値は実装クラスと同じ型でなければならない
そういう操作は、その型のインスタンスの集合の下で閉じている
ある閉じた操作によって、他の概念への依存関係を導入することなく、高度なインタフェースが提供される

Chapter11. アナリシスパターンを適用する

アナリシスパターンとは、ビジネスモデリングにおける、共通の構造を表す概念グループのこと
ただ1つのドメインに関係することもあれば、多くのドメインにまたがることもある

Fowler が紹介しているアナリシスパターンは、当該する分野での経験を基にしている(ex.在庫管理と会計)ため、適切な状況で用いれば実践的
骨の折れるドメインに直面している人に対して、イテレーティブな開発プロセスを始めるにあたっての、非常に有益な出発点を提供する
アナリシスパターンは技術的な解決策ではなく、特定のドメインでモデルを考え出すのを支援する手引きである

Chapter12. デザインパターンをモデルに関係づける

ストラテジー(STRATEGY)

問題の要約:

ドメインモデルに含まれているプロセスの中には、技術的に動機づけられたものだけでなく、問題となっているドメインで、実際に意味を持つものもある
あるプロセスに対して、その代替となるものを提供しなければならないとすると、適切なプロセスを選択することに伴う複雑さは、複数のプロセス自体にある複雑さと相まって、手に負えなくなる

解決策の要約:

プロセスの中で変化する部分を、モデルの中で独立した「ストラテジー」オブジェクトに括り出すこと
ルールと、ルールが支配する振る舞いは、切り離して括り出すこと
そのようなルールや置き換え可能なプロセスは、ストラテジーデザインパターンにしたがって実装すること
ストラテジーオブジェクトの複数のバージョンは、プロセスを実行する上での様々な方法を表している

コンポジット(COMPOSITE)

問題の要約:

ネストされたコンテナの関係性がモデルに反映されていないと、共通する振る舞いを階層の各レベルで繰り返さなければならず、さらにネストに柔軟性がなくなる(例えば、コンテナは通常、自分のいるレベルにある他のコンテナを含むことができず、また、レベルの数は固定されている)
クライアントは、階層の様々なレベルを扱うにあたって別々のインタフェースを使わなければならない
こうした使い分けは、概念的な違いをクライアントが意識していなくても必要である
階層を再帰しながら集約された情報を作り出すのは、非常に入り組んだ処理である

解決策の要約:

コンポジットを構成する全てのメンバを包括的に含む抽象型を定義すること
情報を戻すメソッドはコンテナに実装され、内容についての集約された情報を戻す
「リーフ」ノードは、それぞれ独自の値に基づいて、それらのメソッドを実践する
クライアントは抽象型を扱えばよく、リーフとコンテナを区別する必要はない

Chapter13. より深い洞察へ向かうリファクタリング

開始

より深い洞察へ向かうリファクタリングは、様々な形で始められる

  • コードのもつ問題点、つまり複雑さやぎこちなさへの対応をスタート地点にする
  • リファクタリングに対する従来の見方から離れてみる
    • コードが整然として見えルガ、モデルの言語がドメインエキスパートと切り離されたように見える
    • 新しい要求が自然には適合しない
      • やはりドメインモデルが間違っているという認識が得られることもありうる
  • 同僚やドメインエキスパートとブレインストーミングしてみる
  • アナリシスパターンやデザインパターンに見られるような、本に書かれた体系的な知識を利用する

開発チーム

次の段階は、意図を明確かつ自然に伝達するようモデルを改良する方法を探し出すことである
新しいモデルを探求するには、より長い時間がかかり、より多くの人の参加が必要となる
具体的なプロセス(例)はこんな感じ

  • 変更を先導する人が、開発者数人を選び出す
    • 問題の中に繊細な箇所がある時には、必ずドメインエキスパートを参加させる
  • この4、5人のグループで会議室やコーヒーショップへ行き、30分から1時間半のブレインストーミングを行う
  • UML図をスケッチしたり、オブジェクトを使用してシナリオのウォークスルーを試したりする
  • 主題に関するエキスパートが、モデルを理解して役に立つと思っているかを確認する
  • 満足のいくものを見つけたら、席に戻ってコーディングする
    • あるいは、数日かけてじっくり考えることにして、戻って何か別の作業をする

このプロセスを生産的なものに保つ上で、いくつかポイントがある

  • 自主的な意思決定
  • スコープと休憩
  • ユビキタス言語の駆使

先達の技

車輪の再発明が常に必要とは限らない

  • ドメイン自体に関する文献やその他の情報源から着想を得る
  • 他者の経験をアナリシスパターンという形で利用する

タイミング

変更を完全に正当化できるまで待つのは、待ちすぎというものである

ほとんどのプロジェクトチームは依然として、コードの変更に対して慎重すぎる
コードを変更するリスクと、変更にかかる開発者の時間とコストを見込んでいるのが理由
一見理にかなっているが、もともと難しいものを必要以上に難しくして、リファクタリングを抑圧してしまう

より深い洞察に向かうためのリファクタリングは、ドメインの主題に関する継続的な探求、開発者の教育、さらに開発者とドメインエキスパートの間での合意などの一部にならなければならない
それゆえ、次の場合にはリファクタリングすること

  • 設計が、ドメインに関するチームの現在の理解を表現していない
  • 重要な概念が設計で暗黙的になっている(かつ、それを明示的にする方法がわかっている)
  • 設計において重要な部分を、よりしなやかにする好機がある

好機となる危機

より深い洞察へ向かうリファクタリングは、安定したものではない
モデルを安定して改良しているところで、突然ある洞察へと導かれ、それによってあらゆるものが刷新される

そうした状況は好機には見えないことが多く、むしろ危機のように捉えられる
突然、モデルの中に、明らかに不適切な部分があるとわかるのだ
モデルが表現できる内容に大きな穴が空いていたり、極めて重要な領域であるのにモデルが明瞭でなかったりする

このことが意味しているのは、チームが理解の新しいレベルに到達したということである
今や高められた視点から見れば、古いモデルは貧弱に見える
この視点であれば、はるかに優れたモデルを思いつくことができる

4. 戦略的設計

Chapter14. モデルの整合性を維持する

巨大なシステム向けのドメインモデルを完全に統一することは、現実的ではないし、コストにも見合わない
しかし、我々にできることがないわけではない
何を統一すべきかについての前向きな意思決定と、何を統一しないでおくかについての現実に即した認識を組み合わせることで、置かれている状況に関する明確な全体像を共有できる
この全体像があれば、確実に統一したい部分を統一する方向に向けつつ、統一しない部分のせいで混乱や破損が生じないようにすることに着手できる

境界づけられたコンテキスト(BOUNDED CONTEXT)

特定モデルを適用できる限定された範囲
コンテキストの境界を定めることで、チームメンバは何を一致させるべきで、何を独立して開発できるのかについての理解を明確化し、共有できる

問題の要約:

複数のモデルはどんな巨大なプロジェクトにも存在する
だが、別々のモデルに基づくコードが組み合わされると、ソフトウェアは、バグの温床となり、信頼できなくなり、理解しにくくなる
チームメンバ間のコミュニケーションは混乱し始める
あるモデルをどのコンテキストで適用すべきでないのかについては、ほとんどの場合不明瞭である

解決策の要約:

モデルが適用されるコンテキストを明示的に定義すること
明示的な境界は、チーム編成、そのアプリケーションに特有の部分がもつ用途、コードベースやデータベーススキーマなどの物理的な表現などの観点から設定すること
その境界内では、モデルを厳密に一貫性のあるものに保つこと
ただし、境界の外部の問題によって注意をそらされたり、混乱させられたりするのを避けること

継続的な統合(CONTINUOUS INTEGRATION)

問題の要約:

多くの人々が同一の境界づけられたコンテキストで作業していると、モデルが分裂する傾向は強くなる
チームが大きければ大きいほど、問題も大きくなるが、3、4人ほどの少人数でも深刻な問題に直面することがある
しかし、システムをさらに小さいコンテキストに分割してしまうと、結局は有益なレベルで統合し、一貫させることができなくなる

解決策の要約:

全てのコードと他の実装成果物を頻繁にマージさせるプロセスを策定すること
その際、分裂に対して素早く警告する自動化されたテストも一緒に用いること
ユビキタス言語の執拗な鍛錬を絶え間なく行い、モデルに対する共有された見方を練り上げること
概念は、別々の人の頭の中で進化していくからだ

コンテキストマップ(CONTEXT MAP)

プロジェクトに含まれる複数の境界づけられたコンテキストや、コンテキストとモデルの実際の関係を表現したもの

問題の要約:

他のチームに所属する人々は、コンテキストの境界をあまり意識せず、境目をぼかしたり相互の接続を複雑にしたりする変更を、そうとは知らずに加えるかもしれない
別々のコンテキスト同士を接続しなければならない場合、コンテキストは相互に滲み出す傾向がある

解決策の要約:

プロジェクトで機能しているモデルをそれぞれ識別して、その境界づけられたコンテキストを定義すること
これには、非オブジェクト指向のサブシステムにある暗黙的なモデルも含まれる
境界づけられたコンテキストそれぞれに名前をつけ、その名前をユビキタス言語の一部にすること

モデル同士の接点を記述して、あらゆるコミュニケーションで必要となる明示的な変換について概略を述べ、共有するものがあれば強調すること
まず、「現在存在する」領域の地図を書くこと
変換にはその後で取り掛かること

ここでの重要なポイントは以下の2つ

  • 境界づけられたコンテキストには、それについて話ができるように、名前がなければならない
    • その名前は、チームのユビキタス言語に加えなければならない
  • 全員がどこに境界があるかを知っていなければならず、コードのどの一部をとっても、あるいはどんな状況にあっても、そのコンテキストを認識できなければならない

共有カーネル(SHARED KERNEL)

問題の要約:

まとまりのない複数のチームが、密接に関連したアプリケーションに取り組んでいると、しばらくの間は作業を急いで進めることができても、それぞれが作り出すものはうまく適合しないだろう
結果的に、初めから継続的な統合を行った場合よりも多くの時間を、変換層と修復作業に費やすことになり、この二度手間のせいで共通のユビキタス言語がもつ利点を失うことになる

解決策の要約:

2つのチームが共有することに合意したドメインモデルのサブセットを指定すること
もちろん、これには、モデルのサブセットに加え、コードのサブセットや、おでるの該当箇所に関連するデータベース設計も含まれる
この明示的に共有されたものには特別な地位が与えられているので、もう一方のチームに相談せずに変更してはならない

稼働しているシステムは頻繁に統合すること
ただし、チームの中で行われる継続的な統合よりは、やや頻度を下げること
この統合の際には、両チームのテストを実行すること

顧客/供給者の開発チーム(CUSTOMER/SUPPLIER DEVELOPMENT TEAMS)

問題の要約:

上流チームが自由に開発の舵を取れなくなるのは、下流のチームが変更に対する拒否権を持っている場合や、変更を要求するための手続きがあまりに面倒な場合である
下流のシステムを壊してしまうのではないかと心配するあまり、上流のチームが抑制されることさえある
その一方で、下流のチームは上流チームがつける優先順位の言いなりになって、自分たちではどうすることもできない

解決策の要約:

2つのチームの間に明確な顧客/供給者という関係を確立すること
計画時には、下流のチームが上流のチームに対して、顧客としての役割を果たすようにすること
下流の要件に必要となる作業について交渉し、予算を立てることで、提供の約束とスケジュールを全員が理解できるようにすること

期待されるインタフェースを検証する、自動化された受入テストを共同で開発すること
そのテストを上流チームのテストスイートに追加し、継続的な統合の一部として実行されるようにすること
このテストを実施することで、下流への副作用を心配せずに、上流チームは自由に変更を行えるようになる

順応者(CONFORMIST)

問題の要約:

2つの開発チームに上流/下流関係があるにも関わらず、上流に下流チームの要求に応える動機がない場合、下流チームはどうすることもできない
人の役に立ちたいという重いから上流開発者は約束するかもしれないが、それが守られるとは思えない
そういう善意を信じると、下流チームは決して手に入れられない機能に基づいて計画を立ててしまうことになる
下流のプロジェクトは遅れ、チームは最終的に、与えられたもので我慢することを学ぶことになってしまう
下流チームの要求に合わせたインタフェースは実現する運命にないのだ

解決策の要約:

上流チームのモデルに隷従することで生じる、境界づけられたコンテキスト間での複雑な変換を取り除くこと
確かに下流の設計者が取れるスタイルは制限され、そのアプリケーションにとって理想的なモデルが作れなくなるかもしれないが、順応することを選ぶことで統合は大幅に簡略化されるのだ
また、ユビキタス言語を供給者チームと共有することにもなる
供給者がハンドルを握っているのだから、供給者がコミュニケーションしやすくした方がいい
人の役に立ちたいという思いから、彼らは情報を共有してくれるだろう

腐敗防止層(ANTICORRUPTION LAYER)

問題の要約:

新しいシステムを構築していて、それが他のシステムと接する巨大なインタフェースを持たなければならないという場合、2つのモデルを関係づけることが難しいと、最終的にはその新しいモデルの意図は完全に圧倒されてしまい、結果として、もう1つのシステムのモデルに似せようとその場しのぎで修正せざるを得なくなるかもしれない
レガシーシステムのモデルは貧弱であるのが普通だが、例外的にうまく開発されていても、現在のプロジェクトの要求には合わないかもしれない
それでも、統合することには多くの価値が見出されるかもしれないし、それが絶対的な要件になっていることもある

解決策の要約:

隔離するためのレイヤを作成することによって、クライアントに対して、独自のドメインモデルの用語で表現された機能を提供すること
この層は、既存のインタフェースを通して他のシステムと通信するので、他のシステムを修正する必要はほとんどないか、全くないこともある
内部的には、このレイヤが必要に応じて、2つのモデル間での変換を両方向に対して行う

腐敗防止層が2つの境界づけられらコンテキストを連結する手段であるということを覚えておくこと

別々の道(SEPARATE WAYS)

問題の要約:

統合は高くつくが、それによる利益は小さいこともある

解決策の要約:

境界づけられたコンテキストを他とは一切繋がりを持たないものと宣言し、開発者がその小さいスコープ内で、シンプルで特化した解決策を見つけられるようにすること

公開ホストサービス(OPEN HOST SERVICE)

問題の要約:

あるサブシステムをその他多くのサブシステムと統合しなければならない場合、それぞれに対して特別に変換サービスを作成すると、チームが行き詰まるかもしれない
保守すべきものが次第に大きくなっていき、変更を行う際に注意すべきことも次々と増える

解決策の要約:

これらのサブシステムにアクセスできるようにするプロトコルを、サービスの集合として定義すること
そのプロトコルを公開し、こちらのサブシステムと統合する必要のある人が全員使用できるようにすること
新しい統合の要件に対応する際には、プロトコルに機能を追加し、拡張すること
ただし、あるチームだけに特有の要求は別だ
そのような特殊なケースには、1回限りの変換サービスを使用してプロトコルを拡張し、共有プロトコルは単純で一貫性のある状態に保つこと

公表された言語(PUBLISHED LANGUAGE)

問題の要約:

既存のドメインモデルへの直接的な変換や、既存のドメインモデルからの直接的な変換は、適切な解決策でないことがある
既存のモデルは過度に複雑であったり、うまく分割されていなかったりするかもしれない
おそらくは、ドキュメント化されてもいない
そのモデルをデータ交換用の言語として使ってしまうと、本質的に動きが取れなくなり、新しい開発の要求に対応できなくなる

解決策の要約:

必要なドメインの情報をコミュニケーションにおける共通の媒体として表現できる、明確にドキュメント化された共有言語を使用し、必要に応じてその言語への変換と、その言語からの変換を行うこと

Chapter15. 蒸留

混ざり合ったコンポーネントを分離し、より価値があって役に立つ形で本質を抽出するためのプロセスである
ソフトウェア設計では、モデルの主要な側面を抽象化すること、または巨大なシステムを分割してコアドメインを全面に持ってくることを意味する

ドメインモデルに対する戦略的蒸留は、次に挙げることを全て行う

  • システムの全体的な設計と、設計同士がどう関係するのかを、チームメンバ全員が把握できるようにする
  • ユビキタス言語に入れやすいサイズのコアモデルを識別することで、コミュニケーションを促進する
  • リファクタリングの指針とする
  • モデルで最も価値がある領域に作業を集中させる
  • アウトソーシングと既製のコンポーネントの利用、その割り当てについて決定する際の指針となる

コアドメイン(CORE DOMAIN)

モデルの特徴を示す部分
ユーザの目標の中心となり、アプリケーションを差別化して価値あるものにする

問題の要約:

巨大なシステムを設計する際には、寄与するコンポーネントの数が非常に多い
しかも、どれも複雑な上に成功には全てが絶対に必要である
そのため、ドメインモデルの本質である実際のビジネスの資産が不明瞭になり、おろそかにされてしまうかもしれない

現実は厳しいもので、設計のすべての部分が等しく改良される訳ではない
優先順位を設定しなければならないのだ
ドメインモデルを資産化するには、モデルの極めて重要なコアを洗練し、アプリケーションも機能を作り出す上で最大限に活用しなければならない
反面、高いスキルを持った開発者はそう多くはないが、そういう開発者が惹かれがちなのは、技術的なインフラストラクチャや、特別なドメインの知識がなくても理解可能な、うまく限定できるドメインに関する問題なのである

解決策の要約:

モデルを煮詰めること
コアドメインを見つけて、それをサポートする大量のモデルやコードから容易に区別する手段を提供すること
最も価値のある特化した概念を浮き彫りにすること
コアは小さくすること

最も才能がある人をコアドメインに割り当て、そうした区分に応じて採用すること
コアに対して力を尽くし、深いモデルを見つけ出し、システムのビジョンを実現するのに十分な、しなやかな設計を開発すること
それ以外の部分への投資は、蒸留したコアをどうサポートするかによって正当化すること

汎用サブドメイン(GENERIC SUBDOMAIN)

問題の要約:

モデルの中には、専門的な知識を捉えることも伝えることもなく、複雑さを付け加えるだけの部分もある
本質と無関係なものがあると、それが何であれ、コアドメインを見分け、理解するのが困難になる
モデルを停留させるのは、誰もが知っている一般原理や、専門領域に属するのに主要な焦点ではなく、補佐役を果たすような詳細である
だが、いかに汎用的でも、こういう本質とは別の要素は、システムを機能させ、モデルを完全に表現する上で欠かせない

解決策の要約:

設計中のプロジェクトにとって動機となっていない、高凝集のサブドメインを識別すること
そうしたサブドメインから汎用的なモデルを括り出して、別のモジュールに入れること
その中に特化した要素を一切残してはならない

いったん分離したら、その部分に対して継続される開発の優先順位をコアドメインより下げ、その作業にコアとなる開発者を割り当てるのを避けること(そこから得られるドメインについての知識はほとんどないからだ)
このような汎用サブドメインに対しては、既製品による解決策や公表されているモデルの採用も検討すること

解決策の選択肢いろいろ

  • 既製品による解決策
  • 公表されている設計やモデル
  • 実装のアウトソーシング
  • 自社での実装

ドメインビジョン声明文(DOMAIN VISION STATEMENT)

問題の要約:

プロジェクトが始まった時には、モデルは存在さえしていないのが普通だが、開発に集中する必要性はすでに生じている
開発の後期になると、モデルを詳細に調べなくてもわかる形で、システムの価値を説明する必要がある
また、ドメインモデルの重要な側面は、複数の境界づけられたコンテキストにまたがることもあるが、これら別々のモデルはその定義上、共通の焦点を示すような構造にはできない

解決策の要約:

コアドメインとそれがもたらす勝ちに関する簡潔な記述を作成すること(約1ページ)
これが、価値の定義(Value proposition)である
ドメインモデルを他と差別化するものでない側面は無視すること
ドメインモデルがどのように役に立ち、多様な関心に対してどうバランスをとるかを示すこと
スコープを狭い範囲に留めること
この声明文は早期に作成し、新しい洞察を得たら改訂すること

強調されたコア(HIGHLIGHTED CORE)

問題の要約:

チームメンバがコアドメインの構成を大まかに知っているとしても、別の人々が全く同じ要素を拾い上げることはなく、同じ人であってさえも日によって変わるものだ
絶えずモデルをフィルタリングして主要な部分を識別するという知的労働は、本来であれば設計について考えるのに費やすべき集中力を奪う上、モデルに関する広範な知識を必要とする
コアドメインは、もっと見やすくしなければならない

コードの構造を著しく変更することは、コアドメインを識別するための理想的な方法だが、短期的に見ると、必ずしも実用的とは限らない
実は、そういう大きなコードの変更を容易に行うには、チームでまさに欠けている見方が必要なのだ

解決策の要約:

簡潔なドキュメント(3〜7ページ程度)を書き、コアドメインとコアを構成する要素間の主要な相互作用を記述すること

モデルの主要なリポジトリ内においてコアドメインの各要素にフラグを立てること
ただし、その役割をことさら明らかにしようとしなくても良い
コアに入るものと入らないものを開発者が楽にわかるようにすること

蒸留ドキュメントがコアドメインの本質を概説しているなら、それはモデルを変更する意義を示す、実用的な指標としての役割を果たす
モデルやコードの変更が蒸留ドキュメントに影響を与える場合には、他のチームメンバとの協議が必要である
変更したらチームメンバ全員に速やかに通知し、蒸留ドキュメントに含まれていない新バージョンを配布すべきだ
コアの外に対して行われる変更や、蒸留ドキュメントに含まれていない詳細に対する変更であれば、協議も通知もなしで統合することができ、他のメンバは作業の過程で気づくことになる
そうなれば、開発者はXPが提唱する完全な自立を手に入れることになる

凝集されたメカニズム(COHESIVE MECHANISMS)

問題の要約:

処理が設計を肥大させ始めるくらい複雑なレベルに到達することもある
概念的な「何が」が、機械的な「どのように」によって侵食されてしまうのだ
問題を解決するためのアルゴリズムを提供するメソッドが大量に存在してしまうと、問題を表現するメソッドがわかりにくくなる

解決策の要約:

概念的に凝集されたメカニズムを切り分けて別個の軽量なフレームワークにすること
特に、形式主義や十分にドキュメント化された種類のアルゴリズムに気をくばること
意図の明白なインタフェースを用いてフレームワークの機能を他から使えるようにすること
これで、ドメインの他の要素は問題を表現すること(「何が」)に集中でき、複雑な解決(「どのように」)はフレームワークに移譲できる

隔離されたコア(SEGREGATED CORE)

問題の要約:

モデル内にある複数の要素は、一部がコアドメインに仕え、一部が補助的な役割を果たすかもしれない
コアに仕える要素が、汎用的な要素と密接に結合していることもある
コアの概念上の凝集は、強くもなく可視的でもないかもしれない
こうした雑音ともつれによって、コアの発達が妨げられる
設計者は最も重要な関係性を明確に理解することができず、貧弱な設計が作られることになる

解決策の要約:

モデルをリファクタリングして、コアの概念を補助的な役割を果たすもの(はっきりと定義されていないものも含む)から分離すること
そうすることにより、コアの凝集度を高めつつ、他のコードへの結合を低くすること
汎用的な要素や補助的な要素は全て別のオブジェクトに括り出し、それを別のパッケージに入れること
モデルをリファクタリングした結果、密接に結合している要素を分離することになるとしても、やらなければならないのだ

抽象化されたコア(ABSTRACT CORE)

問題の要約:

別々のモジュールに置かれたサブドメインの間で大量の相互作用があると、モジュール間で多数の参照を生成する必要が生じて、分割したことの価値をほとんどなくしてしまうか、相互作用を間接的に行わなければならなくなって、モデルが曖昧になるかのいずれかとなる

解決策の要約:

モデルにおける最も根本的な概念を識別し、それを別のクラス、抽象クラスまたはインタフェースに括り出すこと
この抽象的なモデルは、重要なコンポーネント間の相互作用をほとんど表現するように設計すること
この抽象的なモデル全体を独自のモジュールに入れること
ただし、特殊で詳細な実装クラスは、サブドメインによって定義されたモジュールに残すこと

Chapter16. 大規模な構造

巨大なシステムに包括的な原則がなく、そのせいで各要素を解釈する際に、設計全体にまたがるパターンにおいてどのような役割を果たすかという観点から考えることができなくなければ、開発者は「木を見て森を見ず」になってしまう

「大規模な構造」は、システムをおおよその構造から議論し、理解できるようにするための言語である

ルールについてのパターンや、役割や関係性についてのパターンを考え出すこと
このパターンはシステム全体に行き渡る
また、このパターンがあることで、全体に置ける各部分の位置付けが、その部分の責務を詳細に知らなくても理解できるようになる

進化する秩序(EVOLVING ORDER)

問題の要約:

設計に制約がなければ、できあがるシステムの全体像が誰にでも理解できない上に、保守するのも非常に困難になる
しかし、アーキテクチャも、アップフロントな設計上の想定によってプロジェクトを束縛し、アプリケーションの特定の部分を受け持つ開発者や設計者からあまりに多くを奪ってしまうかもしれない
やがて、開発者は構造に合うようにアプリケーションを書き直すか、構造を転覆させて完全に無くし、調整されていない開発による問題を呼び戻すことになる

解決策の要約:

概念上の大規模な構造をアプリケーションと共に進化させ、場合によっては途中で全く別の種類の構造に変更すること
詳細な知識を必要とする、設計とモデルに関する詳細な意思決定を、制約しすぎてはならない

大規模な構造を適用すべきなのは、モデルの開発に不自然な制約を強いることなく、システムを大幅に明確化する構造が見つけられたときだ
うまく合わない構造なら、ない方がましなのだから、包括的なものを目指すのではなく、出てきた問題を解決する最小限のものを見つけることが一番だ
「より少ないことは、より豊かなこと(Less is more)」なのだ

システムのメタファ(SYSTEM METAPHOR)

問題の要約:

ソフトウェアの設計は、非常に抽象的で把握しにくい傾向にある
システムを理解して、全体としてのシステムの見方を共有するための具体的な方法は、開発者もユーザも等しく必要としている

解決策の要約:

システムを表す具体的な類比が登場し、チームメンバの想像力を捉えて、役立つ方向に思考を導きそうであれば、それを大規模な構造として採用すること
そのメタファを中心に設計を構成して、ユビキタス言語に取り入れること
システムのメタファは、システムに関するコミュニケーションを容易にすると同時に、システムの開発を導かなければならない
これによってシステムの様々な部分が一貫したものとなり、さらには、別の境界づけられたコンテキストを超えて広がるかもしれない
しかし、メタファは全て不正確なものなので、拡大しすぎたり不適切であったりしないかを絶えず調べ直し、障害になるようなら取り消せるようにすること

責務のレイヤ(RESPONSIBILITY LAYERS)

問題の要約:

個々のオブジェクトがそれぞれ手作りの責務を与えられているとすると、ドメインの広い範囲をまとめて処理する上で指針も統一性も能力もないことになる
巨大なモデルに一貫性を与えるには、そうした責務を割り当てる際に何らかの構造を課すことが有効である

解決策の要約:

モデルの中にある概念上の依存関係を調べること
また、ドメインの様々な部分の変更について、変化の割合とその原因も調べること
ドメインに自然な階層が認められたら、それに幅広い抽象的な責務を割り当てること
それらの責務は、システムの高次の目的と設計について語るものでなければならない
モデルをリファクタリングして、各ドメインオブジェクトと集約およびモジュールの責務が、1つのレイヤに与えられた責務の範囲にうまく収まるようにすること

知識レベル(KNOWLEDGE LEVEL)

知識レベルとは、他のオブジェクトグループがどう振る舞うべきかを記述するオブジェクトグループである

問題の要約:

エンティティ間にある役割と関係が状況によって変わるアプリケーションでは、複雑さが爆発的に増えかねない
完全に汎用的なモデルも、高度にカスタマイズされたモデルも、ユーザの要求には役立たない
最終的にオブジェクトに残るのは、多様な状況を網羅するための他の型への参照か、状況によって使い道が変わる属性である
同一のデータと振る舞いをもつクラスが、別々の組み立てルールに適応するためだけに数が増えてしまうかもしれない

解決策の要約:

基礎となるモデルの構造と振る舞いを記述し制約するのに使用できる、独特なオブジェクトの集合を作成すること
これらの関心ごとは2つの「レベル」として別々に保ち、一方を非常に具体的にし、もう一方にはユーザやスーパーユーザがカスタマイズできるルールと知識を反映させること

着脱可能コンポーネントのフレームワーク(PLUGGABLE COMPONENT FRAMEWORK)

問題の要約:

多様なアプリケーションの相互運用が必要で、全てが同一の抽象に基づきながら独立して設計されている場合、複数の境界づけられたコンテキスト間で変換しなければならないために、統合が制限されてしまう
共有カーネルは緊密に連携していないチームにおいては現実的ではない
重複と断片化のせいで開発とインストールのコストが増大し、相互運用が非常に困難になる

解決策の要約:

インタフェースや相互作用にある抽象化されたコアを蒸留し、そのインタフェースの多様な実装を自由に置換できるようにするフレームワークを作成すること
同様に、抽象化されたコアのインタフェースを経由して操作される限り、あらゆるアプリケーションがこのコンポーネントを使用できるようにすること

Chapter17. 戦略をまとめ上げる

まず評価する

プロジェクトにおいて戦略的設計に取り組む際には、現在の状況を明確に評価することから始める必要がある

  • コンテキストマップを書くこと
    • 一貫したものが書けるか?
    • それとも曖昧な場所があるか?
  • プロジェクトでの言語の使われ方に注意を払うこと
    • ユビキタス言語はあるか?
    • それは開発を支援できるくらい豊かであるか?
  • 何が重要であるかを理解すること
    • コアドメインは識別されているか?
    • ドメインビジョン声明文はあるか?それを書くことはできるか?
  • プロジェクトで使われている技術はモデル駆動設計に向いているか?
  • チームの開発者は必要な技術的スキルを持っているか?
  • 開発者はドメインについてよく知っているか?ドメインに関心を持っているか?

戦略的設計上の意思決定を行うために欠かせない6つのこと

  • 意思決定はチーム全体に伝えなければならない
  • 意思決定プロセスはフィードバックを吸収しなければならない
  • 計画は進化を許容しなければならない
  • アーキテクチャチームが、最も優秀な人を全て吸い上げてはならない
  • 戦略的設計にはミニマリズムと謙虚さが必要である
  • オブジェクトはスペシャリストだが、開発者はジェネラリストである
    • うまくいっているプロジェクトには、他人のことに首をつっこむ人が多い
    • チームでの交流を、ソフトウェアに対してやるように整理しようとしないこと
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.