第 1 ç« : ドメむン駆動蚭蚈入門

“1. Introducing Domain-Driven Design” from “Domain Modeling Made Functional: Tackle Software Complexity with Domain-Driven Design and F#” 📚

゜フトりェア開発者の仕事ずは:

  • not only コヌドを曞くこず
  • but also ゜フトりェアを通しお問題を解決するこず

芁件が䞍明瞭だったり、蚭蚈が悪ければコヌディングをどれだけ頑匵ろうずよい䟡倀は埗られない

  • ぀たり garbage in, garbage out
    • 📝 この衚珟は゜フトりェア自䜓ぞの入力ず出力に察しお䜿われるこずが倚いが、ここでは input が「芁件」、output を「埗られる䟡倀」ずいうかなり高レむダな意味で䜿われおいる

“garbage in” を枛らすのに必芁なもの:

  • 明解なコミュニケヌション
  • 共有ドメむン知識に基づく蚭蚈アプロヌチ

ドメむン駆動蚭蚈DDDをによっおこれらを実珟できる。

共有モデルの重芁性

たず開発者が問題を正しく理解するこずが重芁

ずりうるアプロヌチを 3 ぀玹介:

  1. 仕様曞・芁件定矩曞を敎備する 💣
  2. ドメむン゚キスパヌトを開発プロセスに入れる ⚠
  3. ドメむン駆動蚭蚈 ✅

1. 仕様曞・芁件定矩曞を敎備する 💣

これはだめなやり方。

理由:

  • ドメむン゚キスパヌトず開発チヌムの距離が遠くなっおしたう ❌
  • “䌝蚀ゲヌム” のようなこずが実際に起こり、これはプロゞェクトにおいおは臎呜的 ❌

2. ドメむン゚キスパヌトを開発プロセスに組み蟌む ⚠

いわゆるアゞャむルなやり方。䞀芋良さそうに思えるがベストではない。

誀りをすぐに修正できるようにするために、ドメむン゚キスパヌトを開発プロセスのフィヌドバックルヌプに組み入れる。

デメリット:

  • 開発者の働きがドメむン゚キスパヌトのメンタルモデルの単なる翻蚳者でしかなくなっおしたう ❌
  • 必ず抜け萜ちおしたう情報がある ❌
  • 将来、ドメむン゚キスパヌトからの入力なしにコヌドをメンテする開発者は容易に方針を誀っおしたう ❌

3. ドメむン駆動蚭蚈 ✅

プロゞェクトに関わる人々䞋蚘が共通のメンタルモデルを共有した状態で開発を進める:

  • ドメむン゚キスパヌト
  • 開発者
  • ステヌクホルダヌ

゜フトりェアのコヌドはメンタルモデルを盎接反映したものになるので、DDD では “翻蚳” ずいう䜜業は存圚し埗ない。

メリット:

  • 垂堎投入スピヌド ✅
  • 埗られるビゞネス䟡倀の倧きさ ✅
  • 無駄の排陀 ✅
  • スムヌズなメンテナンス ✅

コラムでは、開発者自身がドメむン゚キスパヌトになる重芁性が瀺されおいる

共有メンタルモデルを䜜るためのガむドラむン:

  • デヌタ構造ではなく、ビゞネスむベントずワヌクフロヌに着目せよ
  • ドメむンを小さいサブドメむンに分割せよ
  • それぞれのサブドメむンに぀いおモデルを䜜れ
  • 䌚話やコヌドで䜿われる共通蚀語を䜜れ

ビゞネスむベントからドメむンを理解する

共有メンタルモデルの構築はどこから始めたらいい → むベントから始めよ ✅デヌタ構造から始めるな ❌

理由:

  • ビゞネスがデヌタをただ持っおいるだけで終わるこずは有り埗ないため
  • ビゞネスは䜕らかの方法でデヌタを倉換するため

ビゞネスプロセスずは、デヌタやドキュメントの倉換凊理の集たり → これらの倉換がどう行われ、どう関連しおいるかを理解するこずが重芁

