個人開発者向けのサービスの開発記録 #43 20240228

tyshgc
·

本日の作業

  • 🚴 分報に関する設計・実装

    • 🚴 UseCase Hooksと結合実装

  • Domain EventとPrismaの実装

  • Supabaseの設定と開通

    • Supabase Auth

    • Supabase Database

  • 🛑 🚴 イベントストーミングとサービスブループリンの融合についてzennにまとめる(休日にやる)

OOP型の集約(エンティティ)と値オブジェクトの実装

雑にまとめ。

コンテキストや集約といった形にしていますが、コンテキストは実装フェーズやモデルの蒸留度に合わせて常に見直す様にしています。つまり最初のドメインモデリングが絶対正しいわけではないし、フェーズによっては明らかにコンテキストを分けて書いた方がいい場合を除いて最初から頑張って区分けしない様にしています。要するに色々実装していく中でわかることもあるので曖昧なうちはわかることからやるっていうシンプルな考えです。

これから説明するOOP型の集約や値オブジェクトはclient side(Front End)の文脈で利用しています。client側ではユーザのインタラクションとその状態に対してあえて不完成な集約を許容しています。理由はバリデーションをこれらドメイン層に持たせてView(Formコンポーネントなど)にそのロジックを書かない様にするためです。View層とドメイン層とそれぞれでバリデーションすれば良いのでは?という意見もあると思いますが、結果的に内容が重複するのと単なる値の検証には結果ならずどちらにしても何かしらかドメインに起因したロジックになるということからこうしています。

構造

次のようにContext(境界付けられたコンテキスト)に集約エンティティがある形でディレクトリ構造もその通りに配置しています。このレイヤーにあるものは基本全てユニットテストを書く様にしています。

sharedディレクトリの配下には他のContextや集約・エンティティで共通した要素を持つ共通性のある値オブジェクトを置きます。

値オブジェクトとエンティティの抽象クラス

抽象クラスで値オブジェクトエンティティをextendできるように抽象クラスを準備します。基本継承はこれら抽象クラスのみでこれ以上の継承は行わないルールで実装しています。

  • Entity抽象クラス

    • Entityはvaluesをジェネリクスで定義できるようにしています。このvaluesはサブエンティティまたは値オブジェクトで構成されます。また、equalsでエンティティが同じものかどうかを検証できる様にしています。それと生成時にuuidを発行する様にしてオブジェクトとして一意性を担保できる様にしています。よくあるパターンでは例えばUser EntityであればUserIdで一意性を担保しますのでuuidはなくても良いとは思いますが念のため。

  • Value Object抽象クラス

    • 値オブジェクトはzodのvalidatorを生成時に渡すように定義しています。また、equalsで値オブジェクトが同じものかを検証できる様にしていますが、そもそも値オブジェクトはimmutableであることが前提なので正直なくても良いのではと思っていますが念のため。

      ValueObject抽象クラス

値オブジェクトの実装

validatorを定義するファイルと値オブジェクトのファイルは分けています。理由はvalidatorのみ参照するケースがあるためです(例えばドメインイベントでのinetrfaceにこれを活用するとか)。

  • 例)認証で利用するメールアドレスの値オブジェクト

    • validator.ts

    • value-obejct.ts

集約(ルートエンティティの実装)

サブエンティティや値オブジェクトを組み合わせて集約を表現します。「認証集約」を例にすると考えられる様子と振る舞いは次の通りです。

  • 要素

    • 認証用メールアドレス

    • 認証状態

    • 認証方法

  • 振る舞い

    • 認証用メールアドレスを参照

    • 認証用メールアドレスをセット

    • 認証状態の変更

    • 認証状態の参照

    • 認証方法の参照

※その他にも認証という事象に対して振る舞いは想定できるともいますが、その辺についての問答はChatGPT v4と壁打ちしたものがあるのでそれを残しておきます。

  • 例)認証集約(ルートエンティティ)

    • entity.ts(authStatusやauthMethodも値オブジェクトにした方が良いかも)。

という感じで実装してます。これをRepository Patternを使い永続化を行ったりUseCase Hooksと結合しています。

続きは後日書きます。

その他、メモ

← #42 #44 →

@tyshgc
デザインファーム及びスタートアップ(上場)などを経てフリーランスとして、様々なスタートアップや大手企業の新規事業の立ち上げ期における事業設計・アプリケーションの設計・開発、サービスのUX分析とデザインとエンジニアリングの両軸でお手伝いさせていただいています。 現在、個人開発者向けの支援サービスを個人開発中。 X Account: @tyshgc