ravelll の日記

よしなに

エリック・エヴァンスのドメイン駆動設計 4章メモ

3章の週は時間が取れなかったので一旦飛ばしました。
4章はドメインを表現する箇所と技術的な要求を実現する箇所を分離すべき理由とその方法としてのレイヤ化アーキテクチャについて。


4章 ドメインを隔離する

  • (ravelll)ドメインから生じる問題とは?
    • あるドメインにおいてソフトウェアが解決したい問題?
  • 問題解決の流れを表現する部分と技術的な流れを実現している部分が混ざらないようにする必要がある
    • そうしないと何がモデルなのかをソフトウェアから理解することが難しくなる

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

  • (ravelll)"ビジネスロジックとは何?"という問いに対する答えを1つ言語化できるようになる章っぽい
  • MVC の例
    • UI の変更がビジネスロジックの変更を巻き込んでしまう
    • "凝集度の高いモデル駆動のオブジェクトを実装することが現実的ではなくなる"
      • ビジネスモデルを純度高く反映したオブジェクトを実装するのが難しくなるということ?
    • 技術的なフローを実現するコードとビジネスモデルを表すコードが混ざるとテストもぎこちなくなる
  • Layered Architecture で関心事を分離しつつ相互作用も継続してできるようにする
    • "本質的な原則は、レイヤ内のどの要素も、同じレイヤの他の要素か、その「下にある」レイヤの要素にしか依存しない、ということである。"
    • "レイヤの価値は、それぞれがコンピュータプログラムにおける特定の側面を専門的に扱うことにある。"
    • "もちろん、決定的に重要なのは、設計における最も重要で凝集度の高い側面を隔離するレイヤを選び出すことだ。"
      • Layered Architecture は具体的な層の設計までを提供するものではなさそう
      • とは言えうまく行っているところはだいたいこういうパターンになるよね、という傾向はある
        • UI(Presentation) 層
          • ユーザーは人間に限らない
        • Application 層
          • ビジネスルールや知識についてのロジック・状態を持たず薄く保たれる
          • 技術的な操作や処理の状態は持てる
          • 調整役
          • UI 層と厳密に区別されない場合もある
        • Domain(Model) 層
          • ビジネスの状況や概念を表す責務を追う
          • これを分離して始めてモデル駆動開発が可能になる
        • Infrastracture 層
          • 上位レイヤーを支える一般的な技術機能提供を行う(これはしばしばサービスという形で提供される)
    • それぞれのレイヤはそれぞれ異なる速度で進化する
    • 各レイヤーは分散して配置されうる
  • 表示、格納、アプリケーションタスク管理などのロジックはドメインモデルの表現には不要
    • "アプリケーションタスク管理" とは?
  • (ravelll)依存が単方向になるべき理由を言語化できる?
    • 双方向になる => 互いに互いを知ることになる => 関心事を一方に留めておけなくなる ということ?

オンラインバンキングの機能をレイヤに分割する

  • ドメイン層でやるのは (1) 指定された口座Aを振込元して口座Bに対して指定された金額を追加すること (2) 指定された口座Aから指定された金額を引くこと
  • トランザクションを開始・コミットする、振り込みを DB に記録する、等はスコープ外
  • "おそらくそこには、元帳オブジェクトや、振り込みおよび引き落としオブジェクト、金銭取引オブジェクトなどが含まれていただろう。"
    • 振る舞いもオブジェクトなんだ。オブジェクトとは…?

レイヤを関係づける

  • 依存方向を逆転したいときはコールバックやオブザーバーを使う
  • (ravelll)アプリケーションコーディネータとは?