䜿われずにただ眮かれおいるだけのデヌタは䜕の䟡倀も生たない。 これらのデヌタから䟡倀を匕き出すためのプロセスはどうやっお始たるか → ドメむンむベントによっお始たる

ドメむンむベントの䟋:

  • 倖郚トリガヌ
  • スケゞュヌルに基づいたトリガヌ
  • 芳枬に基づくトリガヌ

ドメむンむベントは事実である倉化しないため必ず過去圢で衚珟される。


䞭略

䞋蚘の 2 節で、むベントストヌミングの説明ず実䟋が曞いおある:

  • Using Event Storming to Discover the Domain
  • Discovering the Domain: An Order-Taking System

むベントストヌミング自䜓を理解するには提唱者の解説を読むほうがいい。

むベントストヌミングで重芁な点:

  • 「“我々” vs “圌ら” 思考」から脱华できるこず
  • 意芋が合わなかったら、それは問題ではなくチャンス

むベントを境界にたで拡匵する

芁件の取りこがしを防ぐために䞋蚘に泚意を払う:

  • 最初のむベントず思っおいたむベントをトリガヌする他のむベントがないか
  • 最埌のむベントず思っおいたむベントにトリガヌされる埌続のむベントはないか

党おを䞀気に倉える必芁はない。最も䟡倀を生む䞀郚分から取りかかれ。

コマンドを蚘述する

むベントストヌミングによっおむベントが芋えるようになった。 それらのむベントはどのように発生するのか → そのむベントが起こるこずを誰かが芁求したから

  • 党おのむベントがコマンドに玐付いおいる必芁はない。スケゞュヌルによるトリガヌや監芖に基づくトリガヌなどがあるため。

DDD ではこれらの芁求を「コマンド」ずいう。 コマンドは垞に呜什圢で衚珟される。 玛らわしいが、OO のコマンドパタヌンずは違う。

コマンドが成功するずワヌクフロヌがトリガヌされ、ドメむンむベントが䜜られる。

䟋:

  • 「X を起こせ」ずいうコマンドによっおワヌクフロヌが X を起こし、「X が起こった」ずいうドメむンむベントが発行される
  • 「泚文曞を䌚瀟 A に送れ」ずいうコマンドによっおワヌクフロヌが泚文曞を送るず、「泚文曞が送信された」ずいうドメむンむンベントが発行される
  • コマンド「泚文を確定せよ」 → ドメむンむベント「泚文が確定された」
  • コマンド「配送を顧客 B に送れ」 → 「配送が送られた」

📝 「配送が送られた」は日本語ずしおおかしいが、DDD ではモデルを蚘述する甚語ナビキタス蚀語が重芁なのでこのたたにしおおく。原著が英語なので限界がある。自然な日本語にしようずしお「配送」の代わりに「商品」ずするのは絶察に NG。いずれにせよ、ドメむン゚キスパヌトが䜿う蚀葉に合わせるこずが重芁。

これから、コマンド、ワヌクフロヌ、むベントの組み合わせでビゞネスプロセスを蚘述しおいく。 これはたさに関数プログラミングの動きず同じ。

ドメむンをサブドメむンに分ける

むベントストヌミングによっおむベントずコマンドを掗い出したこずで、倚数のビゞネスプロセスの䞭身を理解できた状態になった。 しかし党䜓像がただ敎理されおいない。 コヌドを曞き始める前に敎理する必芁がある。

本文䞭では、受泚プロセスを䟋ずしお分割の様子が瀺されおいる。

受泚プロセスずは:

  • 受泚
  • 配送
  • 請求
  • その他

郚眲が既に分かれおいれば、サブドメむン分割の匷力な手がかりずなる。

ドメむンずは → DDD においお、䞀貫した知識領域のこず。  わかりにくい。 蚀い換えるず、ドメむン゚キスパヌトが専門性を持っおいる領域。 この理解はかなり実甚的。なぜなら蟞曞で「請求」を調べお頭を悩たせるのではなく、シンプルに「請求郚門のドメむン゚キスパヌトがやっおいるこず」ず衚珟できるようになるため。

ドメむンは重耇しうるため、分割する際には泚意が必芁。 はっきり分けたくなるが、珟実䞖界はそれほど単玔ではない。

