自分が現在所属してる開発現場では、従来より__ドメイン駆動設計__を採用しています。そこで自分自身の技術的なキャッチアップを兼ねて、アウトプットの意味でもqiitaにドメイン駆動開発について綴ってみようと思います。あくまで自分自身の実践を通して得られた知見ではなく、本やブログなどで得られた断片的知識を自分なりに繋ぎ合わせたものなので、もし間違ってたらすいません(参考文献は下記にあります)
#ドメインとは
ソフトウェアとは何らかの課題を解決するためのものです。そのためソフトウェアを開発する際には、その課題が存在する__対象領域(=ドメイン)__に対する理解が不可欠になります。例えば、会計ソフトなら経理、音楽編集ソフトならコード理論や楽器、路線探索アプリなら全国の鉄道網、こうしたことに対する理解は__ドメインエキスパート__と呼ばれる領域のプロフェッショナルなどを中心に、チーム全体で対象領域への解像度と理解度を上げていく必要があります。
ドメイン駆動開発を行うためには、まず現実領域にあるそうしたドメインを抽象化、概念化することで、コードで扱えるオブジェクトに落とし込む必要があります。しかしながら、ソフトウェアが解決する目的によって必要な知識は取捨選択される必要があります。例えば、会計ソフトにおいてはお金に関する理解は当然必須ですが、他方で円の起源が江戸時代にあるとか、1円玉を作るのに本当は3円かかってるというような知識は必要ありません。他にもペンはペンでも小説家にとってのペンと文房具店にとってのペンでは、書くものと売るものと言ったような形で機能的な側面は大きく違います。
こうした現実の諸問題から、不必要なことを削ぎ落として概念化していく過程を__モデリング__といい、結果として得られたモデルは__ドメインモデル__と呼ばれます。つまり文房具屋にとってのペンモデルと小説家にとってのペンモデルは目的としている機能が異なるためモデルとしては全く別個のものになります。そしてさらに、このドメインモデルをコードが扱えるようなオブジェクトに落とし込まれたものが、__ドメインオブジェクト__となります。(evansの言葉を借りるとドメインモデルとは問題解決のために、物事の特定の側面を抽象化したものと言える)
またこのモデリングの過程で、ソースコードが業務の内容をある程度反映できるように、用語の統一化をはかります。例えば入金を意味する単語にはdeposit, payment, coin_inなど様々な言葉がありますが、あえてpaymentに統一化することで、開発チームだけではなく、ビジネスサイドも容易に理解できるような形に落とし込みます(=これをユキビタス言語という)。これによりビジネス要求に対するスピードも上がることが期待されます。
DDDと相性のいい言語について
ドメイン駆動設計では、こうしたオブジェクトを複数作り、それらが連関するような構造で機能します。そのため言語には型がある方が望ましいとされており、C#やJavaなどが積極的に用いられるようです。また静的型付言語でなくとも、漸進的型付を採用しているRubyやタイプヒントの概念があるPython、そのほか静的解析が提供されてる言語でも実現することは可能だそうです。
#モデルをより洗練されたものに
現実にある課題は可変的なもので頻繁に変化するものです。そのためドメインオブジェクトもそれに応じて頻繁な変化を余儀なくされます。ソフトウェアが解決しようとしている課題によっては、開発においても最も大変なのは技術的なことよりも、むしろユーザーの活動やビジネス的なものであることが多かったりもします。そうした変更に対してはドメインモデルは素直に忠実に即時的に受け止めることで、そうした柔軟なソフトウェアの課題解決を実現します。つまりモデルは初めから完璧を目指す必要はなく、継続的に改善し続けていくことで、より洗練されたものを目指すのです。そしてこの継続的なリファクタリングの中でも、頻繁に変更されるモデルは、ビジネス要求の高いものとみなされ、事業価値の高い__コアドメイン__として対象化されます。
しかしながら同時に、モデルをより洗練としたものにするためには、ソフトウェアのプログラムは拡張性に耐えうるものでなければなりません。ここでチームにおいて共有された何らかの開発指針(きめ)がないと、プログラムは不要に肥大化し、保守性、可読性が困難なものにならざるを得ません。またwebフレームワークはあくまでその名の通りフレームワークを提供するのに止まり、ビジネスロジックに対しては何ら指針を持たないため、この点における有効な解決策を提供しません。こうしたプログラムが宿命的に抱える複雑さに対抗し、現実環境で刻々と変化する課題に柔軟に対応するための開発手法がドメイン駆動設計になわけです。
#アプリケーションの構築
ここまでは、あくまで現実のドメインをドメインオブジェクトに落とし込んだだけで、これだけではソフトウェアによる課題解決は実現できません。ドメイン層のオブジェクトに対して何らかの処理を施すことによって、実際にアプリケーションを構築していきます。
###ドメイン設計開発に用いられることの多いオニオンアーキテクチャ
ドメイン駆動設計を実際に進める上で大切なのは、「関心の分離」 つまりドメイン層を他から隔離するということです。従来のアーキテクチャでは、UIやURLルーティングを担当するプレゼンテーション層、そして処理の流れを記述するビジネスロジック層、そして最下位にリレーショナルデータベースやモデルを定義するインフラ層があり、上から下へと依存しているような状況でした。しかしながらこれでは、プログラムが拡張するにつれて、ビジネスロジック層が肥大化し、クラス同士の密結合による副作用、テストの困難さなどを招いてしまいます。またビジネスロジック層が、インフラ層に依存しているような形であったため、ドメイン開発において必要なモデルの継続的な改善やDBなどインフラ面での変更は、ソフトウェアにとって大きな負担を強いることになりました。
ドメイン駆動設計では、ドメイン層をどこにも依存させないような形をとります。つまり本来であれば依存するはずのインフラ層(レポジトリ)に対して、あえてドメインがレポジトリのインターフェースを切り、インフラ層がそこに依存するというような形を取ることで、依存関係を逆転させます。これによってドメイン層はどこにも依存することなく、ひたすらに集中的にドメインにだけ関心を払えば良くなり、インフラ技術の変更などの影響を被らなくなります。通常モデルはデータベースに近いため、変更にはコストとリスクが伴いますが、この依存関係の逆転によって、モデルを安全に継続的に洗練させていくことが可能になります。
#MVCフレームワークとの違い
従来のMVCフレームワークはあくまで大きな枠組みを提供してくれるのみで、ビジネスロジックにおける細かい指針は提供しません。他方でドメイン駆動設計においては、ドメインロジックに対して明確な指針を持ちます。それは実装したロジックをできるだけ小さく分割し、メソッドあたりの責務を小さくすることです。これにより、処理が単体処理の組み合わせによって実現されるため、仕様変更の影響が限定的になり、単体テストも行いやすくなります。またドメイン層はどこにも依存してないため、ドメイン層に対してのみ関心を払えばいいので、可読性、保守性を高く保った状態でプログラムを拡張することができるのです。
#まとめ
最後にドメイン駆動設計による__メリット__をまとめると
- プログラムの拡張に伴う可読性、保守性の低下に対抗できる。
- フレームワークが対象としていないような領域においても指針を提供するため、設計方針の統一が取れやすい。
- ユキビタス言語という共通言語を用いるため、開発チームだけでなくビジネスサイドにも了解が取れやすい。
- レイヤー分割、単体処理の組み合わせで処理を実現するので、仕様変更の影響が小さくて済む
- ソフトウェアが課題解決の対象とする現実問題の課題の柔軟な変化に対応しやすい。
- 本来であればビジネスロジックが依存しがちなインフラ面とビジネスロジックを分割できる。
最後まで読んでいただきありがとうございました。
##参考文献
- Goでレイヤードアーキテクチャ
- [DDD]ドメイン駆動設計で実装を始めるのに一番とっつきやすいアーキテクチャは何か
- 俺たちのドメイン駆動設計はこれからだ!
- [ドメイン駆動設計でなぜ作るか、どう作るか] (https://medium.com/aerial-partners-engeneering/%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88%E3%81%A7%E3%81%AA%E3%81%9C%E4%BD%9C%E3%82%8B%E3%81%8B-%E3%81%A9%E3%81%86%E4%BD%9C%E3%82%8B%E3%81%8B-518c22bcc486)
- ドメイン駆動設計で保守性をあげたリニューアル事例 〜 ショッピングクーポンの設計紹介