Edited at

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