@shin1x1
2015/06/27 PHP Conference Fukuoka
レイヤードアーキテクチャを意識した
PHPアプリケーションの構築
レイヤードアーキテクチャ
レイヤードアーキテクチャ
(c) 2015 Masashi Shinbara @shin1x1
• アプリケーションをレイヤ(層)に分割
• レイヤ毎に役割を担う
• レイヤ間で協調して、処理を行う
OSI参照モデル
(c) 2015 Masashi Shinbara @shin1x1
7.Application
6. Presentation
5. Session
4.Transport
3. Network
2. Data link
1. Physical
MVC
(c) 2015 Masashi Shinbara @shin1x1
View
Controller
Model
MVCの悩み
CakePHP 1.x
(c) 2015 Masashi Shinbara @shin1x1
Fat Model
(c) 2015 Masashi Shinbara @shin1x1
• 1,000行を超える Model
• Model の役割が多すぎる
• DAO / バリデーション / ビジネスロジック等々
MVC
(c) 2015 Masashi Shinbara @shin1x1
View
Controller
Model
MVC + Service
(c) 2015 Masashi Shinbara @shin1x1
View
Controller
Model
Service
サービスレイヤを追加
(c) 2015 Masashi Shinbara @shin1x1
• Controller と Model の間のレイヤ
• ビジネスロジックとバリデーションを担う
• 1アクションメソッドに、1サービスクラス
• ビジネスロジックの共通化は、モデル or ビヘイビア
結果
(c) 2015 Masashi Shinbara @shin1x1
• Fat(Controller¦Model) を、ある程度解消
• レイヤは、まだグルーピングの単位
• レイヤ間の依存関係が整理されていない

=> サービスが、セッションを操作等
よりレイヤーを意識
Laravel
(c) 2015 Masashi Shinbara @shin1x1
• Laraval + AngularJS
• Laravel は、REST API の提供
• UI は、AngularJS
意識したところ
(c) 2015 Masashi Shinbara @shin1x1
•レイヤ役割を明確にする
•レイヤ間の依存を明確にする
• 上位レイヤが下位レイヤを呼ぶ(逆は無い)
• 下位レイヤはどこから呼ばれるか関知しない
•処理の流れを一方向にする
•サービスを中心に考える
レイヤー構造
(c) 2015 Masashi Shinbara @shin1x1
Routing
Controller
Model(Eloquent)
Service
レイヤーの役割
(c) 2015 Masashi Shinbara @shin1x1
Routing
Controller
Model
Service
ルーティング、認証、フィルタ
HTTPリクエスト、レスポンス
バリデーション、サービス実行
事前条件検証、ビジネスロジック
データベースアクセス、
エンティティ固有の処理
レイヤの依存、処理の流れ
(c) 2015 Masashi Shinbara @shin1x1
Routing
Controller
Model(Eloquent)
Service
サービスを中心に考える
(c) 2015 Masashi Shinbara @shin1x1
•サービス(ビジネスドメイン)が中心
•事前条件検証とビジネスロジック
•HTTPの関心毎は持ち込まない

必要なもの引数で渡す(scalar, array, object)
Service
public function update(Reservation $reservation, User $user, array $inputs)

{

if ($user->id !== $reservation->user_id) {

throw new PreconditionException('could_not_update');

}



DB::transaction(function () use ($user, $reservation, $inputs) {

$reservation->book->incrementInventory($reservation->quantity);

$this->store($reservation, $user, $inputs);

});

}
Service
public function update(Reservation $reservation, User $user, array $inputs)

{

if ($user->id !== $reservation->user_id) {

throw new PreconditionException('could_not_update');

}



DB::transaction(function () use ($user, $reservation, $inputs) {

$reservation->book->incrementInventory($reservation->quantity);

$this->store($reservation, $user, $inputs);

});

}
事前条件の検証
Service
public function update(Reservation $reservation, User $user, array $inputs)

