😽
【ポエム】DDDの勘所とか
ある領域(ドメイン)に存在する問題を解決したいときに採用するとメリットのありそうな開発手法。だからといって、どこでも使えばいいわけではない。
また、複雑な開発になりがちなので、何を取り込むか捨てるかの判断は重要。
良いモデルとはテストができたり・可読性があるのではなく、リリース後も含めた問題解決ができること。なので、モデリング行為で躓いた状態でプロジェクトがn年進んでしまうと、作り直したほうが良いレベルの製品ができあがって、保守性が低下してしまう。
採用しなくても良いと思われるケース
- 規模が小さい
- 複雑なビジネスドメインを扱わない
- ジュニアが多いプロジェクト
- とりあえず早く作って検証したいPoC
DDDでやるとなったときに具体的にどうするか
ドメインスペシャリストにヒアリングしてユースケース図・ドメインモデル図を書いていく。
今はChatGPTもあるので、できればMermaidでコード化しておくと補完や差分を管理できる点で望ましい。
graph TB
subgraph "製品"
User((ユーザー))
subgraph "製品登録"
Post[登録]
Edit[編集]
Show[閲覧]
end
subgraph "履歴"
ShowHistory[閲覧]
end
end
User --> Post
User --> Edit
User --> Show
User --> ShowHistory
モデルの境界を決める
話す人のコンテキストによって、「料金」や「ステータス」・「数」の概念が曖昧だと、1つのモデリングにいくつもの状態を持ってしまって複雑化する。この用語は何を指しているのかを明確にし、コンテキストが違う場合はモデリングをわける。
ORMとの付き合い方
RailsのActive Recordを使うと、DBと1:1のモデリングなってしまう。データベースは永続化の手段なので、これをそのままモデル・エンティティとして使うと単なるデータの入れ物としてしか機能せず問題解決しにくくなる。
class User < ActiveRecord::Base
validates :name, presence: true, length: { maximum: 255 }
validates :age, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
def initialize(attributes = {})
@name = attributes[:name]
@age = attributes[:age].to_i
@age = 0 if @age <= 0
end
end
u = User.new
u.name = "John"
u.age = 20
u.save
- 値を自由にセットできないようにしたり、作ってほしくないインスタンスを仮に作るのを止めて、条件を見て一発であるべきUserインスタンスを作るようにしたい
=> どういうインスタンスが存在されそうなのかはドメインスペシャリストと話す - ユーザーを作ったり、更新するユースケースを分けて、パブリックメソッド経由で更新することでどうしたいかを書くだけにする
=> どうしたいかはドメインモデル図を参考にする - トランザクションは一箇所にする、自由に更新できるようにしない。インスタンスは長く引き回さない
- 薄いORM: Data Mapperのormや、sqlcのようなSQLクエリをGo言語のコードに自動変換するツールを採用すると実装に落としやすいかも。ActiveRecordだとデータの詰め方は要検討
フレームワーク
- MVCのような3層構造だとモデルのファット化を避けるためにXxxxServiceが量産されがち
- オニオンアーキテクチャを検討する
- トレンドではなく問題解決できる技術選定をする
参考
Discussion