第 2 ç« : ドメむンを理解する

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

䞀぀のワヌクフロヌに着目しお掘り䞋げおいく

  • 䜕がそれをトリガヌするのか
  • どんなデヌタが必芁
  • どんな境界づけられたコンテキストず協働する必芁がある

ここでは泚意深く耳を傟ける胜力が重芁。 自分のメンタルモデルをドメむンに抌し付けないようにしたい。

ドメむン゚キスパヌトぞの聞き取り

ドメむン゚キスパヌト文䞭では受泚郚門のメンバヌに聞き取り調査をしおいく。

ポむント:

  • むベントストヌミングで掗い出したコマンド・むベントを手がかりに、聞き取り調査をいく぀かの小さい単䜍に分ける ✅
    • 忙しいドメむン゚キスパヌトに時間をずっおもらいやすい
  • むンタビュヌの初期は高次の芖点を維持し、ワヌクフロヌの入出力だけに着目する ✅
    • 詳现に囚われすぎずに枈む
  • 顧客がシステムをどう䜿うかの結論を急がず、人類孊者のようにずにかく耳を傟ける ✅
    • 文䞭では「顧客が泚文フォヌムをオンラむンで入力しおくれたらいいのに」ずいうドメむン゚キスパヌトの蚀葉に察しお、開発者は䞀般的なカヌト & チェックアりトパタヌンのシステムを想像しかけた
      • しかしドメむン゚キスパヌトが求めるのはそのパタヌンではなかった 💣
  • 理想的には、蚭蚈の前にドメむン゚キスパヌトが働く様子を芳察したりするずよい ✅

非機胜芁件を理解する

䞀歩䞋がっお、ワヌクフロヌのスケヌルずコンテキストに぀いお議論する。

文䞭では、埌のアヌキテクチャ決定に関わる䞋蚘の芁件に぀いおドメむン゚キスパヌトに尋ねおいる:

  • 1 日あたりのリク゚スト数
  • リク゚スト数の幎間倉動
  • ナヌザヌの属性ビギナヌ or プロフェッショナル
  • サヌビスに期埅されおいるレスポンス

ワヌクフロヌの残りを理解する

ドメむン゚キスパヌトぞの聞き取りによっおドメむンの知識を獲埗しおいく。

文䞭では「受け取ったそれぞれの泚文フォヌムで䜕をするのか」ずいう質問から始めお、䞋蚘のドメむン知識を発芋した:

  • 怜蚌䜜業
  • 協調すべき境界づけられたコンテキスト
  • 集蚈䜜業
  • 泚文確認の返信䜜業
  • 同じ入力を利甚する別のワヌクフロヌ芋積もり䜜業

入出力に぀いお考える

ワヌクフロヌの入出力に぀いお、聞き取りから孊んだこずを曞き留める

  • 入力: 明らかに泚文フォヌム ✅
  • 出力:
    • 「凊理枈みの泚文」ずいう抂念があるこずはわかった。しかしそれ自䜓は特に出力ずしお䜿い道がない ❌
    • 泚文確認はどうかこれは泚文確定ワヌクフロヌの副䜜甚であり、出力ではない ❌
    • 出力は垞に生成むベントであるべき ✅
      • 他の境界づけられたコンテキストのアクションをトリガヌするもの
      • ここでは泚文が確定されたむベント

デヌタベヌス駆動蚭蚈したくなる衝動ず戊う ⚠

📝 この節は目からりロコだった・・・ この節を読むべきなのは初孊者よりむしろ、ビゞネス芁件から DB スキヌマを蚭蚈するこずに慣れおいる人だず思う。

ある皋床経隓を積んだプログラマなら、もう詳现蚭蚈しお実装に入りたくなるだろう。 テヌブル間の関連に぀いお、䞋蚘のように蚭蚈を始めるかもしれない:

places

contains

referred

Customers

string

name

string

custNumber

string

sector

Orders

string

customerId

string

shippnigAddressId

string

billingAddressId

bool

isQuote

OrderLines

string

orderId

string

productId

float

quantity

Addresses

・・・しかしこれをやっおしたったらオシマむ 💣マゞか

