Posted at

24章 Magic Beans(魔法の豆)

More than 3 years have passed since last update.


目的

MVCのMを単純化する


  • モデルを単純化する為、モデルは単なるデータアクセスオブジェクトとしてしまう。

⇒ Modelの過度の単純化により、逆に複雑に。。。


アンチパターン

モデルがアクティブレコードそのもの


  • モデル = テーブル(ビュー)の1レコード

  • CRUD操作

  • DAO


MagicBeans/anti/model

$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が関わるアプリケーション開発の生産性・保守性を高めることができる。


最後に、

モデルはテーブルから分離させましょう。