Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Laravel DDD データ詰め替え戦略
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
okamos
December 11, 2025
73
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Laravel DDD データ詰め替え戦略
okamos
December 11, 2025
More Decks by okamos
See All by okamos
データベースパスワードローテーションの自動化とPHP Swoole を用いたCache戦略について
okamos102
1
88
Featured
See All Featured
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
750
We Have a Design System, Now What?
morganepeng
55
8.2k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
160
Making the Leap to Tech Lead
cromwellryan
135
9.9k
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
1.7k
Ruling the World: When Life Gets Gamed
codingconduct
0
260
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
200
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
260
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
150
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
71
40k
Faster Mobile Websites
deanohume
310
31k
Transcript
Laravel DDD データ詰め替え戦略
はじめに DDDで開発を行う際、レイヤー間で「データの詰め替え」が発生します。 Laravel特有ではなく一般的な問題であり、以下のようなマッピング方法が知られています。 " 引用: データ詰め替え戦略 1. No Mapping (レイヤ間でモデルを共有し、詰め替えをしない)
2. 2-way Mapping (各レイヤで独自のモデルを持ち、レイヤを跨ぐ呼び出しは上位レイヤが詰め替え の責務を負う) 3. Full Mapping (各レイヤで独自のモデルを持ち、レイヤを跨ぐ呼び出しには専用のモデルを使う) ここはありがちなレイヤードアーキテクチャを仮定し の4層レイヤを考えます。 まずは “1. No Mapping” から考え、徐々に依存度を落としていきます。 アプリケーション層 データアクセス層 プレゼンテーション層 ドメイン層 ・ ・ ・
No Mapping No Mapping とは各レイヤでドメインモデルを共有するような戦略です。 ※ここでは各レイヤはそれぞれの具象クラスに依存しているとします。 Domain ModelはそのままActiveRecordとして解釈され、 データアクセス層から プレゼンテーション層まで伝搬します。
素直にLaravelで開発を行う場合はこの形式になることが多いかと思われます。
No Mapping データアクセス層 No Mappingは、データアクセス層から見た場合、非常に都合の良い戦略です。 上位モジュールから渡されたインスタンスをそのまま永続化できるため、データの詰め替え 処理が不要になります。また、テーブル構造に変更があった場合でも、EloquentModel (DomainModel)が自動的に追従するため、デグレが起きにくいという利点があります。 アプリケーション層 データアクセス層に強く依存しているため、業務ロジックを実装する際にデータベースの知
識が染み出してしまいます。 本来、アプリケーション層は純粋な業務ロジックのみを実装するレイヤですが、この構成では テーブル変更の影響を直接受けてしまいます。つまり、アプリケーション層はデータベースの 都合に振り回される脆弱なレイヤと言えます。 この結果、開発者は本来の責務である業務ロジックの実装に加えて、テーブル構造やリレー ションといった永続化の詳細まで考慮する必要が生じます。
プレゼンテーション層 No Mapping データアクセス層の知識が染み出すことにより責務が曖昧になります。 またデータアクセス層を介さずとも、単体で永続化可能となる上、テーブルの変更がそのまま Domain Modelに影響を与えるため、レイヤを分離するメリットを享受しにくいです。 一方で、Eloquentのfactoryを活用することでテストデータを簡単に生成できる点は、利点 として挙げられます。 プレゼンテーション層はViewの描画やAPIレスポンスの整形のみを担う責務ですが、No
Mappingではテーブル構造をそのまま引き継いでしまいます。 また、この構成では、データの整形処理や表示ロジックをControllerまたはViewのいず れかで実装することになります。 前者の場合はControllerが肥大化し、後者の場合はViewが過度に複雑化するという問題 を招きます。 ドメイン層 参考: Eloquent: Factories
No Mapping これでいいのでは? 正直なところ問題ないです。
終 制作・著作 ━━━━━ 第182回 PHP勉強会@東京
No Mapping これでいいのでは? 正直なところ問題ないです。 多くの場合、No Mapping の戦略はうまくいきます。 ただし、現在はプレセンテーション層までDomainModelを伝搬させている都合上、 どうしてもデータの整形や条件分岐をControllerもしくはview で行う必要があります。
viewで表示ロジックを実装する例 これは少しテストが辛そうです。また表示に関するロジックが点在することになります。 解決するのはViewModel(Presenter) と呼ばれる手法です。
ViewModel の導入 直接DomaiModelをview に渡す代わりに、 一度ViewModelというクラスに詰め替えを 行い、それを用いて描画やAPIのレスポンスを 組み立てる方法です。 ViewModelを活用した場合 コードの見通しが良くなり、表示に関するテストもPHPのクラスに対して書けます。 ViewModelとは?
ViewModel の導入 こんなことが本当に必要なのかどうかの議論は昔からなさているそうですが、少なくとも プレゼンテーション層においては有効に働きそうです。 ViewModelはSmartUIやFatControllerというMVCでの開発でしばしば遭遇する問題 に対する1つの回答です。 参考: Skinny Controller, Fat
Model Rails にはActiveRecordをそのまま使いながら、viewで必要な表示ロジックだけを後付けで追加できるDraperとい う便利なツールがあります。ActiveRecordを委譲したDecoratorを実装するだけで利用可能です。 ! Tips " 引用: ローカルDTO Martin Fowler's Bliki (ja) DTOのようなものを使うとよいのは、 プレゼンテーション層のモデルとドメインモデルとの間に 大きなミスマッチが ある場合です。 この場合、プレゼンテーションに特化したファサード(またはゲートウェイ)を作り、 ドメインモデルを マッピングして、プレゼンテーションに都合のよいインターフェースを 提供するのは理に適っています。 これは Presentation Model とも合います。
ViewModel導入で何が解決したか 解決した問題 まだ残っている問題 - プレゼンテーション層の責務が明確になった - 表示ロジックのテストが書きやすくなった - Fat Controller
/ Smart View を回避できた - アプリケーション層が データアクセス層に依存したまま - DomainModel = Eloquent Model という構造は変わらない - テーブル変更がアプリケーション層に波及する
アプリケーション層の独立性 ViewModelは プレゼンテーション層 を「出口」で分離した。 では「入口」はどうでしょうか。 現状 Controller → UseCase(Eloquentに依存)→ Repository
- Requestの構造がそのままUseCaseに流れ込む - HTTPリクエストの都合がビジネスロジックに影響する - UseCaseの単体テストにRequestのモックが必要 InputData(入力用DTO)を導入し、依存を切る 問題 解決策
2-way Mapping という選択肢 各レイヤで独自のモデルを持ち、 レイヤを跨ぐ呼び出しは「上位レイヤ」が詰め替えの責務を負う形式です。 これにより: - プレゼンテーション層はHTTPの都合だけを知る - アプリケーション層は業務ロジックに集中できる
アプリケーション層とプレゼンテーション層の間にDTOを定義
データアクセス層の分離 2-way Mappingで上位レイヤは整理できました。 しかし、ドメイン層とデータアクセス層の間には依然として問題があります。 現状: Domain Model = Eloquent Model(同一)
問題: - ドメインモデルがActiveRecordの制約を受ける - テーブル構造の変更がドメインモデルに直接影響 - 複雑な集約(Aggregate)の表現が困難 選択肢: A) 許容する(多くのプロジェクトではこれで十分) B) 分離する(Full Mapping) → プロジェクトの複雑さに応じて判断
ドメイン駆動開発 目的 ドメイン駆動開発(DDD)を手法として採用するにあたって必要なエッセンスのうち、ここでは 「柔軟性」について考えてみます。DDDにおける柔軟性は、システムが長期的な成功を収める ために不可欠な変化への耐性を指します。 市場のニーズが絶えず変化する中で、たとえ高い精度で開発されたシステムであっても、既存 のモジュールへの変更は避けられません。この変更コストは、市場へ価値を届けるスピードに 直結し、ひいてはビジネスの価値に直接的な影響を及ぼします。 参考: DDD
Reference 柔軟性の高いモジュール あるレイヤの変更が意図しないレイヤに影響を及ぼす可能性を防ぎ、変更の用意性を高める には、設計が疎結合であることが不可欠です モジュール、ひいてはレイヤ間の結合度(Coupling)を低く保ち、隔離(Isolation)を徹底す る必要があります。
徹底的なCleanArchitecture (Full-Mapping) いくつか重要な点がありますが、ここで言いたいのは各レイヤ間で依存が切れているという 点です。InputData/OutputData という構造体への詰め替えを行うことで他レイヤの変 更を直接的に受け辛い形となっています。
徹底的なCleanArchitecture (Full-Mapping) ここまで行う必要があるか。 プレゼンテーション層 → アプリケーション層 間の詰め替えは賛成ですが、 アプリケーション層 → データアクセス層
間の詰め替えには懐疑的です。わたしは直接 Domain Modelを渡していいと考えます。その場合下記のように多少簡略化されます。
データの詰め替え戦略(入力) ここで発生する詰め替えは3回です 1. プレゼンテーション層 - Request → InputData 2. アプリケーション層
- InputData → Domain Model 3. データアクセス層 - Domain Model → Eloquent Model
データの詰め替え戦略(出力) ここで発生する詰め替えも3回です 1. プレゼンテーション層 - OutputData → ViewModel 2. アプリケーション層
- Domain Model → OutputData 3. データアクセス層 - Eloquent Model → Domain Model
データの詰め替え戦略 - どこがボトルネックか 入力 出力 これは経験則ですが、一番複雑な詰め替えは 入力の2. です。 また入力の2. が複雑ということは、永続化も同程度であり、結果的に入力の3.
と出力の3. も複雑になります。 1. プレゼンテーション層 - Request → InputData 2. アプリケーション層 - InputData → Domain Model 3. データアクセス層 - Domain Model → Eloquent Model 1. プレゼンテーション層 - OutputData → ViewModel 2. アプリケーション層 - Domain Model → OutputData 3. データアクセス層 - Eloquent Model → Domain Model
データの詰め替え戦略 - 複雑な入力の2. よくあるのがDomain ModelがEntityの配列を持つ場合です。 さらに、その Entityが継承関係にある場合はかなり面倒です。 ※ここではモデリングに関しては言及しません。生成ロジックが複雑であるということは、集約の切り方に問題があることがあります。
データの詰め替え戦略 - 複雑な 入力の3. と 出力の3. Factoryで行なった条件分岐処理はデータアクセス層にも現れます。 入力の3. と出力の3. です。
ViewModelを活用した場合 ViewModelを活用した場合
データの詰め替え戦略 - 重複の排除 まずこれの解決方法として、オブジェクト指向の知識を借りることができます。 いくつか方法は考えられますが、個別の生成Factoryを定義し、Chaign of Resposibility やStrategyで分岐を実装する手が考えられます。 ただ、結局この実装はアプリケーション層とデータアクセス層の両方で実装する必要がありそ うです。。
データアクセス層 で DomainModelの詰め替え を しなくても永続化できる O/RMapperを出してよ〜
ぱっぱぱー♪
Doctrineの特徴 DoctrineはData Mapper的なORMであり、ActiveRecord系のEloquentとは異なり 下記の特徴を持ちます。 1. 永続化の分離 永続化の対象としてのPHPのClassは、データベース操作のロジックを一切持たない純 粋なPHPオブジェクト(POPO)であり、Eloquentのように特別なClassを継承する必 要もありません。 2.
Unit of Work ActiveRecord とは異なり、開発者が明示的に永続化のメソッドを呼び出したとき に、まとめてデータベースに書き込みます 3. PHPのクラスに対する直接的なマッピング アノテーションもしくはXMLでクエリ結果とPHPのClassの対照を示すことで、直接必 要なDomanModelを取得可能です
Doctrineを活用したデータの詰め替え マッピングをXMLに書き込むことで、Eloquentを用いていた時に必要であった toEloquent や toDomain のようなデータの詰め替え処理が不要になります。 データの詰め替え処理不要 自動で任意のClass生成
データの詰め替えBefore・After(入力) Before: After: データの詰め替え 処理不要
データの詰め替えBefore・After(出力) Before: After: データの詰め替え 処理不要
まとめ Eloquentは非常に強力なORMですが、詰め替え処理がボトルネックとなるようなドメイ ンモデルにおいてはスポット的にDoctrineを採用するのもありだと思いました。