Upgrade to Pro — share decks privately, control downloads, hide ads and more …

🏗️ ドメイン駆動設計と依存性逆転の原則

🏗️ ドメイン駆動設計と依存性逆転の原則

社内LTにて、ドメイン駆動設計と依存性逆転の原則を布教しましたʕ◔ϖ◔ʔ

はてなブックマークのコメントもどうぞ!

なお、ドメイン駆動設計を理解するためには、依存についても知る必要があります。

是非、依存関係と依存オブジェクト注入もご参照ください👍🏻

長谷川広樹

August 06, 2021
Tweet

More Decks by 長谷川広樹

Other Decks in Programming

Transcript

  1. 目次 ▪ なぜ,我々は依存関係を理解する必要があるのか ▪ 依存(前回のおさらい) ▪ 依存オブジェクト注入の種類(前回のおさらい) ▪ ドメイン駆動設計の原著のアーキテクチャ ▪

    インフラ層で使われるデザインパターン ▪ レイヤードアーキの問題点 ▪ 解決策 ▪ ドメイン駆動設計のアーキテクチャ変遷 ▪ SOLIDの原則 ▪ B:実装が抽象に依存するべき ▪ A:上位と下位のレイヤーの両方が抽象に依存するべき ▪ 『依存性逆転の原則』の成立 ▪ 改めて,アーキテクチャを見る
  2. 依存(前回のおさらい) ▪ 依存とは クラスAがクラスBを引数/返却値として使用 『 A 』は『B 』に依存 ▪ クラス図における依存

    (例)UserクラスはUserNameクラスを使用 <?php namespace App\Domain\User\Entity; use App\Domain\User\ValueObject\UserName; final class User { // UserNameに依存 public function method(UserName $name): string { return "Hello! " . $name->getName(); } }
  3. 依存オブジェクト注入の種類(前回のおさらい) ▪ コンストラクタインジェクション constructメソッド経由で依存対象を渡す. ▪ メリット constructメソッドはインスタンス生成時のみ有効. セッターを完全に無くした場合に インスタンス生成後に状態を変更不可能. 不変的な(Immutable)オブジェクト

    より安全なシステム <?php namespace App\Domain\User\Entity; use App\Domain\User\ValueObject\UserName; final class User { private UserName $name; public function __construct(UserName $name) { $this->name = $name; } } <?php $name = new UserName(); $user = new User($name); // インジェクション
  4. ドメイン駆動設計の原著のアーキテクチャ ドメイン層 インフラストラクチャ層 プレゼンテーション層 ユースケース層 ※順にコンストラクタインジェクションを実行していく ▪ プレゼンテーション層  ・データの必須や書式に関するバリデーション  ・レスポンス構造の整形

    ... ▪ ユースケース層  ・システムの振舞(ユースケース)を具現化 ... ▪ ドメイン層  ・要件定義で作成したドメインモデル図を具現化  ・ビジネス上ありえない値をバリデーション ... ▪ インフラストラクチャ層  ・Active Recordではなく,リポジトリを使う  ・データを取得し,ドメインモデルを作成 ... レイヤードアーキ
  5. インフラ層で使われるデザインパターン ▪ リポジトリパターン  ・極論,DBは何でもよい.  ・複数のテーブルからデータを取得し,   ドメインモデルを作成.  ・ドメインモデル間の依存関係の設計が自由  ⇒ ドメイン駆動設計に合う ▪

    ちなみに,Active Recordパターン  ・モデルが特定のテーブルに関連づけられる.  ・テーブル間のリレーションの設計が,   そのままドメインモデル間の依存関係になる.  ⇒ ドメイン駆動設計には合わない 引用: https://terasolunaorg.github.io/guideline/public_review/ImplementationAtEachLayer/DomainLayer.html
  6. SOLIDの原則 ▪ SOLIDの原則とは オブジェクト指向プログラミングにおいて, スケーラビリティ,保守性,可読性を高めるための5つの方法のこと ▪ 5原則 ・S:Single Responsibility Principle(単一責任の原則)

    ・O:Open Closed Principle(オープン・クローズドの原則) ・L:Liskov Substitution Principle(リスコフの置換原則) ・I:Interface Segregation Principle(インターフェース分離の原則) ・D:Dependency Inversion Principle(依存性逆転の原則)
  7. 依存性逆転の原則 ▪ 依存性逆転の原則とは  A:上位と下位のレイヤーの両方が抽象に依存するべき.  B:実装が抽象に依存するべき. ▪ レイヤードアーキに組み込むメリット  ・ドメイン層が他レイヤーに依存しなくなる.  ・ユースケース層に影響を与えずに,インフラ層のリポジトリクラスを交換しやすくなる.   ⇒

    テスト時のみ実装リポジトリクラスをモックリポジトリへのエイリアスとすれば,     DBにアクセスしないユニットテストが可能.(モックリポジトリは値を返却するだけ)   ⇒ リプレイス時に異なるリポジトリクラスに交換可能.
  8. B:実装が抽象に依存するべき <?php namespace App\Domain\Foo; interface FooRepositoryIF { // IDを元にドメインモデルを一つ取得 public

    function findById(FooId $id): Foo; // IDを元にドメインモデルを全て取得 public function findAll(): array; } <?php namespace App\Infrastructure\Foo; class FooRepositoryImpl implements FooRepositoryIF { public function findById(FooId $id): Foo // 実装を強制 { } public function findAll(): array { } } 実装が抽象(インターフェース)に依存 ※ 他言語でも類似する機能を使う インターフェースリポジトリ 実装リポジトリクラス
  9. A:上位と下位のレイヤーの両方が抽象に依存するべき <?php namespace App\Interactor\Foo; final class FooInteractor { private FooRepositoryIF

    $fooRepositoryIF; public function __construct(FooRepositoryIF $fooRepositoryIF) // インターラクタークラスはリポジトリに依存 { $this->fooRepositoryIF = $fooRepositoryIF; // データ型はドメイン層のインターフェースリポジトリ } public function getFoo(FooId $id): Foo { return $this->fooRepositoryIF->findById($id); // インターフェースを経由してメソッドをコール } }