アーキテクチャフレームワーク

  • "多くのインフラストラクチャの要求を統合するフレームワークを使うと、他のレイヤをきわめて特殊な仕方で実装しなければならなくなることも多い。"
    • Rails の話か???
  • "最もよくできたアーキテクチャフレームワークは、複雑な技術的問題を解決する一方で、ドメイン開発者がモデルを表現することに集中できるようにする。しかし、フレームワークは、ドメインについての設計の選択肢を制限する前提を多く設けすぎたり、開発の速度を低下させるほど実装を重苦しくしてしまったりすることで、容易に開発の妨げとなり得るのだ。"
  • (ravelll)ドメインオブジェクトってつまるところ何?
    • ドメインモデルのいずれかの登場人物に対応するクラス?
  • フレームワークを選ぶときはちゃんとソフトウェアがモデル駆動となるものを選びましょう

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

  • ドメイン駆動設計におけるレイヤ化アーキテクチャ => ドメイン層があること
  • "利口なUI(Smart UI)"
    • ビジネスルールのあまり無い小さく短命なシステムにおいてはアプリケーションを小さな単位に分割し、そのユーザーインタフェースに全てのビジネスロジックを詰めるという戦略がある
      • Layered Architecture を水平分割と呼ぶなら利口な UI は垂直分割っぽい
    • (ravelll)4GL ツールとは?
      • 4th generation language
      • R, SQL, MATLAB とか
      • 特定の分野において高次に抽象化された操作を可能とする言語のこと
        • ので特定のシステムと対になっているものも多い
    • やるなら不要な複雑さを高機能な言語やフレームワークから持ってこない用にする持ち込まないようにする
      • 4GL っぽい何かでよい
  • "同じ理由から、モデル駆動設計に取り組むチームは、最初からそれにふさわしいやり方で設計する必要がある。(snip)しかし、最初の一歩を試しに踏み出す先が、ドメインレイヤを隔離したモデル駆動でなければ、プロジェクトは利口なUIに行き詰まることになるだろう。"
  • この章ではドメインを隔離して実装する方法として Layered Architecture を紹介しているが、ドメイン層をどのようにやっていくかについては後続の章が担当するっぽい

エリック・エヴァンスのドメイン駆動設計 2章メモ

ユビキタス言語とそれを作る・使う上でのよくある勘違いの章と理解した。

第2章 コミュニケーションと言語の使い方

  • 言語はドメインに関する意思決定と実装を結ぶもの
    • 言語の乖離は実装の乖離に繋がりそう
  • ドメインエキスパートと開発者のそれぞれがドメインを記述する言語を独自に作り出してしまう
    • 翻訳が必要になるが、翻訳はモデルの概念を混乱させることに繋がり、混乱は破壊的なリファクタリングに繋がる
    • 通訳は知識の噛み砕きを鈍化させる
  • ちゃんとモデルに基づいた言語で会話をするように頑張らないと知識の噛み砕きのプロセスが良いモデルを作ることに繋がらなくなっていく
  • 実装に紐づく言語でみんながしゃべると不意に矛盾が見つかることが多くなって便利で、その一方で開発者の言葉をそのまま共通言語として採用するにはドメインエキスパート側の負担が大きいので双方から歩み寄った現実的な解としてのユビキタス言語という概念、という感じ?
  • 何でもかんでもユビキタス言語化するのではなく、あくまでもモデルが対象とする範囲においてユビキタス言語を作る、というのはなるほどという感じ
  • ユビキタス言語は開発者・ドメインエキスパートが理解するものの最大公約数となるような定義ではなく、厳密に限定された定義としなくてはならない
    • 両者が同じものを想像する程度に理解できる名前だからオッケーというものではない
  • UML はそれを書き出して議論に中心に置くことで統一した相互関係・モデル名を全員が持ち議論できるようにする = Unified Modeling Laungage
  • UML はそんなに完璧に詳細を書き出すものではない
  • UML はオブジェクトの属性と関係は容易に書き出せる一方でオブジェクトの振る舞いや制約は書き出しづらいツール
    • その限界をユビキタス言語を用いた会話によって補える
  • "モデルは図ではない"
    • 図は単にモデルについて議論する際にコミュニケーションや理解を円滑にするための表現の1つというだけ
    • 前職で開発の進行をやったときにすべてのモデルを言葉で表現しようとしたけど、もっと図を使ったり、複数の方向からモデル作成を試行してみればよかったな…
      • そもそもコミュニケーションが足りてなさすぎたのも問題だった

書かれた設計ドキュメント

  • ドキュメントが事実と乖離していく問題
    • XP => 極力書かずにコードに語らせる。コメントはこれに含まれないので重視しない
      • 厳密で活きたモデルを保てるが、理解しづらい。また背景を伝えられない
  • "すでにコードがうまくやっていることを、ドキュメントでもやろうとするべきではない"
    • ドキュメントはコードを補足する
  • ドキュメントはそれが必要なら乖離が問題として浮上する
  • 問題にならず乖離しているドキュメントは更新するのも時間の無駄
  • ユビキタス言語でモデルの背景となるビジネス知識などを共有することに成功するとモデルのドキュメンテーションを小さくすることができる
    • ドキュメントでコードと会話を補足する
  • "正しいことをするだけでなく、正しいことを言うコードを書くためには、潔癖でなければならない"
    • 前者だけではモデルとの繋がりが曖昧になる(名前が曖昧とか)
  • コードから何らかモデルを説明するもの(図とかテキストとか)を出力する方法は研究されていないのかな
    • コードを直接ドメインエキスパートが読むのは現実的には難しいけどそれを抽象化したものを使って会話ができると良さそうな気がする

