30
1 CatalystCon#1 Catalyst かか Model かかかかか - MVC か M かかかかかか - Dann [email protected]

Separate Model from Catalyst

Embed Size (px)

DESCRIPTION

catalystcon1

Citation preview

1

CatalystCon#1

Catalyst から Model を切り離せ

- MVC の M のあるべき姿 -

[email protected]

2

CatalystCon#1

アジェンダ

WAF における MVC と WAF と M の関係

Catalyst(WAF) から M を切り離す方法

MVC の M を構築するためのアーキテクチャ

3

CatalystCon#1

WAF における MVC とWAF と M の関係

4

CatalystCon#1

WAF の役割

WAF は基本的に Web/Http の世界の仕事をするセッション管理認証処理URL ディスパッチャフォームバリデーション

Controller としての役割M と V のノリとしての役割モデルへ処理の委譲モデルの処理結果を View にフォワード

5

CatalystCon#1

WAF の役割でないこと

モデルの管理モデルのビジネスロジックモデルの Caching の機構Etc..

Catalyst で良くない点Catalyst::Model::*

M が Catalyst に依存しているModel をプラガブルに拡張するのは、 AF の役割

6

CatalystCon#1

WAFとModelの関係のあるべき姿は?

基本は、 Model は Web の世界からは切り離されていること

MVC の M は POPO(Plain Old Perl Object) で構成する

Why ?

7

CatalystCon#1

M を WAF から切り離すべき理由

Testability が向上するモデルの Unit Test が Catalyst を使わずに可能にテストの実行速度が早くなる

Web のコンテキスト以外での再利用が可能になる

POPOService

POPO Model(Schema::* など )

CLI(App::CLI, App::Cmd)

WebAPI(Catalyst::Controller::Resources)

Catalyst::Controller

M

8

CatalystCon#1

とはいっても、WAF では一部 M を知る必要がある。

どうするか?

9

CatalystCon#1

Catalyst(VC) と Model(M)の関係別の Model の切り離し

10

CatalystCon#1

M と VC の機能の共有関係

(a) M と VC 間に機能共有が必要でない場合

(b) M,V,C の全てで共有したい機能がある場合Ex) 国際化の機構( Controller 、 View 、 POPO Mo

del どこでも必要)

( c ) V, C の一部で M が必要な場合Ex) 認証の機構M のロジックはいらないが、データは必要

このパターン別に、モデルの切り離し方、 VC との繋ぎ方がある。

11

CatalystCon#1

(a) M でしか必要のない機能の場合 モデルの切り離し方

Catalyst の Model にせず、 POPO だけを使う

POPOService

POPO ModelCatalyst

Controller

CatalystView

M

V

C

12

CatalystCon#1

(b) WAF と APP( モデル ) で機能を共有したい場合

例えば国際化 V でも C でも国際化したい e.g (c.loc) M でも国際化したい eg. loc(‘message’)

モデルの切り離し方 アプリケーション (POPO Model) 側で共通の機能 ( 国際化)

を実装し、プラグインでアプリケーションの機能を参照する

Plugin::I18N --> MyApp::I18N

国際化方法 POPO Model(MyApp::Model::Hoge) からは MyApp::I18N で国際

化 . E.g) loc View では、 Plugin::I18N で国際化 . E.g) c.loc

13

CatalystCon#1

POPO ModelCatalyst

Controller

CatalystView

MyApp::I18NCatalyst

Plugin::I18Nx

(b) のパターン

CM

V

14

CatalystCon#1

(c) WAF の一部でモデルが必要な場合

例えば、認証の機構プラグイン側では認証の仕組みが必要で一部モデ

ルが必要。モデル側では認証の仕組みは不要というケース。

ユーザークラスは Catalyst のモデルじゃないと Catalyst の Plugin から参照が…

モデルの切り離し方Catalyst(WAF) の世界にモデルを閉じ込めるのが

いいCatalyst::Model::Adaptor が最適

15

CatalystCon#1

POPO User

Catalyst::Model::Adaptor

(c) のパターン

Catalyst::Plugin::Authentication::Store::DBIC

M

16

CatalystCon#1

MVC の M を構築するアーキテクチャ

17

CatalystCon#1

Domain Logic Patterns

Domain Model(+Service Layer)Service(workflow logic)Domain Model(domain logic)Logic とデータは同じところにask ではなく、 tell.

Transaction ScriptUnit of Work が 1 メソッドLogic とデータの分離Ask のモデル

Table Module※ 詳しくは PofEAA 参照

18

CatalystCon#1

Service Layer + Domain Model 「モデル」を Service と Domain Model に分ける Service Layer