{

if ($user->id !== $reservation->user_id) {

throw new PreconditionException('could_not_update');

}



DB::transaction(function () use ($user, $reservation, $inputs) {

$reservation->book->incrementInventory($reservation->quantity);

$this->store($reservation, $user, $inputs);

});

}
ビジネスロジック
サービスから作る
(c) 2015 Masashi Shinbara @shin1x1
• サービスとテストを先に実装
• サービスの最初の利用者は、テスト
• サービスを Web に結ぶのが、コントローラ
• サービスは、バッチ処理等からも、使える
リポジトリパターン
(c) 2015 Masashi Shinbara @shin1x1
• リポジトリパターンは採用しなかった
• データストアは、データベースのみ
• テストは、フィクスチャを利用
• サービス以下は、必要な時に分離すれば良い

(利用者は、その影響を受けない)
ドメインごとに名前空間を分ける
[package]
+ [AcmeOrder]
+ [Controller]
+ [Service]
+ [Model]
+ [Validation]
[AcmeUser]
+ [Controller]
+ [Service]
+ [Model]
+ [Validation]
PSR-4
結果
(c) 2015 Masashi Shinbara @shin1x1
• レイヤの役割に専念できる
• サービスから作るので、何を作るかが明確に
• どこを見れば良いかが分かりやすい
• サービスをどう分割していくかが課題
これから
レイヤ間の抽象化
(c) 2015 Masashi Shinbara @shin1x1
• レイヤ間の連携を抽象化する(主にサービス)
• サービスは、interface を implements

コントローラは、interface を操作
• 実際の具象クラスは知らなくて良い
データストアの分離
(c) 2015 Masashi Shinbara @shin1x1
• サービスからデータストアを分離
• リポジトリパターン
• データストアへの操作が明確になる
DDD - Eric Evans
(c) 2015 Masashi Shinbara @shin1x1
UI
Application
Infrastructure
Domain
Onion Architecture
(c) 2015 Masashi Shinbara @shin1x1
https://www.develop.com/onionarchitecture
まとめ
(c) 2015 Masashi Shinbara @shin1x1
• レイヤードアーキテクチャ
• MVC + Service
• Service を中心に、レイヤを意識
• より良いものを模索する旅は続く
@shin1x1
(c) 2015 Masashi Shinbara @shin1x1
あなたの
アーキテクチャの話が
聴きたい!