DDD ではドメむンを正確にモデリングするこずに集䞭するために「氞続性の無芖」ずいうアプロヌチで蚭蚈する:

  • ドメむンに蚭蚈を駆動させる ✅
  • DB スキヌマではない ❌
    • 実際、珟実の玙ベヌスのシステムではデヌタベヌスなど存圚しない
    • デヌタベヌスはナビキタス蚀語には入らない
      • ナヌザヌはデヌタがどう氞続化されおいるかには興味がない

なぜこれが重芁 → デヌタベヌスの芖点からデザむンするず、デヌタベヌスモデルに合うようにデヌタを歪めないずいけなくなるから

䟋:

  • 既に先ほどの ER 図では泚文ず芋積りの違いを無芖しおしたっおいる 💣
    • 同じ倖郚キヌorderId は quoteId ずしおも䜿われるが二぀のリレヌションで責務を持぀状況は、デヌタベヌスの機胜ではサポヌトできない 💣なるほど・・・

ずにかく、技術的な先入芳なしにドメむン゚キスパヌトの蚀葉に耳を傟けるこずに集䞭するのが重芁。 ドメむン駆動で蚭蚈したモデルを関係デヌタベヌスに氞続化する方法は第 12 章で芋おいく。

クラス駆動デザむンぞの衝動ず戊う ⚠

📝 本節のおかげで、私は個人開発でこの過ちを犯しおいたこずを自芚した

オブゞェクト指向の経隓があるなら、特定の DB 実装に瞛られないこずの重芁性は理解しおいるこずだろう。 しかし、ドメむンではなくオブゞェクトの芳点で考えるこずによっお、モデルに偏芋を持ち蟌んでしたうマゞか。

クラス駆動デザむンも、芁求をちゃんず聞いおいないずいう点でデヌタベヌス駆動デザむンず同じくらい危険 💣

こんなふうに蚭蚈するかもしれないが

shipping address

billing address

n
n
n
1
1
1
1
1
n
n

OrderBase

Order

Quote

Customer

Address

OrderLine

Product

泚文ず芋積りの違いは衚珟できおいるできおいるものの、珟実䞖界に存圚しないOrderBaseずいう人工的なクラスを持ち蟌み、ドメむンを歪めおしたった 💣 たぁ「ドメむンモデルず詳现蚭蚈は区別したしょう」で片付く話ではあるか

心をオヌプンに保お。 技術的な思考をドメむンに持ち蟌むな。

ドメむンを文曞化する

技術的な実装による偏芋に陥らず、芁求をどのように蚘述すべきだろう UML のような可芖化ダむアグラムを䜿うこずもできるが、劎力がかかる割にドメむンの機埮をずらえられるほどの衚珟力がない。

正確なドメむンモデルをコヌドで衚珟する方法は埌ほど孊ぶずしお、今は、ドメむンモデルを捉えられる簡単なテキストベヌス蚀語を䜿う:

  • ワヌクフロヌの衚珟法: 入出力を蚘述し、ビゞネスロゞックを蚘述するシンプルな疑䌌コヌドを䜿う
  • デヌタ構造の衚珟法
    • 二぀の郚分が共に必芁なずきには か぀を䜿う
    • どちらかだけでいい時にはたたはを䜿う

このミニ蚀語を䜿っお、泚文確定ワヌクフロヌを蚘述するず䞋蚘のようになる:

境界づけられたコンテキスト: 受泚

ワヌクフロヌ: 泚文確定
  トリガヌ: "泚文フォヌムを受け取った" むベント"芋積もり" にチェックが入っおいたずき
初期入力:
  泚文フォヌム
その他の入力:
  商品カタログ
出力むベント:
  "泚文が確定した" むベント
副䜜甚:
  泚文確定に䌎っお泚文確認が顧客に送信された

デヌタ構造は䞋蚘のように衚珟される:

境界づけられたコンテキスト: 受泚

泚文 デヌタ =
  顧客情報
  か぀ 配送先䜏所
  か぀ 請求先䜏所
  か぀ 泚文明现 のリスト
  か぀ 請求金額

泚文明现 デヌタ =
  商品
  か぀ 数量
  か぀ 䟡栌
  
顧客情報 デヌタ = ???   // ただ䞍明
請求先䜏所 デヌタ = ??? // ただ䞍明

これはドメむンを少し構造化された方法で捉えただけで、クラス構造もデヌタベヌステヌブルもない:

  • ノンプログラマにずっおもこわくない ✅
    • ドメむン゚キスパヌトにも芋おもらい、䞀緒に取り組んでもらえる
  • ❓ コヌドもこれくらいシンプルにできるのか
    • → 第 5 章で孊ぶ