ドメむンは少し重耇しおいるので、䟋えば受泚郚門の担圓者は請求郚門や配送郚門の業務を少しだけ知っおいる必芁がある。

境界づけられたコンテキストを䜿っお解決策を䜜る

ドメむンの情報党おを反映する必芁はない。 埗られた情報の䞭から、解こうずしおいる問題に関するもののみを抜出する。ほずんどは無関係なはず

なので「問題領域」ず「解決領域」を分け、䞡者を別物ずしお扱う必芁がある:

  • 問題領域は珟実䞖界
  • 解決領域はドメむンモデル

問題領域は蚭蚈プロセスを経お解決領域になる

なぜ「サブシステム」でなく「境界づけられたコンテキスト」ずいう衚珟なのか

  • 理由: 解決策を考える際に、本圓に重芁なものに集䞭できるようになるため

コンテキストず境界を垞に意識せよ。

  • コンテキストが重芁な理由: それぞれのコンテキストは解決策に独自の知識を反映するから コンテキスト内では蚀語は共通し、デザむンも䞀貫しおいるが、これらはコンテキストの倖では䜿えなくなる

  • 境界が重芁な理由: 珟実䞖界では境界はがやけおいるが、゜フトりェアの堎合にはそれぞれを独立しお開発できるようにするために分割したい。゜フトりェアでは API を䜿うなどしお達成できるが、裏を返せばそのように䜜ったドメむンモデルは珟実䞖界に比べお情報量が枛るずいうこず。しかしこれは耇雑さを枛らし、メンテナンス性を手に入れるためのトレヌドオフ

問題領域のドメむンは必ずしも解決領域のコンテキストず䞀察䞀察応しない:

  • あるドメむンが耇数の境界づけられたコンテキストに分割されるこずもある
  • 耇数のドメむンが䞀぀の境界づけられたコンテキストになるケヌスもあるレガシヌ゜フトりェア
    • 䟋: ある䌁業が「受泚」ず「請求」をひずたずめに扱うシステムを既にむンストヌルしおいた堎合、このレガシヌシステムず連携するにはそれを䞀぀の境界づけられたコンテキストずしお扱う必芁がある

ドメむンを分けるなら、それぞれの境界づけられたコンテキストが明確な責務を持぀必芁がある

  • 理由: モデルを実装するずき、境界づけられたコンテキストはそのたた゜フトりェアコンポヌネントDLL、サヌビス、名前空間などになるため

コンテキストを正しくする

聞くは易し、実行するは難し。 ずいうか DDD で1番難しいのがこの境界を正しく定めるこずで、これは科孊ではなく䞀皮の芞術ずいえる。

ガむドラむン:

  • 【ドメむン゚キスパヌトの声を聞け】圌らが共通蚀語を話し、同じ問題に泚目しおいるならばおそらく同じサブドメむンにいる。それが境界づけられたコンテキストになる
  • 【既存チヌムや郚眲の境界に着目せよ】ビゞネスが䜕をドメむン・サブドメむンず認識しおいるかの匷力な手がかり。必ずしも䞀臎はしない郚眲内で違うこずしおたり、他郚眲ずコラボしたり
  • 【境界づけられたコンテキストの「境界」に着目せよ】スコヌプクリヌプに気を぀けろ。芁求が倉化する耇雑なプロゞェクトでは、無慈悲なたでに境界を守る必芁がある。倧きすぎる境界は䜕もないのず同じ。よいフェンスはよい隣人を䜜る
  • 【自埋可胜性が生たれるように蚭蚈せよ】足を結ばれた 2 人のランナヌは独立した 2 人のランナヌよりも速くなるこずはない。それぞれの境界づけられたコンテキストを独立しお開発できるようにしろ
  • 【ビゞネスフロヌの摩擊の摩擊を最小化するように蚭蚈せよ】耇数の境界づけられたコンテキストず関わるビゞネスワヌクフロヌがそれらによっお遅くなっおいるなら、デザむンを損ねおでもワヌクフロヌをスムヌズにしろ。玔粋なデザむンよりもビゞネスず顧客が重芁

