🐙

俺のDDDは間違っている。けどもうこれでいいや。

2024/10/22に公開

はじめに

DDD本読んだり(尚挫折したので全然読めてない)、世間の記事を読んだ結果自分の中で歪んだDDD観が醸成された気がしますが、そんなに大きく外してない気がするのでもうこれでいいやの気持ちでまとめ、頭の中を整理しようという試みです。

まとめ(先に)


  • 現場担当者にわかるような用語をしっかり定義して二人三脚で進めよう。
  • 業務を全部まとめて考えるとヤバいので、いい感じに分けよう。ざっくりマイクロサービス境界的な感じに。
  • ビジネスロジックの分離、IFの抽象化等で、ビジネスロジックを組み込みながらSOLIDに作ろう。
  • でもフレームワークと合わないところは絶対出てくるからそれは苦しめ。

DDDの目指すところ


  • システムは業務にフィットしたものである必要がある(自明)
  • 業務は複雑である(大体の場合自明)
  • システムはSOLID等に準拠し、整然としている方がよい(自明)
  • 複雑な業務と、SOLIDなシステムの橋渡しは難しい(自明)

という条件で、いかに業務にフィットしていて、かつ、整然としたシステムを作るか?という方法論・プラクティス、設計パターンを集めたものがDDDだと思っています。

業務が複雑であるというところが条件付きとなっていますが、世の中には結構簡単な業務ももちろんあり、DDDの前提が成り立たないこともあります。
(これがいわゆる小規模システムにはDDDが向かないという話だと思っています。)

方法論・プラクティス(戦略的設計)

戦略的設計と戦術的設計とかいう用語、覚えにくすぎませんか?

戦略的設計と言われるのがDDDの方法論・プラクティスの部分です。この部分はざっくり以下


  • システムの言葉ではなく、業務に近い言葉で現場担当者と理解を醸成、定義をはっきりさせよう。(ユビキタス言語を使用したドメインエキスパートとのモデリング)
  • 業務を適切な単位で切り分けて、関係ない要素やプロパティはいったん棚上げしよう。また切り分けははっきりわかるよう管理しよう(境界付けられたコンテキスト)

尚、ここをどうやるか?というのについて、はっきりした方法論は無い!(ドン!)

一応、ユビキタス言語を使用したモデリングは、ドメインモデル(値オブジェクトとEntity)でモデリングする。というあたりはある程度巷にコンセンサスがあるうえで、sudoモデリングとかいう方法がある程度メジャーではあるようです。
何言ってるかわかりませんね。

「プロパティとメソッドを書いたクラスと少しの関数の一覧と関係性で、機能の議論すれば大体OK、クラス図は大業務単位で適切に分割する。」
くらいの意識でいいんじゃないかな、、、だめですか、、、
大事なのはDBのレコードが云々とか、外部キー制約が云々とかシステムのことはいったん忘れて、業務に近い言葉の定義を業務担当者と作り上げることだと思います。

境界付けられたコンテキストについては、大体マイクロサービスつくるのと近い感じになるのかなと思っており、REST API等でつないでよい(トランザクションレベルの強い整合性が必要とされない)なら、分けてもよいかも? くらいの雰囲気で大体近くなるんじゃないかなと思っています。

設計パターン(戦術的設計)

用語覚えにくい(再び)
こっちはもろコードの書き方に近い領域です。原典のDDDはかなりオブジェクト指向を意識した構成となっています。
パターンはいろいろあるのですが、要は以下を目指していると考えています。


  • ビジネスロジックを隔離してメンテ・テストしやすくする。(ドメイン層)
  • 出来ればインフラとか外部IFの生処理も隔離して、メンテ・テストしやすくする。(リポジトリとか)
  • ビジネスロジックを埋め込んだ時にバグりにくくする(値オブジェクト・Entityの区分けや集約)
  • なんかその他全体的に関心ごとを分離する。

最後のその他の部分が、DDD原典の頃の技術スタックではレイヤードやMVC的な構成、比較的最近のMVVMなりなんなりを考慮に入れるとCleanArchitecutreに近づいていくんだと思います。

個人的には、これを全部きれいにやりきるのは相当しんどいと思っており、やるやらで言えば、


  • ドメイン層の分離はほぼマストでやる。(ここがバグると重大な問題になるため)
  • リポジトリパターンはビジネスの整合性のためならいいかも。(DBとかの抽象化は気にしすぎない)
  • 値オブジェクト/Entity/Serviceの概念は、Mutable/Immutable的な話なので取り入れて損はないけど、他の方針で交通整理できるなら問題ないと思う
  • その他の関心ごとはフレームワークに合わせて気合で分離するしかない、、、

という感じだと思っています。
リポジトリパターンの整合性と書いたのは、DDDの集約の出し入れをするイメージです。集約?贅沢な名だね。今日からお前は、業務に必要な一通りの情報だよ!

リポジトリパターンの中で、DBやORMの抽象化をするパターンもあると思います(CleanArchitectureとかまさにそんな感じを目指していると思っています)が、ぶっちゃけプロダクションのDB変更なんて作り直しと大差ないくらい大変なので、最初からこれらを抽象化する必要が明確にあるプロダクトはそんなに多くなく、強く意識する必要はないんじゃないかな、、、と思っています。

最後のその他の関心ごとの分離というのが曲者で、これが結局DDD役立たなくね?となる部分だと思っており、例えば


  • FluxでもMVVMでも何でもいいんですが、最近はUI/UXのため、どうしてもクライアント側にビジネスロジック(例えば入力値のバリデーションとか)を持たせる必要があり、じゃあこれってクライアントサイドにどこまで持たせるの?(クライアントにControllerだけ置くの?それともクライアントのModelとかでちょっと処理させるの?)という苦しみ(そして結局クライアントサイドが膨らんで死ぬ)
  • k8sならIstioとかで流量制御とかできるけど、そうじゃない場合どこでやんの?"流量"に例えば有効注文数みたいな業務の観点があったらこれってビジネスモデル?それともセッション情報とかでカウントできるからインフラ?という苦しみ。

等々等々、結局フレームワークの中でできるだけドメイン層を分離しようとすると相応に苦しむことになります。し、現実問題実装とドメインモデルの間のギャップがすごいことになることも多いと思います。

結局、SOLIDを常に意識しよう!とあんまり変わらなくなることもありそう。ちゃんちゃん。

Discussion