Type Level Domain Modeling
型のみでDomain Modelingをする
UMLなどの外部のツールを使用せずに、仕様と実装を直接管理できる
non developperであるDomain Expertもこれを見てレビューする
Documenting the Domain Modeling in Simple DSLを元に作っていく感じ #??
ユビキタス言語で名詞になるもの
primitive typeで表現できるような概念はnewtypeなどで定義する
ユビキタス言語的には、stringのような概念は無いので逐一それ用の型を用意しようという話
その組み合わせの概念は、直和や直積の形で型を定義する
code:hs
data OrderQuantity = UnitQuantity Unit
| KilogramQuantity Kilogram
現時点で不明な型がある場合
とりあえず明示的にUndefined型にしておき、わかった時点で書き換える
F#ならexn型を使用して、type Undefined = exn型を作る
これで型レベルでの静的検査には通過できる
が、実装時には無理になるので、そのタイミングにでもUndefinedを別のものに替える
例えば、ShippingAddressとBillingAddressのような型が現れた時
これらの型の中身が同じものなのかどうかはDomain Expertに訊く
彼が別物といえば、全く同じ構造であっても、別物として定義しておく
smart constructorを使うなど?
型定義の話では出てこないか?
ユビキタス言語で動詞になるもの
Modelの流れをWorkflowで図示する
関数型で定義する
code:fs
type ValidateOrder = UnvalidateOrder -> ValidatedOrder
これ簡単そうに見えて難しいよなmrsekut.icon
選ぶ動詞がかなり適切でないとミスる
右辺に来るものが「何の」状態を表しているのかを明確にわかるものにしていないといけない
出力が複数ある場合は直積、直和で表現する
入力が複数ある場合は
ORの場合は直和
ANDの場合は、
カリー化して引数の数を増やす
こうすると直積にするよりもDIしやすい
関数に対してDI
特に、入力が「本当の入力」ではなくただの依存関係である場合は、こちらのほうが良い
ただし、各値がめっちゃ密接なものの場合はRecordにしても良い
副作用を関数型で表現する
失敗の可能性がある場合はResult型を使用する
非同期処理の場合はAsync型を使用する
複合したやつはこんな感じ
code:ex.fs
type ValidateOrder =
UnvalidatedOrder -> Async<Result<ValidateOrder, ValidationError list>>
通信系の処理では、Async&Resultの組み合わせはよくあるのでエイリアスを定義しておくといい
code:fs
type ValidationResponse<'a> = Async<Result<'a, ValidationError list>>
仕様を満たした型を定義することで、必要なtestの量を減らす
参考
/mrsekut-book-97816805025/092 (CHAPTER 5 Domain Modeling with Types)~