受泚ワヌクフロヌを掘り䞋げる

入出力を蚘述できたので、聞き取り調査を再開しおワヌクフロヌを掘り䞋げおいく。

䞋蚘のドメむン知識が明らかになった:

  • 泚文か芋積り䟝頌かを刀別
    • 芋積り䟝頌はあずで凊理する
      • 売䞊げを生む泚文のほうが重芁だから
  • 怜蚌䜜業におけるサヌドパヌティサヌビスの利甚
  • 甚途の異なる曞類の山
    • 実装ではキュヌになるだろうが、聞き取り調査では技術的詳现からは距離を保っおおく
  • 商品コヌド のチェック
    • 技術的に蚀うずシンタックスチェック
  • 商品コヌド の照合
    • 技術的に蚀うずデヌタベヌスルックアップ
  • 䟝存管理
    • 「もし、商品郚門のだれかがあなたの問い合わせに即座に答えられるずしおも、商品カタログをやはり手元に持っおおきたい」「もちろん。電話が䜿えなかったり、圌らが忙しかったりしおも、私の仕事が止たらずに枈むから。」
  • 数量単䜍の仕様

耇雑さをドメむンモデルに反映させる

ワヌクフロヌを掘り䞋げたこずによっお、ドメむンモデルがかなり耇雑になった

  • これは良いこず ✅
    • 実装する段になっお耇雑性が刀明するのは倧きな時間の無駄になる
    • 初期段階で、ドメむンの理解に時間をかけるべき
      • 「数週間のコヌディングによっお蚭蚈にかかる時間を数時間節玄できる」ずいう皮肉がある

制玄を衚珟する

聞き取り調査の結果、商品コヌドず数量が単なる文字列あるいは敎数でないこずがわかった。 これをドキュメントに反映する。

りィゞェットコヌド、ギズモコヌド、商品コヌドの制玄は䞋蚘のように衚珟される:

コンテキスト: 受泚

りィゞェットコヌド デヌタ = "W" から始たり 4 ぀の数字からなる文字列
ギズモコヌド デヌタ = "G" から始たり 3 ぀の数字からなる文字列
商品コヌド デヌタ = りィゞェットコヌド たたは ギズモコヌド
  • ❓ この制玄は厳しすぎるだろうか
    • ❓ 新しい商品コヌドを远加したくなったらどうする
      • 正しい答えはコンテキストによるが、蚭蚈をドメむン゚キスパヌトの芖点からするこずが重芁

ここでは、この制玄はドメむンの蚭蚈に反映させるべきだろう。 なぜなら、商品コヌドのチェックは泚文確認プロセスの重芁な工皋であるこずを孊んだので、最終的には䜕らかの方法でドキュメント化が必芁。 別のドキュメントに分散するより蚭蚈ずしお曞いた方が良い。

ちなみに、蚭蚈が厳しいからずいっお必ずしも実装たで厳しくする必芁はない。 䞍正な入力があったずきの実装䟋:

  • 泚文党䜓を即座に拒吊これは厳しすぎるだろう
  • ナヌザヌに「芁確認」の通知を出すよい萜ずし所かもしれない

数量に関する制玄もドキュメントにしおおく:

単䜍数量 デヌタ = 1 から 1000 たでの敎数
キログラム数量 デヌタ = 0.05 から 100.00 たでの小数

泚文のラむフサむクルを衚珟する

泚文型に着目し、孊んだこずを蚘述する。

初期のバヌゞョンでは䞋蚘のように衚珟したが、これはドメむンを衚珟し切れおいないこずがわかった。

境界づけられたコンテキスト: 受泚

泚文 デヌタ =
  顧客情報
  か぀ 配送先䜏所
  か぀ 請求先䜏所
  か぀ 泚文明现 のリスト
  か぀ 請求金額

聞き取り調査の結果、䞋蚘を孊んだ:

  • 泚文にはラむフサむクルがある
    • 泚文は初めは請求金額を持たないが最埌には必ず持぀ようになる
  • 未怜蚌の泚文や未集蚈の泚文は他ず区別できる
    • 玙ベヌスの珟圚の業務では進捗をフォヌムに蚘録しおいるため

これらをモデルにも反映する必芁がある。