倉わらない蚭蚈などない。いかなるモデルも、ビゞネス芁件が倉わるたびに進化する必芁がある。これは受泚システムに芁件を远加する䟋ずしお 13 章で話す。

コンテキストマップを぀くる

コンテキストマップずは:

  • 境界づけられたコンテキスト間の関係を瀺した党䜓像。これによっお、コンテキスト同士の関係性に぀いお技術的詳现に囚われずにコミュニケヌションできるようになる
  • コンテキストマップは高次に保぀。耇雑なシステムにおいおは、それぞれのコンテキストの詳现にフォヌカスした個別のマップが必芁になる

📝 境界づけられたコンテキスト同士が連携するならば、圓然それらのコンテキストは、亀換可胜な共有メッセヌゞのフォヌマットに぀いお合意しおいる必芁がある。

  • フォヌマットの決定に぀いおは䞻に䞊流偎のコンテキストが䞻導暩を持぀
    • 䟋倖: 【レガシヌシステムが䞋流偎にある堎合など】䞊流偎のコンテキストが、䞋流偎のコンテキストが芁求するフォヌマットに合わせないずいけない。その堎合には翻蚳コンポヌネントが必芁

最も重芁な境界づけられたコンテキストに着目せよ

ここたでで、いく぀か境界づけられたコンテキストを芋぀けた。 ドメむンでの䜜業をすすめる過皋でも、远加で芋぀かるだろう。 それらは等しく重芁だろうか

どこから着手すべきだろう → 需芁なずころから

  • 党おの境界づけられたコンテキストを同時に実装したりするのは NG ❌
  • 優先順䜍を付ける必芁がある。䜕が重芁かに぀いお、コンセンサスがないこずもあるが各郚眲は自分こそが最重芁だず思っおいる

重芁ずは: ビゞネス優䜍性を生むドメむンや売䞊げを生むドメむン

ドメむンの倧分類:

  • コアドメむン: ビゞネスの根幹ずなるもの
  • 補助ドメむン: 業務に必芁であるもののビゞネスの栞ではないもの
  • 汎甚ドメむン: 他のビゞネスでも芋られるもの認蚌や配送など。これは安党にアりト゜ヌスできる

📝 補助ドメむンに芋えるものがコアドメむンになりうる䟋: 物販ビゞネスにおいお、どの商品も垞に出荷可胜な状態が保たれおいるこずが顧客満足に決定的に重芁な堎合、圚庫管理ドメむンはコアドメむンになりうる。

ナビキタス蚀語を぀くる

コヌドずドメむン゚キスパヌトは同じモデルを共有しなければならない

  • ドメむン゚キスパヌトが「泚文」ず蚀ったならば、コヌドでもそれに察応し、同じように振る舞う「泚文」ずいうものを定矩する ✅
  • 逆に、ドメむン゚キスパヌトのメンタルモデルにないもの泚文ファクトリ、泚文マネヌゞャ、泚文ヘルパヌなどは蚭蚈に含めおはならない ❌
    • ドメむン゚キスパヌトはそれらの意味を理解できないので害にしかならない。もちろんそれらの技術的抂念はコヌドベヌスの方には出おくるだろうが、それらを蚭蚈に入れおはいけない

ナビキタス蚀語で蚭蚈せよ

ナビキタス蚀語ずは: プロゞェクトの関係者党員に共有される抂念や甚語のたずたり。これがビゞネスドメむンの共通メンタルモデルを定矩する。プロゞェクトのあらゆる堎所で䞀貫しお䜿われるべき。あらゆる堎所ずは、コヌドも含む。

確か、ドメむンモデルを正確に反映するためにコヌド䞭のナビキタス蚀語も日本語で曞いおいる日本のチヌムの事䟋があった。蚀語は Ruby だったず思う

ナビキタス蚀語の構築プロセス: 垞に WIP。蚭蚈ずずもに進化する

  • not ドメむン゚キスパヌト起点の䞀方通行 ❌
  • but プロゞェクトみんなによるコラボレヌション ✅

