spring
初心者
mvc
DDD

MVC の Model 肥大化への対処

More than 1 year has passed since last update.

MVC とは何かを 1 から学ぶ で投稿した内容の続きとして、MVC の問題点についてどう対処するか、についてまとめていきます。

MVCの問題点 (再掲)

  • 業務で扱うデータ要件が複雑になればなるほど、Model が肥大化していく (今回のテーマ)
  • 入力に応じた出力要件が複雑になればなるほど、Controller と View の依存性が高くなる

Model の肥大化とは…

例えば、Issue 管理のための Web アプリケーションを作成するとします。
Web の画面から、ユーザが Issue を閲覧・登録・更新・削除出来るようにする場合、以下の実装を担当するのはどこでしょうか。

  • DB に格納された Issue から、未完了のものを取得する
  • ユーザが更新 / 削除するために選択した Issue の詳細情報を取得する
  • ユーザが更新 / 削除するために選択した Issue が完了済でないかチェックする
  • 画面から更新された Issue を DB に反映する

…答えはすべて Model です。

Controller はこの Model の状態を View に渡し、View は Model の状態を参照して画面に返すだけなので、上記のようなビジネスロジックを実行し、データ ( ここでは Issue ) を操作するのは全て Model となります。

このように業務機能や、扱うデータ要件が複雑になるほど、Model が担う役割が多くなる = 肥大化することは容易に想像がつきます。

Model 肥大化 への対処

レイヤアーキテクチャの導入

そこで、 MVC のアーキテクチャパターンに、アプリケーションのレイヤ構成を当てはめ、肥大化する Model を分割します。
MVC の設計上、Model が担う役割自体を減らすことは出来ないので Model の中の役割分担を明確にし、煩雑に肥大化していくことを防ぎます。

レイヤ化

レイヤ化にも色々な種類が存在しますが、例として 実践ドメイン駆動設計 で述べられている 以下の 4 層をもとに整理していきます。

  • UI 層 (プレゼンテーション層)
  • アプリケーション層
  • ドメイン層
  • インフラストラクチャ層

UI 層 (プレゼンテーション層)

  • ユーザのリクエストを受付け、レスポンスを画面に表示する層。

アプリケーション層

  • アプリケーションをコーディネートする層。プレゼンテーション層から受取ったリクエストをハンドリングし、ドメイン層を使ってアプリケーションを実行する。

ドメイン層

  • Domain Object を持ち、Domain Object に対するアプリケーションのビジネスロジックを実行する。

インフラストラクチャ層

  • ドメイン層の実装を持つ層。Domain Object に対する CRUD 操作の実装を提供する層。DB に接続し、データの CRUD 操作を行うことで DB を永続化する。

MVC との対応関係

  • UI 層 : View
  • アプリケーション層 : Controller
  • ドメイン層 : Model

( インフラストラクチャ層 : Model が 保持する Domain Object に対する CRUD 操作の実装 )

ドメイン層とインフラストラクチャ層の分割

ここで更に、肥大化する Model ( = ドメイン層 ) を更に以下の役割に分割します。

ドメイン層

  • Domain Object
    ビジネスロジックを実行する上で必要な資源。Entity。POJO。

  • Repository
    Domain Object の CRUD 処理を行うインターフェース。
    Repository は DB アクセスの実装は持たず、ルールの定義のみ。

  • Service
    アプリケーションのビジネスロジック。

インフラストラクチャ層

  • RepositoryImpl
    ドメイン層で定めた Repository の実装をもつ。
    O/R Mapper を使用してDB に接続し、Domain Object の CRUD 処理を行う。

  • O/R Mapper
    DB と Entity のマッピングを行う。

各レイヤ間の関係は以下の図の通りです。

図1.png

上記の図で押さえるポイントとしては 2 つです。
1. ドメイン層 (Model) は アプリケーション層から使用・参照される
2. ドメイン層 (Model) は インフラストラクチャ層のインタフェースを定義

つまり、ドメイン層はどこの層にも依存していないことになります。インフラストラクチャ層の実装が変わったとしても、ドメイン層ではインタフェースを定義しているのみのため影響を受けません。

こうしてアプリケーションをレイヤ化し、分割することで Model が疎となり、煩雑な肥大化を防ぐことが出来ます。


例えば Java の Spring Framework を使用すれば @Service@Repository アノテーションを付けるだけでフレームワークが上手く処理してくれるのですが、書く側が理解して設計できないと、プログラムが少し複雑になっただけで応用が効かなくなりそう ( 効かなくなって自分の首を締めた経験あり ) ということで整理してみました。

参考

DDDを踏み外してからもう一度踏み出してみた - hatajoeのブログ
実践DDD本の第4章「アーキテクチャ」 ~レイヤからヘキサゴナルへ~ (1/4):CodeZine(コードジン)
2.4. アプリケーションのレイヤ化 — TERASOLUNA Server Framework for Java (5.x) Development Guideline 5.3.0.RELEASE documentation