2021年5月10日月曜日

今更ながら DDD について考えてみた

今更ながら DDD について考えてみた

2003 年ごろに提唱された DDD がなぜか今盛り上がっている気がするので今更ながら DDD (Domain Driven Development) について考えてみました
なお原著であるエリック・エヴァンスのドメイン駆動設計は読んでいません
完全に個人的な主観で記載しているので解釈の間違い等はご容赦ください
また DDD のすべてに触れているわけではないのでそれもご容赦ください
文字が多いです

あくまでも「設計手法」であることを忘れてはいけない

いざ実装となるとそのプロダクトの性質や方向性が実装に大きく影響します
それに対して絶対 DDD を適用することは難しいと思っています

設計手法=数ある解決手段の中の一つにしかすぎないと思っています
何でもかんでも DDD を使うのは良くないと思うのでプロダクトのこの部分は適用できそうだとかここは難しいという判断が重要だと思います

DDD は完璧な銀の弾丸ではないかなと思います
もちろんトライすることは良いことだと思います

オブジェクト指向の拡張

に近いかなと個人的には思っています
オブジェクト指向のクラス=ドメインモデルになるケースは結構あるかなと思っています

ただ大きく違うのは粒度と性質かなと思っておりドメインモデルは「値オブジェクト」や「エンティティ」という表現を使っておりオブジェクト指向で言うところのフィールドが Immutable であるかどうかなどを決める必要があります
また振る舞いは「ドメインサービス」として別クラスに書いたりします

オブジェクト指向でもそのようなことはできますが基本的にはフィールドの Settter さえあれば値は変更できます
振る舞いに関しても同じクラスに書くことが多いと思います

また自分がオブジェクトの拡張だと思う理由のもう一つとしては DDD のサンプルをいろいろ調べると大抵のケースでクラスを使っています
当然クラスを使わないで DDD するのは不可能ですがクラスが使える言語は大抵オブジェクト指向な言語で書くことが可能な言語であることが多いのでそう感じているのかもしれないです

オブジェクト指向をしっかり使えていれば実は勝手に DDD っぽく書けているケースがあるかも?

ドメインモデルをどこまで抽出するか

例えば以下のようなコードがあるとします
何らおかしなところはないユーザを管理するクラスです

class User
  def initialize(name, age)
    @name = name
    @age = age
  end

  attr_accessor :name, :age
end

ですが DDD 的には以下のように値オブジェクトとして name と age をドメインモデルとして抽出します

class UserName
  def initialize(value)
    @value = value
  end

  attr_reader :value
end

class UserAge
  def initialize(value)
    @value = value
  end

  attr_reader :value
end

class User
  def initialize(name, age)
    @name = name
    @age = age
  end

  attr_accessor :name, :age
end

UserName や UserAge クラスを新たにドメインモデルとして抽出しています
DDD 的にはこうすることでユーザ名や年齢のバリデーションを各クラスに持たせることがよしとされています (値オブジェクト)

かなり極端な例ですが個人的にはオーバーエンジニアリングな感じがあります
このようにどこまでをドメインモデル (クラス) として抽出するかの判断が非常に難しいと思っています

一応判断基準はあるのですが正直「経験」というか「感覚」が物を言う世界かなと思っています
やりすぎも良くないと思うのでいい塩梅のモデリングレベルが要求されるのでそれだけでもかなりの学習コストがあるのかなと感じます

フレームワークの流儀に従うかどうか

Web アプリなどを開発する場合は基本的には Web フレームワークを使うかなと思います
自分であればよく Sinatra という Ruby 製の軽量フレームワークを使います
また Ruby には有名な Rails というフレームワークもあります

基本的にはどちらも MVC を使って開発することがほぼんどです
そういったフレームワークが提供する機能というか書き方がある程度整っている状態で DDD を採用しようとすると MVC に対して無理やり DDD を適用するようなことが発生します

もちろん適用することは可能です
ルーティングの部分はそのままでモデルの部分だけを DDD っぽく書くなんてことはできるかなと思います
ただ Rails を使う場合には active_record と Model の関係がかなり密接に絡んでおり無理に Model を書き換えて DDD を適用しようとすると大変なことになりそうな気がしています (やったことはないのであくまでも予想です)

フレームワークにはそれなりの流儀というか書き方のルールがあるかなと思っています
個人的にはまずはそれを優先するべきかなと考えています
その上で一部のロジックを DDD にするというのはありなのかなーという気はしていますが、いろいろと設計思想が混同したコードはあまり良い方向にいかないような気もしています

DDD の知識がないとコードの可読性は落ちるかも