レイヤードアーキテクチャを意識したPHPアプリケーションの構築

  • 1.
     @shin1x1 2015/06/27 PHP ConferenceFukuoka レイヤードアーキテクチャを意識した PHPアプリケーションの構築
  • 2.
  • 3.
    レイヤードアーキテクチャ (c) 2015 MasashiShinbara @shin1x1 • アプリケーションをレイヤ(層)に分割 • レイヤ毎に役割を担う • レイヤ間で協調して、処理を行う
  • 4.
    OSI参照モデル (c) 2015 MasashiShinbara @shin1x1 7.Application 6. Presentation 5. Session 4.Transport 3. Network 2. Data link 1. Physical
  • 5.
    MVC (c) 2015 MasashiShinbara @shin1x1 View Controller Model
  • 6.
  • 7.
    CakePHP 1.x (c) 2015Masashi Shinbara @shin1x1
  • 8.
    Fat Model (c) 2015Masashi Shinbara @shin1x1 • 1,000行を超える Model • Model の役割が多すぎる • DAO / バリデーション / ビジネスロジック等々
  • 9.
    MVC (c) 2015 MasashiShinbara @shin1x1 View Controller Model
  • 10.
    MVC + Service (c)2015 Masashi Shinbara @shin1x1 View Controller Model Service
  • 11.
    サービスレイヤを追加 (c) 2015 MasashiShinbara @shin1x1 • Controller と Model の間のレイヤ • ビジネスロジックとバリデーションを担う • 1アクションメソッドに、1サービスクラス • ビジネスロジックの共通化は、モデル or ビヘイビア
  • 12.
    結果 (c) 2015 MasashiShinbara @shin1x1 • Fat(Controller¦Model) を、ある程度解消 • レイヤは、まだグルーピングの単位 • レイヤ間の依存関係が整理されていない
 => サービスが、セッションを操作等
  • 13.
  • 14.
    Laravel (c) 2015 MasashiShinbara @shin1x1 • Laraval + AngularJS • Laravel は、REST API の提供 • UI は、AngularJS
  • 15.
    意識したところ (c) 2015 MasashiShinbara @shin1x1 •レイヤ役割を明確にする •レイヤ間の依存を明確にする • 上位レイヤが下位レイヤを呼ぶ(逆は無い) • 下位レイヤはどこから呼ばれるか関知しない •処理の流れを一方向にする •サービスを中心に考える
  • 16.
    レイヤー構造 (c) 2015 MasashiShinbara @shin1x1 Routing Controller Model(Eloquent) Service
  • 17.
    レイヤーの役割 (c) 2015 MasashiShinbara @shin1x1 Routing Controller Model Service ルーティング、認証、フィルタ HTTPリクエスト、レスポンス バリデーション、サービス実行 事前条件検証、ビジネスロジック データベースアクセス、 エンティティ固有の処理
  • 18.
    レイヤの依存、処理の流れ (c) 2015 MasashiShinbara @shin1x1 Routing Controller Model(Eloquent) Service
  • 19.
    サービスを中心に考える (c) 2015 MasashiShinbara @shin1x1 •サービス(ビジネスドメイン)が中心 •事前条件検証とビジネスロジック •HTTPの関心毎は持ち込まない
 必要なもの引数で渡す(scalar, array, object)
  • 20.
    Service public function update(Reservation$reservation, User $user, array $inputs)
 {
 if ($user->id !== $reservation->user_id) {
 throw new PreconditionException('could_not_update');
 }
 
 DB::transaction(function () use ($user, $reservation, $inputs) {
 $reservation->book->incrementInventory($reservation->quantity);
 $this->store($reservation, $user, $inputs);
 });
 }
  • 21.
    Service public function update(Reservation$reservation, User $user, array $inputs)
 {
 if ($user->id !== $reservation->user_id) {
 throw new PreconditionException('could_not_update');
 }
 
 DB::transaction(function () use ($user, $reservation, $inputs) {
 $reservation->book->incrementInventory($reservation->quantity);
 $this->store($reservation, $user, $inputs);
 });
 } 事前条件の検証
  • 22.
    Service public function update(Reservation$reservation, User $user, array $inputs)
 {
 if ($user->id !== $reservation->user_id) {
 throw new PreconditionException('could_not_update');
 }
 
 DB::transaction(function () use ($user, $reservation, $inputs) {
 $reservation->book->incrementInventory($reservation->quantity);
 $this->store($reservation, $user, $inputs);
 });
 } ビジネスロジック
  • 23.
    サービスから作る (c) 2015 MasashiShinbara @shin1x1 • サービスとテストを先に実装 • サービスの最初の利用者は、テスト • サービスを Web に結ぶのが、コントローラ • サービスは、バッチ処理等からも、使える
  • 24.
    リポジトリパターン (c) 2015 MasashiShinbara @shin1x1 • リポジトリパターンは採用しなかった • データストアは、データベースのみ • テストは、フィクスチャを利用 • サービス以下は、必要な時に分離すれば良い
 (利用者は、その影響を受けない)
  • 25.
    ドメインごとに名前空間を分ける [package] + [AcmeOrder] + [Controller] +[Service] + [Model] + [Validation] [AcmeUser] + [Controller] + [Service] + [Model] + [Validation] PSR-4
  • 26.
    結果 (c) 2015 MasashiShinbara @shin1x1 • レイヤの役割に専念できる • サービスから作るので、何を作るかが明確に • どこを見れば良いかが分かりやすい • サービスをどう分割していくかが課題
  • 27.
  • 28.
    レイヤ間の抽象化 (c) 2015 MasashiShinbara @shin1x1 • レイヤ間の連携を抽象化する(主にサービス) • サービスは、interface を implements
 コントローラは、interface を操作 • 実際の具象クラスは知らなくて良い
  • 29.
    データストアの分離 (c) 2015 MasashiShinbara @shin1x1 • サービスからデータストアを分離 • リポジトリパターン • データストアへの操作が明確になる
  • 30.
    DDD - EricEvans (c) 2015 Masashi Shinbara @shin1x1 UI Application Infrastructure Domain
  • 31.
    Onion Architecture (c) 2015Masashi Shinbara @shin1x1 https://www.develop.com/onionarchitecture
  • 32.
    まとめ (c) 2015 MasashiShinbara @shin1x1 • レイヤードアーキテクチャ • MVC + Service • Service を中心に、レイヤを意識 • より良いものを模索する旅は続く
  • 33.
    @shin1x1 (c) 2015 MasashiShinbara @shin1x1
  • 34.