説明のためのモデル

  • 実装、設計、コミュニケーションの根底にあるモデルはチームで1つにしよう
  • モデルのコアとなるものではなく一般知識を説明するためには別のモデルを利用できる
    • そのときにはコアとなるモデルと混同しないように UML は使わないほうが良い

エリック・エヴァンスのドメイン駆動設計 1章メモ

今週から社内で読書会が開かれることになった。基本的には事前に読んでくるスタイルの会ということで第1回の範囲となる1章を読んだので、雑に取ったメモを放流。

1章 知識を噛み砕く

  • ドメイン知識が無い状態でもの(PCB)を作った体験
  • ドメインエキスパート(PCB回路設計者)がソフトウェアが達成すべきものをよく知っているわけではない
  • ドメインエキスパートと話し合う中で語彙を研鑽する
    • 用語の不一致を正す、使うべき言葉をドメインエキスパートが学ぶ
  • 処理の流れ(モデル)を一緒に書いていくやり方が良い?
    • 登場人物の名前を知る
    • 登場人物の関係を知る
    • 処理の名前を知る
    • 処理の概要・目的を知る
  • ドメインエキスパートとの議論においてソフトウェアの詳細に立ち入り過ぎないよう気をつけるべきっぽい
    • "すみません、詳細に立ち入りすぎました"
  • ドメインモデルを注意深く作成することで本質的な処理を見つけやすくなる?
    • "その後ほんの数日のうちに〜実際に計算したことには変わりない"
  • ドメインエキスパートと一緒に図を作ったことで、あるドメインの複雑さの中で今回つくる機能が持たねばならない部分がどこなのか、を開発者単体で考えたときと比べて精度高く知った状態で開発に入ることができるのでは
    • 複雑さを見誤るとどんなに設計が良くても負債になりそう
    • 例えば Web アプリだと DB の設計を含むくらい機能開発をするときにはミスると辛いしそこを境界線として特に注意深くドメインエキスパートとコミュニケーション取りながら作る、みたくすると良いのかもしれない
  • ドメインエキスパートと一緒に図を作ることでソフトウェアの構造をドメインエキスパートより理解できるようになる
    • その結果、ドメインエキスパートがソフトウェア開発に協力的になる、という流れがある
    • ドメインエキスパートとの距離を感じたら大まかな設計を一緒にやってみることから始めると良いのかな
    • ソフトウェア開発者がドメインエキスパートとコミュニケーションを取るフレームワークとなった
      • 完全にいい話
  • ドメインエキスパートと一緒にモデルを作成しソフトウェアを開発することで、ドメイン知識がソフトウェアに組み込まれる
  • 本ではドメインエキスパートがオブジェクト間の相互作用を提示するまでになってるけどそれを望むのはきつそう
  • 顧客が本当に求めているものを協力して探すには、やはりモデルを一緒に作るのが良さそうに感じた
    • "モデルを改良すると、コードも一緒に進化した。数カ月後、PCB 技術者は自分たちの期待を上回る、機能豊富なツールを手にしていた。"

効果的なモデリングの要素

  • 筆者によるこの話についてこれが成功の秘訣だったリスト
    • モデルと実装を結びつけること
    • モデルに基づいて言語を洗練させること
      • 最初辛い(主にドメインエキスパートが)けど相互にモデルを理解できるようにしておくことでモデルの構造と矛盾しない思考で議論することができるようになった
    • 知識豊富なモデルを開発すること
      • モデルは単なるデータスキーマではなく、複雑な問題を解決する振る舞いと守るべきルールがある。クゥ〜ッ
    • モデルを蒸留すること
      • 蒸留 = 本質的でない概念を切り捨てる
    • ブレインストーミングと実験をすること
      • モデルの形を色々と書いてみては議論することで使えるか調べた
      • このときに会話がぎこちない = このモデルはダメそうという判断ができた
  • (ravelll)開発者がドメインエキスパートのとき DDD を利用する利点はあるのか
    • ユーザーを登場人物に含めて間接的にモデルについて議論する、と考えるとモデルを洗練させ実装と一致させる狙いで利用する意味が十分ありそう
    • DDD が良いのは翻訳による情報の欠如や時間的なロス、人間関係の改善とするなら、ユーザーと直接話すことはなく開発者がただ議論するだけなら翻訳のオーバーヘッドも小さそうなので実は効果的ではない?

