DDD / Angles of Attack


Angles of Attack (p.282)

要約

  • アプローチの角度
    • この章ではさまざまなテクニックを示してきたが、大掛かりなシステムに対して一度に適用することはできない。ここではまず2つのアプローチを示し、続いて具体例を挙げる。
  • サブドメインを切り出す
    • デザイン全体に一気に取り組むことはできない。特殊な数学としてみることができる部分があれば、切り出しなさい。状態の変化を制限するような複雑なルールがあれば、別のモデルに抜き出すか、ルールを宣言できる単純なフレームワークに当てはめなさい。そうすることで、新しく抜き出した部分だけでなく、元の部分も細かく、明快になる。(というのも(?))元の部分は宣言的なスタイルで書かれているからだ。
    • 全体をうっすらと改善するよりも、ある一部分に焦点を当てて、そこのデザインを柔軟にしたほうが良い。(詳しくは15章で)
  • できるものならば確立された形式に準拠する
    • 概念的なフレームワークを1から構築するというのは、一朝一夕でできることではない。ものによっては、プロジェクトのライフサイクルを通じて構築する必要がある。しかし長い時間をかけて確立された概念的な枠組みを使うこともできる。
      • 例えば勘定("account")
    • このような形式化された概念のフレームワークは数多くあるが、個人的には数学が好き。以下、「分け前数学」の具体例を挙げる。

  • 【具体例】パターンの統合:分け前数学("Shares Math")*1
    • ブレイクスルーの時に出てきたローンシステムの話
    • 仕様:借り手が元金の支払いを行なった場合、基本的にはローンにおける貸し手のシェアに基づいて配分される。
  • 支払い分割の最初のデザイン
    • 図10.16
    • LoanはownerをキーとしてShareを持つ。
  • コマンドの分割とSIDE-EFFECT-FREE-FUNCTION
    • 既にINTENTION-REVEALING INTERFACEは実現されている。しかし、distributePaymentPrincipal?()はシェアの計算と同時にLoanの変更を行なってしまうので危険。だから、問い合わせと命令とを分割する。*2
    • 結果が図10.17
    • これはこれで悪くない。FUNCTIONがINTENTION-REVEALING INTERFACESの背後に複雑な処理を隠蔽している。しかし、機能を追加した場合にはコードの重複も出そうなので、まだ粒度には問題がありそうだ。このような問題に対する伝統的な対処法はサブルーチン化であり、間違ってはいない。しかし、究極的には根底にある概念的な境界を見出し、モデルを深めたいのだ。このようなCONCEPT-CONTOURINGな粒度を用いたデザインの諸要素は、必要なバリエーションを産み出すことと結びつけることができる。
  • 隠された概念を暴き出す(Making an Implicit Concept Explicit)
    • Shareオブジェクトの扱いは複雑。その原因は分け前に関するルールと計算が個別の分け前ではなくグループに紐づいているからだ。失われている概念があるのであって、それはつまり、「分け前は全体を構成する一部分として相互に関連している」というものだ。この概念を見えるようにしたものが図10.18
    • Share Pieは特定のLoanを分割したものの全体を現している。これはENTITYであり、同一性はLoanのAGGRIGATEの中に局所化されている。分割についての計算を実際に行なうのはShare Pieに委譲できる。(図10.19)
    • Loanは単純化されたし、Shareの計算はその責務に焦点を当てたVALUE OBJECTで一元管理されている*3。それでも、計算自体は柔軟(versatile)にも簡易にもなっていない。
  • Share PieがVALUE OBJECTに:洞察の連鎖
    • デザインを新しくすることがモデルそれ自体に対する洞察の引き金になり得る。この場合ではLoanShare Pieの結合が強いためにShare PieSharesの関係をあいまいにしているようなので、Share PieをVALUE OBJECTにしてみては?
    • Share Pieがimmutableにならなければいけないので、increase(Map)とdecrease(Map)を修正し、新しいShare Pieを返すようにする。
    • CLOSURE OF OPERATIONを押し進めよう。
    • prorate()は戻り値を変えるだけで良い。副作用がないことを示すために名前をporated()に変更する。「分け前数学("Shares Math")」ができ始めた。
    • 新しいVALUE OBJECTについてASSERTIONSを作ることができる。
      • getAmount():全体は部分の合計に等しい。
      • minus():二つのPiesの差はそれぞれの所有者の分け前の差である。
      • plus():二つのPiesの和はそれぞれの所有者の分け前の差である。
      • prorated():元利合計は全ての所有者よって分け前に応じて分配される。
  • 新しいデザインの柔軟性
    • Loanクラスのメソッドはとてもシンプル
    • これらの短いメソッドはその意味を表している。Share PieのデザインによりLoanのコード内で宣言的なスタイルを用いることができるようになった。コードは業務取引に関する概念的な定義として読めるようになってきている。
    • 複雑すぎて、前には記述できなかった他の取引の例(省略)
    • Share Pieのデザインが持ついくつかの特徴により、コード内において(各演算を)簡易に結合し、可読性をあげることができている。
      • 複雑なロジックはSIDE-EFFECT-FREE FUNCTIONSを持つ特別なVALUE OBJECTの中に隠蔽されている。
      • 状態を変更する演算子はシンプルであり、ASSERTIONSによって特徴が記述されている。
      • モデルの各概念は切り離されている。処理は必要最低限しか関連しあっていない。
      • 慣れ親しんだ形式によってプロトコルが簡単に把握できる
    • 数学の形式に対応した場所を切り取ったことで、Shareのデザインは柔軟になり、重要なLoanFacilityメソッドが洗練された。

  • まとめ
    • 柔軟な設計はソフトウェアが変更と複雑さとに対処できるようになる上で非常に重要。15章では柔軟な設計が持つ戦略的な価値を紹介する。

担当者のつぶやき

  • 「オブジェクト指向の美しさ」みたいなものを垣間見て感動しました。こういうシステム開発をやってみたいです。
  • 最近、DSLに興味があるのですが、コードをここまで洗練できるならDSLによる顧客との打ち合わせも、かなり有効かもしれませんね。

みんなの突っ込み


まとめ (議事録)


*1 専門用語なんでしょうか?数学のことは良く分かりません。
*2 それによってSIDE-EFFECT-FREE-FUNCTIONが実現される。
*3 この段階ではShare PieはENTITYでは?