関数型ドメインモデリング ドメイン駆動設計とF#でソフトウェアの複雑さに立ち向かおう
https://scrapbox.io/files/6763d3fde4b8ae48c1f85d17.webp
まずは自然言語で条件と型を書いていくのが良さそうrkasu.icon
第1部 ドメインの理解
第1章 ドメイン駆動設計の紹介
コーディングはソフトウェア開発の一側面にすぎません。きちんと設計したり、コミュニケーションをとったりすることも同じくらい重要です。もしかしたら、それらのほうが大切かもしれません。
それな。
ビジネスイベント(ビジネスロジック)とそれに関連するワークフローを発見するための共同プロセス
様々なドメインエキスパートを集めて質問して回答をもらうをお互い繰り返してビジネスイベント明らかにしていくワークショップ
ドメインとはドメインエキスパートが専門としているものごとただそれだけ ドメイン駆動設計のもっとも重要な課題の一つはこれらのコンテキストの境界を正しく設定するこ 第2章 ドメインの理解
第3章 関数型アーキテクチャ
「システムコンテキスト」は、システム全体を表す最上位の概念です。
システムコンテキストは、複数の「コンテナ」から構成されます。それらは、Web サイト、Web サービス、データベースなどのデプロイ可能な単位です。
次に各コンテナは、多数の「コンポーネント」から構成されます。それらは、コードの構造において主要な構成要素です。
最後に、各コンポーネントは、多数の「クラス」(関数型アーキテクチャでは「モジュール」が使われます)から構成されます。それらには低レベルのメソッドや関数の集合が含まれます。
境界づけられたコンテキスト間のデータ転送
渡されるオブジェクトは境界内で定義されたオブジェクトでありこれをドメインオブジェクトと呼ぶ
https://gyazo.com/ef55c83fc30dc611c5fdc7d836c99d2f
シリアライズされてから他に共有される
データ転送オブジェクトのことをDTOと呼ぶ
第2部 ドメインのモデリング
第4章 型の理解
TypeScriptでいうと判別ユニオンだな
code:typescript
type Circle = {
kind: 'circle';
radius: number;
};
type Rectangle = {
kind: 'rectangle';
width: number;
height: number;
};
type Triangle = {
kind: 'triangle';
base: number;
height: number;
};
type Shape = Circle | Rectangle | Triangle;
kindをみて判別できる
F#のような関数型言語では必ず何かを返さないといけないのでvoidは使えない TypeScriptでもそうしたいな。
普段から意識すればできるかしら?rkasu.icon
第5章 型によるドメインモデリング
ドメインモデルを考えるとき以下のパターンを考える
単純な値
単にstringやIntとして比較せずにラッパー型を定義してあげる
例えばOrderIdとProductCodeは同じIntだけど混同されないようにする
ANDによる値の組み合わせ
ORによる選択肢
ワークフロー
特定の何かを表すのがエンティティである
例えば一意な識別子(ID)など
本章で新しく紹介したDDDの用語を列挙します。
値オブジェクトは、アイデンティティを持たないドメインオブジェクトです。同じデータを含む2つの値オブジェクトは同一とみなされます。値オブジェクトは不変でなければならず、一部が変更されると別の値オブジェクトになります。値オブジェクトの例としては、名前、住所、場所、金額、日付などがあります。
エンティティは、プロパティが変更されても持続する本質的なアイデンティティを持つドメインオブジェクトです。エンティティオブジェクトは通常、IDまたはキーフィールドを持ち、同じID/キーを持つ2つのエンティティは同じオブジェクトであるとみなされます。エンティティは通常、ドキュメントのように寿命と変更の履歴を持つドメインオブジェクトを表します。エンティティの例としては、顧客、注文、製品、請求書などがあります。
集約は関連するオブジェクトの集まりで、ドメイン内の整合性を確保するためと、データトランザクションの原子単位として使用するために、単一のコンポーネントとして扱われます。他のエンティティは、「ルート」として知られる集約の「トップレベル」のメンバーのIDである識別子によってのみ、集約を参照するべきです。
第6章 ドメインの完全性と整合性
境界づけられたコンテキストが重要
第7章 パイプラインによるワークフローのモデリング
booleanで型を定義しない。
ユニオン型で定義する話ここでもでてきた
第3部 モデルの実装
第8章 関数の理解
入力をあらかじめ制限して不正な値を入れない
そもそも排除しておく
もしくは型を拡張してオプショナルにして受け付けておく
第9章 実装:パイプラインの合成
第10章 実装:エラーの扱い
第11章 シリアライズ
第12章 永続化
第13章 設計を進化させ、きれいに保つ
参照
我々は業務アプリケーションをつくって運用していますが、いわゆる例外を処理し忘れてサーバーが落ちたとか、500エラーになったといったことがほぼ起きていません。これまでのアプリケーションで起きていた、「ここのフロー実装し忘れていました」「ユニットテストでエッジケーステストをしていませんでした」といったことが原因で障害を起こすことはかなり減りました。堅牢性という意味でのメリットはものすごく大きいです。
これはでかいな。。