知識の噛み砕き

  • "噛み砕く" = それの根底にある意味を知るプロセス
  • "ドメインモデルを噛み砕く"ということ
    • 情報の流れを掬ってその重要な意味の大部分を理解できる抽象的なモデルを見つけること
  • 知識の噛み砕きは一人で行うものではなく、開発者とドメインエキスパートで行う
    • 大抵は開発者が率いる
  • 知識噛み砕きプロセスの失敗事例
    • (1.) ウォーターフォールでの流れ
      • ビジネスエキスパートがアナリストに話をする
      • アナリストが情報を噛み砕き抽象化する
      • ソフトウェアエンジニアがそれを実装する
        • この流れにはフィードバックのタイミングがない
        • アナリストが基にするのはビジネスエキスパートの話だけ
    • (2.) イテレーティブにやってるけど抽象化してなくて知識が積み上がらない
      • 何を作るかビジネスエキスパートに聞いて実装し、終わったら提示する
      • "何を作るか" だけに集中するとモデルの蒸留が行われなくてダメそう
      • "そうしたやり方でも(snip)既存機能の必然的な帰結として強力な新機能が現れるという段階には、決して到達することがない。"
        • ゴールド・エクスペリエンス・レクイエム!!
      • 抽象化もドメインエキスパートとの共同作業なしに行うとドメインエキスパートの考えと乖離してしまう
      • "チームメンバ間のやりとりは、メンバ全員がモデルを一緒にかみ砕くことで変化する。" いい話っぽい
      • ドメインモデルを絶えず改良すると開発者はビジネスにおける重要な原理を習得するよう強いられる、というのがちょっとわかってない
        • ドメインモデルを絶えず改良すること = ドメインエキスパートと絶えずコミュニケーションを取ることで、
        • 重要な原理を習得していないことはドメインエキスパートとコミュニケーションを取ってモデルを作ることを妨げるから?
  • うまく知識をチームが噛み砕けるとモデルはビジネスの深い知識を反映したものになる
    • "改善されるにつれて、モデルは、プロジェクトの中を流れ続ける情報を体系化するためのツールとなっていく。"

継続的学習

  • 生産的なチームを知識を意識的に育てる
    • 十分な知識が無いことを認識することはしばしば難しい
    • 知識はメンバーの入れ替えやアウトソーシング等によって流出する
  • "技術的な知識" って例えば gRPC について知る、みたいな話?
  • 知識があると知識の噛み砕きをよりうまくできるようになる
  • 例えば PCB の事例について学んだところ
    • (エキスパートとの対話を通じて)アプリケーションに関連する重要な概念の理解
    • 構築している内容がただしいかどうかのチェックを行うこと
  • 大事なのは共同作業によって作成されたモデルが残ることではなく知識の噛み砕きのプロセスを起こさせること
    • 知識の噛み砕きが行われることで以後の作業がより効果的になる

知識豊富な設計

  • 設計やリファクタリングはモデルの変化を主軸として行われるもの
    • 逆に言えば、開発者はモデルの変化に機敏に対応できる設計にし、実際に追従していかねばならない
  • 存在しているエンティティやコードを超えて、相互作用やビジネスルールに注目する
    • コードは合っているがビジネスルールとして矛盾している、ということに気づける
    • この辺コードレビューしてるとどうやったら気付けるのかな〜とよくなる…
      • 普段から背景となるビジネスルールまでを考えてコードを読み書きすることで一歩抽象度の高いレビューができるようになる?
  • 人間は自身が触れている世界のプロセスを処理する中おきるギャップを思考によって無意識に調整・補完している
    • そんなことはソフトウェアにできないので、知識をちゃんと噛み砕いて具体化させ、実装したり切り捨てたりする
  • 貨物船の例
    • あるモデルが満たすべきルールを相互作用のプロセスに押し込んでいる
      • これではドメインエキスパートがコード(エンティティを指している?)を読んでも検証できない
    • 知らない人が要求定義とコードとを結びつけるのが困難になる
    • この例ではオーバーブッキングポリシーを別クラスとして表現しているけど、これはポリシーは船舶にも荷物にも紐づくものではなくビジネスとして存在する"知識"であるから独立したクラスとして表現されるのが適当、という判断?
      • "知識を確固たるものにして共有するのに使えることを示すために用いた" とある

深いモデル

  • アプリケーション作ってるときにそれを誰がどう使っているのかを勝手に思い込んでいらない機能を作る、というのは超あるあるという感じ