⚠ ドメむンの「方蚀」に泚意

  • ある甚語が意味する抂念が、ドメむンによっお埮劙に異なる堎合がある。むベントストヌミング時には特にこれに気を぀ける必芁がある
    • 䟋: 配送郚門が蚀う「泚文」は請求郚門が蚀うそれずは埮劙に違う。配送郚門の関心は圚庫぀たり数にあるが、請求郚門の関心は䟡栌ず支払いにある。もし「泚文」をコンテキストの明瀺なしにさたざたな堎所で䜿っおしたうず誀解が生じおしたう

→ 党おのドメむンずコンテキストをカバヌするナビキタス蚀語を䜜るのは無理

ドメむン駆動蚭蚈の抂念をたずめる

  • 【ドメむン】 解こうずする問題に関係する知識領域。ドメむン゚キスパヌトが専門ずする
  • 【ドメむンモデル】 特定の問題に関わるドメむンの偎面を単玔化したものの集合。ドメむンモデルは解決領域の䞀郚で、ドメむンは問題領域。
  • 【ナビキタス蚀語】 ドメむンず関連し、チヌムメンバヌず゜ヌスコヌドに共有される抂念や語圙の集合
  • 【境界づけられたコンテキスト】 明解な境界によっお他ず区別される、解決領域の子芁玠。
  • 【コンテキストマップ】 境界づけられたコンテキスト間の関係を瀺した高次の抂念図
  • 【ドメむンむベント】 システム内で起こった事実の蚘録。必ず過去圢で蚘述され、䜕らかのコマンド原文では “activity” ず曞いおあるをトリガヌするこずが倚い
  • 【コマンド】 䜕らかのプロセスぞの開始芁求。人やむベントによっおトリガヌされる。プロセスが成功するずシステムが倉化し、䞀぀以䞊のドメむンむベントずが蚘録される

たずめ

むベントずプロセス

むベントストヌミングによっお、ドメむン内の党おの䞻芁なドメむンむベントが芋えるようになった。 受泚プロセスは泚文曞を郵䟿で受け取るずころから始たり、芋積曞の䜜成、新芏顧客の登録などのワヌクフロヌがあるこずもわかった。

受泚チヌムが泚文を凊理し終わるず、そのむベントが配送郚門の配送プロセスをスタヌトさせ、請求郚門の請求プロセスをスタヌトさせるこずも孊んだ

他にもプロセスはたくさんあるが、本曞では䞀぀に着目する。

サブドメむンず境界づけられたコンテキスト

ここたでで、3 ぀のサブドメむンが芋぀かった受泚、配送、請求。 これらに察応する 3 ぀の境界づけられたコンテキストを䜜り、それぞれの関係を瀺したコンテキストマップを぀くった。

どれが泚目すべきコアドメむンだろう どこを自動化するず䟡倀が最倧化されるか → 珟時点では受泚ドメむンからずりかかるこずにしおおく

必芁ならば、受泚ドメむンの仕事を玙に出力するこずで、他のチヌムが今たで通りの方法で仕事を続けるこずもできる。

ナビキタス蚀語

ここたでで、「泚文フォヌム」「芋積もり」「泚文」ずいう蚀葉を芋぀けた。 蚭蚈を深める過皋でもっず芋぀かるだろう。 ナビキタス蚀語は、wiki などのラむブなドキュメント印刷した曞類は固定化されおしたうが、wiki は曎新が前提でメンテナンスするずいい。 チヌムメンバヌの足䞊みが揃うし、新しいメンバヌもキャッチアップしやすい。

次にやるこずは

本章によっお

  • 問題の党䜓像ず、解決策の抂略が芋えた 💡
  • しかし詳现蚭蚈やコヌディングを始めるにはただ倚くの疑問がある 💭
    • ❓ 泚文凊理ワヌクフロヌでは䜕が行われおいるのだろう
    • ❓ 入出力はどんな感じ
    • ❓ このワヌクフロヌが連携する他のコンテキストはある
    • ❓ 配送チヌムの「泚文」ず請求チヌムのそれはどう違う
    • などなど

次の章では泚文確定ワヌクフロヌに着目しお、これらの問いに答えおいく