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

クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondo

Shohei Okada
September 20, 2019

クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondo

最近、設計に対する関心高まりを感じています。
その一方で「名前は聞いたことあるけど、敷居が高そう......」「本は読んだけど実際に実装するイメージがつかない......」と感じている方もいらっしゃるのではないでしょうか?
本セッションでは設計に関するテーマとして「クリーンアーキテクチャ」を扱い、セッション前半ではクリーンアーキテクチャのコアとなる考え方を説明します。
後半では「フレームワーク非依存」を謳うクリーンアーキテクチャの考え方を、Laravelのプロジェクトに適用する方法を提案します。
※本セッションは、PHPカンファレンス福岡2019でお話した「Laravelでやってみるクリーンアーキテクチャ」(https://www.slideshare.net/ShoheiOkada/laravel-phpconfuk-152500600)を再編した内容になります

2019/09/21 開催の PHP カンファレンス北海道2019 (https://phpcon.hokkaido.jp/) の発表資料です。

Shohei Okada

September 20, 2019
Tweet

More Decks by Shohei Okada

Other Decks in Programming

Transcript

  1. ໨࣍ • ͜ͷτʔΫͷΊ͟͢ͱ͜Ζʢ2 ෼ʣ • ΫϦʔϯΞʔΩςΫνϟͷ֓ཁʢ3 ෼ʣ • ίΞͱͳΔߟ͑ํʢ5 ෼ʣ

    • Laravel ͱͷ෇͖߹͍͔ͨʢ10 ෼ʣ • ·ͱΊʢ3 ෼ʣ • ࣗݾ঺հʢ2 ෼ʣ 3
  2. ໨࣍ • ͜ͷτʔΫͷΊ͟͢ͱ͜Ζʢ2 ෼ʣ • ΫϦʔϯΞʔΩςΫνϟͷ֓ཁʢ3 ෼ʣ • ίΞͱͳΔߟ͑ํʢ5 ෼ʣ

    • Laravel ͱͷ෇͖߹͍͔ͨʢ10 ෼ʣ • ·ͱΊʢ3 ෼ʣ • ࣗݾ঺հʢ2 ෼ʣ 4
  3. ໨࣍ • ͜ͷτʔΫͷΊ͟͢ͱ͜Ζʢ2 ෼ʣ • ΫϦʔϯΞʔΩςΫνϟͷ֓ཁʢ3 ෼ʣ • ίΞͱͳΔߟ͑ํʢ5 ෼ʣ

    • Laravel ͱͷ෇͖߹͍͔ͨʢ10 ෼ʣ • ·ͱΊʢ3 ෼ʣ • ࣗݾ঺հʢ2 ෼ʣ 5
  4. ໨࣍ • ͜ͷτʔΫͷΊ͟͢ͱ͜Ζʢ2 ෼ʣ • ΫϦʔϯΞʔΩςΫνϟͷ֓ཁʢ3 ෼ʣ • ίΞͱͳΔߟ͑ํʢ5 ෼ʣ

    • Laravel ͱͷ෇͖߹͍͔ͨʢ10 ෼ʣ • ·ͱΊʢ3 ෼ʣ • ࣗݾ঺հʢ2 ෼ʣ 6
  5. ໨࣍ • ͜ͷτʔΫͷΊ͟͢ͱ͜Ζʢ2 ෼ʣ • ΫϦʔϯΞʔΩςΫνϟͷ֓ཁʢ3 ෼ʣ • ίΞͱͳΔߟ͑ํʢ5 ෼ʣ

    • Laravel ͱͷ෇͖߹͍͔ͨʢ10 ෼ʣ • ·ͱΊʢ3 ෼ʣ • ࣗݾ঺հʢ2 ෼ʣ 7
  6. ໨࣍ • ͜ͷτʔΫͷΊ͟͢ͱ͜Ζʢ2 ෼ʣ • ΫϦʔϯΞʔΩςΫνϟͷ֓ཁʢ3 ෼ʣ • ίΞͱͳΔߟ͑ํʢ5 ෼ʣ

    • Laravel ͱͷ෇͖߹͍͔ͨʢ10 ෼ʣ • ·ͱΊʢ3 ෼ʣ • ࣗݾ঺հʢ2 ෼ʣ 8
  7. ໨࣍ • ͜ͷτʔΫͷΊ͟͢ͱ͜Ζʢ2 ෼ʣ • ΫϦʔϯΞʔΩςΫνϟͷ֓ཁʢ3 ෼ʣ • ίΞͱͳΔߟ͑ํʢ5 ෼ʣ

    • Laravel ͱͷ෇͖߹͍͔ͨʢ10 ෼ʣ • ·ͱΊʢ3 ෼ʣ • ࣗݾ঺հʢ2 ෼ʣ 11
  8. ໨࣍ • ͜ͷτʔΫͷΊ͟͢ͱ͜Ζʢ2 ෼ʣ • ΫϦʔϯΞʔΩςΫνϟͷ֓ཁʢ3 ෼ʣ • ίΞͱͳΔߟ͑ํʢ5 ෼ʣ

    • Laravel ͱͷ෇͖߹͍͔ͨʢ10 ෼ʣ • ·ͱΊʢ3 ෼ʣ • ࣗݾ঺հʢ2 ෼ʣ 18
  9. యܕతͳґଘؔ܎ͷίʔυ package foo; import bar; class Foo { bar.Bar x;

    function doFoo() { x.process(); } } 29 package bar; class Bar { function process() { // do something... } }
  10. యܕతͳґଘؔ܎ͷίʔυ package foo; import bar; class Foo { bar.Bar x;

    function doFoo() { x.process(); } } 30 package bar; class Bar { function process() { // do something... } } foo ͔Β bar ͷॲཧΛݺͼग़͢ = ॲཧͷํ޲ foo → bar
  11. యܕతͳґଘؔ܎ͷίʔυ package foo; import bar; class Foo { bar.Bar x;

    function doFoo() { x.process(); } } 31 package bar; class Bar { function process() { // do something... } } foo ͕ bar ͷ͜ͱΛ஌͍ͬͯΔ = ґଘͷํ޲ foo → bar
  12. యܕతͳґଘؔ܎ͷίʔυ package foo; import bar; class Foo { bar.Bar x;

    function doFoo() { x.process(); } } 32 package bar; class Bar { function process() { // do something... } } ॲཧͷํ޲ foo → bar ґଘͷํ޲ foo → bar
  13. ґଘؔ܎ٯసͨ͠ίʔυ package foo; class Foo { Buz x; function doFoo()

    { x.process(); } } interface Buz { function process(); } 33 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } }
  14. ґଘؔ܎ٯసͨ͠ίʔυ package foo; class Foo { Buz x; function doFoo()

    { x.process(); } } interface Buz { function process(); } 34 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } }
  15. ґଘؔ܎ٯసͨ͠ίʔυ package foo; class Foo { Buz x; function doFoo()

    { x.process(); } } interface Buz { function process(); } 35 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } } foo ͔Β bar ͷॲཧΛݺͼग़͢ = ॲཧͷํ޲ foo → bar
  16. ґଘؔ܎ٯసͨ͠ίʔυ package foo; class Foo { Buz x; function doFoo()

    { x.process(); } } interface Buz { function process(); } 36 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } } bar ͕ foo ͷ͜ͱΛ஌͍ͬͯΔ = ґଘͷํ޲ foo ← bar
  17. ґଘؔ܎ٯసͨ͠ίʔυ package foo; class Foo { Buz x; function doFoo()

    { x.process(); } } interface Buz { function process(); } 37 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } } ॲཧͷํ޲ foo → bar ґଘͷํ޲ foo ← bar
  18. ໨࣍ • ͜ͷτʔΫͷΊ͟͢ͱ͜Ζʢ2 ෼ʣ • ΫϦʔϯΞʔΩςΫνϟͷ֓ཁʢ3 ෼ʣ • ίΞͱͳΔߟ͑ํʢ5 ෼ʣ

    • Laravel ͱͷ෇͖߹͍͔ͨʢ10 ෼ʣ • ·ͱΊʢ3 ෼ʣ • ࣗݾ঺հʢ2 ෼ʣ 42
  19. Service Provider ΠϯλʔϑΣʔεͱ۩৅ΫϥεΛ݁ͼ͚ͭΔ 49 class AppServiceProvider extends ServiceProvider { /**

    * Register any application services. * * @return void */ public function register() { $this->app->bind(IdProvider::class, AutoIncrementTaskIdProvider::class); $this->app->bind(TaskRepositoryInterface::class, TaskRepository::class); }
  20. Service Container ΠϯλʔϑΣʔεͰܕએݴΛ͢Δ͕
 ࣮ࡍʹ͸۩৅ΫϥεͷΠϯελϯε͕౉͞ΕΔ 50 /** * Interactor constructor. *

    @param IdProvider $idProvider * @param TaskRepository $taskRepository * @param NormalOutputBoundary $normalOutputBoundary */ public function __construct(IdProvider $idProvider, TaskRepository $taskRepository, … { $this->idProvider = $idProvider; $this->taskRepository = $taskRepository; $this->normalOutputBoundary = $normalOutputBoundary; }
  21. ϑϨʔϜϫʔΫʹґଘͤ͞ͳ͍ PHP ૊ΈࠐΈͷΫϥεఔ౓ʹͱͲΊΔ 57 <?php namespace MyApp\Entities\Task; use DatetimeImmutable; /**

    * Class Inbox * @package MyApp\Entities\Task */ final class Inbox extends Task { /** * @var EstimatedTime|null */ private $estimatedTime;
  22. σʔλϕʔε౳ʹґଘͤ͞ͳ͍ ग़ྗ΍σʔλૢ࡞ͷΠϯλʔϑΣʔεΛఆٛ 61 <?php namespace MyApp\Components\CreateInbox\UseCase; use MyApp\Entities\Task\{Task, Id}; /**

    * Interface TaskRepository * @package MyApp\Components\CreateInbox\UseCase */ interface TaskRepository { /** * 与えられたタスクを永続化する * * @param Task $task */ public function save(Task $task): void;
  23. <?php namespace MyApp\Components\CreateInbox\DataAccess\Database\Repositories; // 略 /** * Class TaskRepository *

    @package MyApp\Components\CreateInbox\DataAccess\Database\Repositories */ class TaskRepository implements TaskRepositoryInterface { /** * 与えられたタスクを永続化する * * @param Task $task */ public function save(Task $task): void { $taskRecord = Eloquents\Task::create([ 'name' => $task->name()->value(), 'note' => $task->note()->value(), ]); ΠϯλʔϑΣʔεͷ࣮૷ ϢʔεέʔεͰఆٛͨ͠ΠϯλʔϑΣʔεΛ࣮૷ 66
  24. <?php namespace MyApp\Components\CreateInbox\DataAccess\Database\Repositories; // 略 /** * Class TaskRepository *

    @package MyApp\Components\CreateInbox\DataAccess\Database\Repositories */ class TaskRepository implements TaskRepositoryInterface { /** * 与えられたタスクを永続化する * * @param Task $task */ public function save(Task $task): void { $taskRecord = Eloquents\Task::create([ 'name' => $task->name()->value(), 'note' => $task->note()->value(), ]); ΠϯλʔϑΣʔεͷ࣮૷ Eloquent ౳͸͜͜Ͱ࢖ͬͯྑ͍ 67
  25. ໨࣍ • ͜ͷτʔΫͷΊ͟͢ͱ͜Ζʢ2 ෼ʣ • ΫϦʔϯΞʔΩςΫνϟͷ֓ཁʢ3 ෼ʣ • ίΞͱͳΔߟ͑ํʢ5 ෼ʣ

    • Laravel ͱͷ෇͖߹͍͔ͨʢ10 ෼ʣ • ·ͱΊʢ3 ෼ʣ • ࣗݾ঺հʢ2 ෼ʣ 70
  26. ґଘؔ܎ٯసͨ͠ίʔυ package foo; class Foo { Buz x; function doFoo()

    { x.process(); } } interface Buz { function process(); } 72 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } }
  27. ໨࣍ • ͜ͷτʔΫͷΊ͟͢ͱ͜Ζʢ2 ෼ʣ • ΫϦʔϯΞʔΩςΫνϟͷ֓ཁʢ3 ෼ʣ • ίΞͱͳΔߟ͑ํʢ5 ෼ʣ

    • ۩ମతͳίʔυྫʢ10 ෼ʣ • ·ͱΊʢ3 ෼ʣ • ࣗݾ঺հʢ2 ෼ʣ 74