Application logic(Workflow logic)Domain Model に対して問題を解決するよう処理を委譲

Publish するインターフェースの明示Controller に見せる処理の明示

トランザクション境界 Domain Model

Domain logic問題領域のロジックは Domain Model にここに主にロジックを記述

19

CatalystCon#1

多くの Web アプリケーションにおける一つの仮定

複雑なビジネスロジックは少ない CRUD の処理をすることのほうが多い CLI が管理用スクリプトとして必要になるケースは多い

重い処理を Job Queue に委譲することは割にある

20

CatalystCon#1

仮定に基づいた Domain model と Service Layer への疑問

DB の構造を見せないリッチな OO なドメインモデルが必要?多くの場合不要。無駄に Domain Model をラップすること

になるDB だけの場合、 Domain Model=ER モデル で十分

ドメインモデルでは、 DB に依存しない抽象化が必要 ?DB しか使わなければ、抽象化不要

常に Controller は Service Layer を介する必要あり?そんなことはない。直接 Domain Model を触ってもよい。1つのドメインモデルのロジックしか必要ないこともある

21

CatalystCon#1

Service Layer + Domain Model の現実解 Service

アプリケーションロジック ( ワークフローロジック)を書く複数のモデルにまたがるロジック複数のモデルへ処理をディスパッチする薄いロジック

サービスは基本的に 1 ユースケースに対応させる Domain Model

ドメインロジックを記述する DB のみの場合

一つのテーブル (Schema::X) に依存したビジネスロジックDomain Model= ER モデル とする

Controller は、 Service or Model にアクセス Controller にはロジックは記述しない ユースケースが CRUD のみのオペレーションに対応する場合、

Domain Model のロジックに直接アクセスしてもよい

22

CatalystCon#1

Catalyst にマッピングすると

POPOService

POPO Models(With DBIC)

CatalystController

CatalystView

POPO Models(With DBIC)

M

これが一番シンプルなマッピングモデルに対する要求は他にもあり、他のマッピング方法もある

23

CatalystCon#1

モデル( Service+Domain Model)を構築するための色々な要求

POPO モデル毎に簡単な設定情報を渡したい POPO モデルを簡単に WAF から参照したい

$c->model() でのアクセスはなんだかんだで便利(インスタンス生成のロジックが隠蔽されてるから)

モデルと WAF を簡単に繋ぎたい POPO モデル間の密な依存関係を断ち切りた

いTestability 向上のため

DI コンテナ を使ってモデルを切り離す

24

CatalystCon#1

POPOService

POPO Model(Schema::* など参照 )

CatalystController

CatalystView

DIコンテナCatalystPlugin

DI コンテナ + POPO Modelのアーキテクチャ

DI コンテナで POPO を Wiring

Plugin or Controller で DI コンテナを参照し、 WAF と M を繋ぐ

25

CatalystCon#1

DI コンテナを利用したモデル構築

DI コンテナ利用の利点モデルは DI コンテナで Wiring されるため、モデルが Cata

lyst の context に依存することが無くなるモデル間の実装の依存関係が切れる

モデル (Service, Model) の参照方法の一例Controller から直に DI コンテナを参照する

$self->model(“Service::Blog”)->create();プラグイン化して Context から DI コンテナを参照する

$c->pmodel(“Service::Blog”)->hello(); Catalyst::Model::Adaptor じゃできない?

Catalyst::Model::Adaptor では、 POPO Model と Adaptor が1:1 対応してしまう

26

CatalystCon#1

まとめ Catalyst は WAF としては必要十分 モデル (Service, Domain Model) について

モデルは WAF から切り離すべきビジネスロジックはモデルに押し込むMVC を考えるときは、モデルの Testability を中心

に考える モデルのアーキテクチャについて

Web アプリケーションの多くは、 ServiceLayer + Domain Model の変形でよいのでは

Catalyst に不足しているものWAF と POPO Model を繋ぐ仕組み

DI コンテナはそれに対する一つの答え MVC の M の拡張などは WAF ではなく、 AF で

27

CatalystCon#1

ご清聴ありがとうございました !

28

CatalystCon#1

付録

29

CatalystCon#1

Service Layer+Domain Model の構築に必要な仕組み(Application Framework としての仕組み)

モデルを Wiring・設定情報を Inject する仕組みDI コンテナ (Bread::Board. あと一歩 )

モデルの横断的な関心ごとを切り離す仕組みCaching, Transaction などMoose or Class::Trigger or Attribute で拡張

モデルをプラガブルに拡張する仕組みClass::Component

30

CatalystCon#1

モデルを Catalyst から切り離すのに実装が必要なものConfigLoaderLoggerCachingExceptionI18N の仕組み