オフショア開発をメインとする部署でエンジニアをしており、受託開発やラボ型開発を捌いていく中で小中規模のアプリケーション開発に携わることが比較的多いです。
そんな中、DDDを導入するには運用コストも開発者の教育コストも高いと感じる中でどういったクラス設計がコストとリターンで見て最適なのかまとめます。
開発経験を積む中で更新されていくと思いますが、まずは現時点での最適解を記載します。
前提
まずクラス設計を行う上で意識したいのはそのシステムがどれだけ使われるか、どれくらいの利益を産むシステムであるかという解像度を高めることです。
もし会社として主軸にしたいシステムであり、今後の利益も大きく見込めるのであればDDDを採用しドメインエキスパートと対話を重ねドメインを明確にし、それをもとにエンティティや値オブジェクト、ユースケースクラスなどを作成することが効果的であると思います。
というのもDDDは変更容易性を意識した設計であり、リファクタが並行で行われることを是としています。
ただし、実際にはプロジェクトで扱うシステムはそこまでの規模を想定していなかったりPoCのフェーズであることも多々あります。
ですのでそういったドメインの明確になっていないシステム、そしてドメインエキスパートも存在しないシステムで採用したいクラス設計やフォルダ分けを示します。
設計方針
結論からまとめると3層アーキテクチャを採用し、技術駆動パッケージを一部採用します。
まず3層アーキテクチャですが、こちらは小中規模アプリケーションであるという前提から複雑なクラス設計を行うよりもむしろシンプルにクラス設計を行う方が開発者の認知負荷が下がり、開発生産性が向上します。
シンプルにするということは保守性や変更容易性が下がってしまうことを懸念されるかもしれませんが、双方の懸念が現実のものとなった時にリファクタなりリプレイスメントを行う方が健全だと考えます。
そもそも従来の設計や言語が恒久的に使われ続けるという前提を疑う必要があるからです。
本当に利益を産み続けるシステムとなった時、システムの改修は社内で必須要件となるはずです。
ですので、まずは円滑に開発が行えることにフォーカスを当てるために3層アーキテクチャを採用します。
また、フォルダ分けですがこちらは3層アーキテクチャの説明の中で追々まとめます。
3層アーキテクチャ
3層アーキテクチャとはここではアプリケーション内部の3層アーキテクチャを指します。
それぞれの層は
- プレゼンテーション層
- ビジネスロジック層
- データアクセス層
で分けられます。
プレゼンテーション層
プレゼンテーション層が担う責務は以下の通りです。
- リクエストパラメーターの加工を行い必要な情報を取り出し、ビジネスロジックに情報を受け渡す
- ビジネスロジック層から取得したデータを整形し、レスポンスを返す
任意ですが、リクエストパラメーターのバリデーションが複雑になる場合は、バリデーション処理を担うクラスにリクエストを渡して、プレゼンテーション層と切り離すのもおすすめです。
クラスのSuffixはControllerを使います。
エンドポイントについてはURLが/email/updateである場合、EmailControllerを作成します。
その後/email/getや/email/deleteなどのURLを定義した場合にはEmailControllerに追記することで、ControllerとURLは一対多の関係にします。
これは同じドメインは同一Controllerにまとめることで凝集性の高さを担保するとともに、1URL1ControllerとなってはControllerクラスが増加してしまい、保守性が下がってしまうことを防ぐことを目的としています。
このため、フォルダ分けとしてはEmailフォルダを作成しその中に1Controllerとなることを想定しています。
ビジネスロジック層
ビジネスロジック層が担う責務は以下の通りです。
- アプリケーションの要件に依存するビジネスロジックを処理する
- DBや外部APIとの接続ロジックが必要な場合はデータアクセスクラスであるRepositoryクラスやAPIClientクラスから取得する
クラスのSuffixはServiceを使います。
ビジネスロジックは一般的に複雑でクラス内は肥大化しがちです。
そのためServiceクラスは1URLあたり1クラス作成します。
先ほどの例に則るならば/email/update、/email/get、/email/deleteに対し、それぞれにEmailUpdateService、EmailGetService、EmailDeleteServiceを作ります。
以上のようにServiceクラスは複数になることが一般的であるため、Emailフォルダ配下にServicesフォルダを作成し、その中に以上で作ったクラスファイルを配置します。
データアクセス層
データアクセス層が担う責務は以下の通りです。
- DBへデータを読み書きする
- 外部APIと接続する
クラスのSuffixはDBへの書き込みの場合Repository、外部APIと接続する場合はClientを使います。
このクラスはDBテーブル1つに対して1つ作ります。
また、異なるServiceクラスで利用されることを鑑み、フォルダは他のドメインの外にRepositoriesフォルダ、もしくはClientsフォルダを作成して配置します。
つまりEmailフォルダと同じ階層です。
データアクセス層のクラスはドメイン毎に作成すると、要件の変更があった場合にあるエンドポイントでは適切な振る舞いをするが、他のエンドポイントでは旧来の要件のままであるということが起きてしまう可能性があります。
以上の点を意識した結果他のドメインに属さない形で外に出しています。
まとめ
開発でドメインエキスパートがいない場合、ドメインをもとにクラスをどのように定義するか、フォルダ構成をどのように分ければ良いか決めかねることがあると思います。
そもそも利益を出せるようになってからリファクタすることを正とすることで、不要な工数をかけることなく円滑な開発が行えるかと思います。
私が実際に開発していく中ではURLが100種類、テーブルが50〜70くらいのシステムであれば十分に機能すると思います。