単純なことですが DDD にはある程度書き方やルールが決まっているのでそれを知らないでコードを読んでも逆に読みづらいのかなという気がしています

値オブジェクトやエンティティに関しては「なんでこんなに細かく抽象化しているのだろうか」とか感じたりするかもしれません
ドメインサービスに関しては「なんでこれはわざわざ別クラスとして切り出しているのだろう」と感じたりするかもしれません

しかもそのルールを知らないと実際にメンテナンスするときに振る舞いをドメインモデル側に記載したりしてしまうかもしれません

もちろんレビューしたり学習したり回避方法はいくらでもありますが完全に初見でコードをみたときに「あ、これは DDD だな」と気づく人は少ないんじゃないかなと思います

DDD で高メンテナンス性は担保できるのか

ドメインモデルを適切に抽出できていればモデルのクラスを見ただけで確かにコードを理解できるかもしれません

しかしそれだけではそのコードをメンテナンスすることはできません
あくまでもコードを修正してテストしてバグを修正できて初めてメンテナンスできるようになると思います

修正箇所を小さく局所的にすること=高メンテンス性なコードであるとは思います
しかしあくまでも修正できるかどうかはある程度の経験が必要だと思います
ここで言う経験は「コードのビルド」すなわちトライアンドエラーすることであると考えておりそれは CI/CD などで担保するものかなと思っています

要するに DDD だけでメンテナンスしやすいコードにするのは難しいのでちゃんと初心者がトライアンドエラーしやすい環境を作っておくことも重要だと言うことです

言語との相性

冒頭でも記載していますが個人的にはオブジェクト指向の拡張かなと思っています
なのでオブジェクト指向ができる言語とは相性が良いと思っています

もう少しいうとゴリゴリの型付け言語のほうが相性が良いかなと思っています (DDD の紹介書籍などを見るとそう感じると思います、たぶん)

具体的には C# や Java などが相性が良いかなと思っています
もちろん Ruby や Python、Swift などの高級言語でも可能だとは思います
ただ Python などはオブジェクト指向から外れたスクリプトみたいな書き方も簡単に含められるので、そういう便利機能というか DDD っぽくない書き方が含まれていると可読性などは落ちるのかなという気もしています

JavaScript とかでもやっているのをちらほら見ますが、まぁどうなんでしょうか、、?
(nodejs ならできるのかな?できないということはないと思うが)

ドメインモデルのスコープをどうするか

基本的にはクライアントから操作できるのはアプリケーションサービスのみです
しかし言語の仕様や実装上の namespace の問題でドメインモデルにアクセスできることはできてしまいます

代替手段はいろいろとありますが本来は機能として触れないようにするべきです (例えば外部に公開しないドメインモデルには private 修飾子を設定するなど)
しかしどうしてもできないこともあるはずです
そういった場合に「ルール」を作るのですがあくまでもルールでありやろうと思えばドメインモデルを直接使うことができてしまいます

個人的にはこのスコープを問題は大したことではないと思うのですが考える必要がある点に注意が必要です
なるべく Getter を作らないという考えも同じようなことだと思います

インターフェース

主にアプリケーションサービスとリポジトリでインターフェースなどで使うことになると思うのですがインターフェースが言語の機能としてない場合があるのでその場合にどうするか考える必要があるかなと思います

ガッツリ設計するような開発手法にはあっているかも

例えばウォーターフローモデルのような開発には向いているかもしれません
DDD は設計の段階でかなり時間を割くイメージがあり、かっちり決めてから開発することになると思うのでアジャイルやプロトタイピングのように書きながらとなると、それなりの DDD の経験と知識がないと難しいかもしれません

その他要素 (集約、委譲 (DI)、トランザクション、アーキテクチャなど) について

結局考える必要が出てくるので学習しておく必要があります
学習しておかなくても最悪良いのですが知っていたほうがいろいろと便利だし DDD の原則に従うことができます

特にアーキテクチャそれだけかなりの学習コストがあるので大変です

最後に

用法用量を守って正しくお使いください
あとは書籍や Web の紹介を読んだだけだと理解できないので実際に自分で手を動かしてコーティングしてみることをオススメします

用語集

  • ドメインモデル
  • ドメインオブジェクト
    • 値オブジェクト
    • エンティティ
  • ドメインサービス
    • 評価 (Specification)
  • リポジトリ (インタフェース)
    • クエリサービス
  • アプリケーションサービス (インタフェース)
  • 集約 (ルール)
  • アーキテクチャ
    • レイヤード
    • ヘキサゴナル
    • クリーン

0 件のコメント:

コメントを投稿