MVC の Model 肥大化への対処

[MVC とは何かを 1 から学ぶ ](http://qiita.com/tentom/items/de95f63bc9e2da2bd0bf)で投稿した内容の続きとして、MVC の問題点についてどう対処するか、についてまとめていきます。


# <i class="fa fa-file-text-o" aria-hidden="true"></i>MVCの問題点 (再掲)
* 業務で扱うデータ要件が複雑になればなるほど、Model が肥大化していく (今回のテーマ)
* <font color="Silver">入力に応じた出力要件が複雑になればなるほど、Controller と View の依存性が高くなる</font>

## Model の肥大化とは…

例えば、Issue 管理のための Web アプリケーションを作成するとします。
Web の画面から、ユーザが Issue を閲覧・登録・更新・削除出来るようにする場合、以下の実装を担当するのはどこでしょうか。
  > * DB に格納された Issue から、未完了のものを取得する
  > * ユーザが更新 / 削除するために選択した Issue の詳細情報を取得する
  > * ユーザが更新 / 削除するために選択した Issue が完了済でないかチェックする
  > * 画面から更新された Issue を DB に反映する


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

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


# <i class="fa fa-file-text-o" aria-hidden="true"></i>Model 肥大化 への対処
## レイヤアーキテクチャの導入
そこで、 MVC のアーキテクチャパターンに、アプリケーションのレイヤ構成を当てはめ、肥大化する Model を分割します。
MVC の設計上、Model が担う役割自体を減らすことは出来ないので Model の中の役割分担を明確にし、煩雑に肥大化していくことを防ぎます。

## レイヤ化
レイヤ化にも色々な種類が存在しますが、例として [実践ドメイン駆動設計 ](https://www.amazon.co.jp/%E5%AE%9F%E8%B7%B5%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88-Object-Oriented-SELECTION-%E3%83%B4%E3%82%A1%E3%83%BC%E3%83%B3%E3%83%BB%E3%83%B4%E3%82%A1%E3%83%BC%E3%83%8E%E3%83%B3/dp/479813161X/ref=pd_lpo_sbs_14_t_1?_encoding=UTF8&psc=1&refRID=7TDTB9MGTYVEENQK8477)で述べられている 以下の 4 層をもとに整理していきます。

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



### UI 層 (プレゼンテーション層)
  * ユーザのリクエストを受付け、レスポンスを画面に表示する層。


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


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


### インフラストラクチャ層
  * ドメイン層の実装を持つ層。Domain Object に対する CRUD 操作の実装を提供する層。DB に接続し、データの CRUD 操作を行うことで DB を永続化する。


## MVC との対応関係
* UI 層 : View
* アプリケーション層 : Controller
* ドメイン層 : Model

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



# <i class="fa fa-file-text-o" aria-hidden="true"></i>ドメイン層とインフラストラクチャ層の分割
ここで更に、肥大化する 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](https://qiita-image-store.s3.amazonaws.com/0/147552/8eba4df1-5886-080d-9ee9-2393ca79f355.png)




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

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

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

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


### 参考
[DDDを踏み外してからもう一度踏み出してみた \- hatajoeのブログ](http://hatajoe.hatenablog.com/entry/2014/01/24/043427)
[実践DDD本の第4章「アーキテクチャ」 ～レイヤからヘキサゴナルへ～ \(1/4\)：CodeZine（コードジン）](https://codezine.jp/article/detail/9922)
[2\.4\. アプリケーションのレイヤ化 — TERASOLUNA Server Framework for Java \(5\.x\) Development Guideline 5\.3\.0\.RELEASE documentation](http://terasolunaorg.github.io/guideline/5.3.0.RELEASE/ja/Overview/ApplicationLayering.html#helper)