目的
MVCのMを単純化する
- モデルを単純化する為、モデルは単なるデータアクセスオブジェクトとしてしまう。
⇒ Modelの過度の単純化により、逆に複雑に。。。
アンチパターン
モデルがアクティブレコードそのもの
- モデル = テーブル(ビュー)の1レコード
- CRUD操作
- DAO
$bug = new Bug();
$bug->summary = '保存時にクラッシュが発生';
$bug->save();
アクティブレコードは単一テーブルの各行に対するSimpleなInterfaceを提供してくれる優れたパターンです!
まるで魔法の豆のようだ・・・
しかし、魔法の豆はありません。
以下、魔法の豆アンチパターンがもたらす弊害の紹介。
####1.モデルをデータベーススキーマに強く依存させてしまう
ex) テーブルの数 = Modelの数が必要。
ex) データベーススキーマを変更する場合、Modelの変更だけではなく、そのModelを使うコードも変更する必要がある。
####2.CRUD機能を公開してしまう
ex) 意図した用法を無視してCRUD操作が行われてしまう。
Bugテーブルのassigned_toが登録されたら電子メールを送る。
というビジネスロジックを無視して、
assined_toを登録するロジックが書かれてしまう。(可能性が高くなる)
####3.ドメインモデル貧血症をもたらす
ex) CRUD以外の振る舞いがモデルの外部に書かれてしまい、振舞いの凝集度が低下する。
####4.ユニットテストが困難
ex) MVCの各レイヤのUTが難しい。負荷が高い。
モデル:
データベースアクセスから分離して行うことができない。
ビュー:
モデルが関連する動的なHTML要素のレンダリングと解析のために、フレームワークは複雑で時間のかかるコードを実行する必要がある。
コントローラ:
ビジネスロジックがコントローラに書かれていると、ビジネスロジックのテストの為にHTTPリクエストを用意したりと無駄な準備が必要になる。
また、同じビジネスロジックが分散しているとテストの重複も発生。
⇒ データベースアクセスからビジネスロジックを、プレゼンテーションからビジネスロジックをそれぞれ分離させること!
アンチパターンの見つけ方
-
テーブルをJOINした処理をどこに書こう?
→ テーブル = Modelになっている可能性あり。 -
同じビジネスロジックが複数個所にある。
→ データベースアクセス以外のビジネスロジックがModelの外に書かれている可能性あり。 -
UTが大変なんですよ。
→ このパターン含め、何かしらのアンチパターンの可能性あり。
アンチパターンを用いてもよい場合
- アクティブレコード自体はアンチパターンではない!
- 単純なCRUD操作を行うだけのアプリケーションや、スピード重視のプロトタイプ作成時など。
魔法の豆のメリットが得られる場合もある。
解決策
Modelがアクティブレコードを[持つ]ようにする。
####1.モデルを理解する
- アクティブレコードのようなDAOとModelの関係は、継承ではなく集約。
- DBのデータを扱うCRUD操作は外部に公開しない。
- コントローラやビューはドメインモデルのインタフェースを使用すべき。
- 疎結合性
- 高凝集性
####2.ドメインモデルの使用
- Modelはビジネスロジックを実装する場所。
- DBとのやりとりは、内部的な実装の詳細。カプセル化。
- クラス図描いてみよう。複雑化・密結合化してないか。
####3.プレーンなオブジェクトのテスト
- 理想は、DBに接続することなくモデルをテストできること。
- モデルとコントローラの切り離し。
- モデルとデータアクセス機能の分離。
####4.現実的に考える
- フレームワークによっては[魔法の豆]アンチパターンを招きやすいが、DAOは効果的に使用できる。
- この章のドメインモデリングの基本は、DBが関わるアプリケーション開発の生産性・保守性を高めることができる。
最後に、
モデルはテーブルから分離させましょう。