表題の一解釈について発表させていただきます。
先日、Wikiでドメイン駆動設計(DDD)の記事を目にしました。
https://ja.wikipedia.org/wiki/%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88
その冒頭に、次の要約が載っていました。
ドメイン駆動設計(英: domain-driven design, DDD)とはソフトウェアの設計手法であり、「複雑なドメインの設計は、モデルベースで行うべき」であり、また「大半のソフトウェアプロジェクトでは、システムを実装するための特定の技術ではなく、ドメインそのものとドメインのロジックに焦点を置くべき」であるとする。
とりあえず、"モデルベースで行うべき"という点には賛成です。実際、ビジネスサイドの人と話をする時は、四角と線でできた簡単な図を、ホワイトボードに書いたりして打ち合わせします。
・・・この時点でもう、私達はすでにDDDを実践しているような気がします。
さて、焦点を置くべきところは"システムを実装するための特定の技術"ではないとのことなので、表題に含まれる"Spring"などの特定の技術に拘泥していてはいけないようです。耳が痛いです。
そうではなく、焦点を置くべきところは"ドメインそのものとドメインのロジック"とのことです。それをモデル化したものに"ドメインモデル"があり、それは以下の"ドメインモデルを表現する要素"によって表現できるようです。
エンティティ (参照オブジェクト): ドメインモデル内のオブジェクトであり、その属性によってではなく、連続性と識別性によって定義される。
値オブジェクト: 事物の特性を記述するオブジェクトである。特に識別する情報はなく、通例、読み出し専用のオブジェクトであり、Flyweight パターンを用いて共有できる。
サービス: 操作がオブジェクトに属さない場合に、問題の自然な解決策として、操作をサービスとして実現することができる。サービスの概念は、GRASPにおいて"純粋人工物"と呼ばれるものである。
リポジトリ:ドメインオブジェクトを取得するメソッドは、記憶域の実装を簡単に切り替えられるようにするため、専門のリポジトリオブジェクトに処理を委譲するべきである。
ファクトリー : ドメインオブジェクトを生成するメソッドは、実装を簡単に切り替えられるようにするため、専門のファクトリーオブジェクトに処理を委譲するべきである。
これらを見て、「これ全部、Springの用語で書き換えられるのでは?」と思ったことが、本稿起草の契機です。実際にやってみたものが下記になります。
-
エンティティ
テーブルに格納されたレコードの入れ物。テーブルのカラムと同じフィールドを持つ。Repositoryの引数であり、戻り値でもある。テーブルのIDがAuto Incrementしている場合、IDフィールドにユニークな値が入る。 -
値オブジェクト
Enum。大抵、コード値とかはEnumにされる。 -
サービス
Controller-Service-Repositoryの3層構造におけるServiceのこと。色々複雑なことをすることもあるようだけど、[ControllerのModel※] ⇔ [RepositoryのEntity] の詰め替え作業をしているだけのこともある。(※MVCにおけるModelのことっぽいけど、実際はただのデータの入れ物) -
リポジトリ
Controller-Service-Repositoryの3層構造におけるRepositoryのこと。要するに、DBに関わる処理をするところ。どんなORマッパーでも、内部ではSQLを実行している。あと、外部APIを読み出す箇所としても使われていたりする。 -
ファクトリー:
DI。Controller-Service-Repositoryの3層構造は、DIで構築されている。@Autowiredを使うスタイルも、いまや古くなってしまったかも。
こんな感じで、概ね書き換えることが出来てしまいました。
ドメイン駆動開発は、そのアンチテーゼがトランザクションスクリプト(if-elseによる長大なメソッド群)らしいです。
トランザクションスクリプトにならないよう、上述の「ドメインモデルを表現する要素」を意識してリファクタリングに勤しめば、ボトムアップ式とはいえ、ドメイン駆動開発をしていることになりそうです。
それなら、"特定の技術"ということにはなりますが、Springを使って開発していたら、「ドメインモデルを表現する要素」を意識することになるので、自然とドメイン駆動開発をしていることになると言えそうです。
とはいえ、ドメインモデル欠乏症という言葉があって、setterとgetter以外に、なんの振る舞いもしないDTOを良しとしているとダメなようです。
実際の開発では、"ドメインそのものとドメインのロジック" を "ドメインモデル" に書き出す、なんて面倒なことはせず、よくある設計パターンを再利用する感じで進めている気がします。Springなら、Controller-Service-Repositoryの3層構造を守っていれば、そんなに困ることはないように思います。
しかし、Wiki冒頭の要約にあった"複雑なドメインの設計"においては、既存の設計パターンを簡単には適用できないのだと思います。
そうしたケースでは、適切なドメインモデルを構築すべく、ビジネスと開発の人の双方が分かるユビキタス言語を発見・発明したり、何度もER図とクラス図を書き直したり、ホワイトボードを前に喧々諤々したりする必要があるのだと思います。
いつか、"複雑なドメインの設計"をすることになっても大丈夫なように、普段から、"ドメインそのものとドメインのロジック"を意識しておくことが大切なのだと思います。
決して、「普段はそんなに意識する必要ないのでは?」なんて不遜なことを思ったりしていないです。