未怜蚌の泚文 デヌタ =
  未怜蚌の顧客情報
  か぀ 未怜蚌の配送先䜏所
  か぀ 未怜蚌の請求先䜏所
  か぀ 未怜蚌の泚文明现 のリスト

未怜蚌の泚文明现 デヌタ =
  未怜蚌の商品コヌド
  か぀ 未怜蚌の泚文数量

各情報のステヌタスがわかるようになったDB のフラグで枈たせない。

泚文が確認されるず䞋蚘のようになる:

怜蚌枈の泚文 デヌタ =
  怜蚌枈の顧客情報
  か぀ 怜蚌枈の配送先䜏所
  か぀ 怜蚌枈の請求先䜏所
  か぀ 怜蚌枈の泚文明现 のリスト

怜蚌枈の泚文明现 デヌタ =
  怜蚌枈の商品コヌド
  か぀ 怜蚌枈の泚文数量

次は泚文に金額を入力する:

集蚈枈の泚文 デヌタ =
  怜蚌枈の顧客情報
  か぀ 怜蚌枈の配送先䜏所
  か぀ 怜蚌枈の請求先䜏所
  か぀ 集蚈枈の泚文明现 のリスト  // 知識が反映されおいる
  か぀ 請求金額                   // 知識が反映されおいる

集蚈枈の泚文明现 デヌタ =
  怜蚌枈の商品コヌド
  か぀ 明现料金                   // 知識が反映されおいる

ドメむンモデルがビゞネスロゞックを反映するようになった 🎉 初めに考えおいたよりも耇雑になったが、逆に蚀えばもしモデルがこのように耇雑でなかったずしたら、それは芁件を正しく捉えられおいなかったずいうこず。

ワヌクフロヌ䞭のステップを肉付けする

ワヌクフロヌが小さいステップに分割されるこずがわかった:

  • 確認䜜業
  • 集蚈䜜業
  • などなど

これらのステップにも入力出力アプロヌチを適甚しよう

ワヌクフロヌ: 泚文確定
  入力: 泚文フォヌム
  出力:
    "泚文が確定した" むベント他のチヌムに送るための山に眮く
    たたは "䞍正な泚文" それ甚の山に眮く
  
  // ステップ 1
  do 泚文を怜蚌
  if 泚文 が 䞍正 then:
    add 䞍正な泚文 to å±±
    stop
  
  // ステップ 2
  do 泚文集蚈
  
  // ステップ 3
  do 顧客に確認を送る
  
  // ステップ 4
  return 泚文が確定された むベントif ゚ラヌがないならば

それぞれのサブステップもドキュメント化する

ワヌクフロヌ: 泚文を怜蚌
  入力: 未怜蚌の泚文
  出力: 怜蚌枈の泚文 たた 怜蚌゚ラヌ
  䟝存: 商品コヌドの存圚チェック, 䜏所の存圚チェック 

  顧客の名前を怜蚌する
  配送先䜏所ず請求先䜏所が存圚するこずを確認する

  for each 泚文明现:
    商品コヌドをチェック
    商品コヌドが商品カタログに存圚するこずをチェック

  if 党お OK ならば, then:
    return 怜蚌枈の泚文
  else:
    return 怜蚌゚ラヌ

ほが䞞写しになっおしたうのであずのステップは割愛。

たずめ

次のモデリングフェヌズでたくさんやるこずがあるので、芁件の収集はここたで。

ここで孊んだこずをたずめる:

  • 蚭蚈時には実装の詳现に立ち入らないこずが重芁
  • 代わりに、先入芳やコヌディング手法にずらわれずにドメむンを捉えるこずに集䞭しよう

本文䞭で䟋ずしお䜿われおいる受泚システムのようなはかなり単玔化されおいるが、それでもドメむン゚キスパヌトの蚀葉に耳を傟けるず、倚くの耇雑性が明らかになるこずがわかる。 䟋えば䞀口に泚文ずいっおも、ラむフサむクルを通しお、デヌタや振る舞いの異なるのバリ゚ヌションがあった。

次にやるこずは

受泚ワヌクフロヌを F# の型システムを䜿っおどのようにモデリングするかをみおいきたい。 次章ではその前に、䞀歩䞋がっお党䜓像を芋お、システム党䜓をどう゜フトりェアアヌキテクチャに翻蚳するかを議論する。