Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

674 views

Published on

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

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

Published in: Software
  • Be the first to comment

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

  1. 1. Laravel PHP Conference Hokkaido 2019 @okashoi WILLGATE, Inc.
  2. 2. • • 🙆 • • #phpcondo 2
  3. 3. • 2 • 3 • 5 • Laravel 10 • 3 • 2 3
  4. 4. • 2 • 3 • 5 • Laravel 10 • 3 • 2 4
  5. 5. • 2 • 3 • 5 • Laravel 10 • 3 • 2 5
  6. 6. • 2 • 3 • 5 • Laravel 10 • 3 • 2 6
  7. 7. • 2 • 3 • 5 • Laravel 10 • 3 • 2 7
  8. 8. • 2 • 3 • 5 • Laravel 10 • 3 • 2 8
  9. 9. 🏁 • • Laravel 9
  10. 10. 🙅 • • Laravel • 10
  11. 11. • 2 • 3 • 5 • Laravel 10 • 3 • 2 11
  12. 12. 2012 ”The Clean Architecture - The Clean Code Blog”, https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html 12
  13. 13. 13 2017 2018
  14. 14. ”The Clean Architecture - The Clean Code Blog”, https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html 14
  15. 15. • 
 • • 15
  16. 16. • • • ※ PHP 16
  17. 17. “ 
 ” 17
  18. 18. • 2 • 3 • 5 • Laravel 10 • 3 • 2 18
  19. 19. 19
  20. 20. 20
  21. 21. 21 🙅
  22. 22. 22
  23. 23. 23
  24. 24. • Enterprise Business Rules • • • Application Business Rules • 24
  25. 25. https://little-hands.hatenablog.com/entry/2019/07/26/ domain-knowledge 25
  26. 26. 26
  27. 27. 27 ↑
  28. 28. 28
  29. 29. package foo; import bar; class Foo { bar.Bar x; function doFoo() { x.process(); } } 29 package bar; class Bar { function process() { // do something... } }
  30. 30. 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
  31. 31. 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
  32. 32. 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
  33. 33. 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... } }
  34. 34. 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... } }
  35. 35. 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
  36. 36. 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
  37. 37. 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
  38. 38. = 38
  39. 39. “ 
 
 ” 39
  40. 40. • 
 ➡ 
 40
  41. 41. 41 UI
  42. 42. • 2 • 3 • 5 • Laravel 10 • 3 • 2 42
  43. 43. Laravel • DI • Eloquent 43
  44. 44. Laravel • 
 Service Provider • Laravel 
 44
  45. 45. Laravel • 
 Service Provider • Laravel 
 45
  46. 46. @Laravel JP Conference 2019 https://speakerdeck.com/mikakane/laravel-package- development 46
  47. 47. 47 packages 

  48. 48. Service Provider • • 
 • = • = 48
  49. 49. 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); }
  50. 50. 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; }
  51. 51. Laravel • 
 Service Provider • Laravel 
 51
  52. 52. Clean Architecture Clean Architecture Kindle No. 3228/6016 52
  53. 53. 53
  54. 54. 54
  55. 55. • • ID 
 55
  56. 56. • • • POPO Plain Old PHP Object ➡ 56
  57. 57. PHP 57 <?php namespace MyAppEntitiesTask; use DatetimeImmutable; /** * Class Inbox * @package MyAppEntitiesTask */ final class Inbox extends Task { /** * @var EstimatedTime|null */ private $estimatedTime;
  58. 58. 58
  59. 59. 59
  60. 60. • • 
 • 
 60
  61. 61. 61 <?php namespace MyAppComponentsCreateInboxUseCase; use MyAppEntitiesTask{Task, Id}; /** * Interface TaskRepository * @package MyAppComponentsCreateInboxUseCase */ interface TaskRepository { /** * 与えられたタスクを永続化する * * @param Task $task */ public function save(Task $task): void;
  62. 62. 62
  63. 63. Web UI 63
  64. 64. Web UI 64
  65. 65. Web UI • • 🙆 • Eloquent 65
  66. 66. <?php namespace MyAppComponentsCreateInboxDataAccessDatabaseRepositories; // 略 /** * Class TaskRepository * @package MyAppComponentsCreateInboxDataAccessDatabaseRepositories */ class TaskRepository implements TaskRepositoryInterface { /** * 与えられたタスクを永続化する * * @param Task $task */ public function save(Task $task): void { $taskRecord = EloquentsTask::create([ 'name' => $task->name()->value(), 'note' => $task->note()->value(), ]); 66
  67. 67. <?php namespace MyAppComponentsCreateInboxDataAccessDatabaseRepositories; // 略 /** * Class TaskRepository * @package MyAppComponentsCreateInboxDataAccessDatabaseRepositories */ class TaskRepository implements TaskRepositoryInterface { /** * 与えられたタスクを永続化する * * @param Task $task */ public function save(Task $task): void { $taskRecord = EloquentsTask::create([ 'name' => $task->name()->value(), 'note' => $task->note()->value(), ]); Eloquent 67
  68. 68. “ 
 
 
 
 ” 68
  69. 69. https://github.com/okashoi/laravel-clean- architecture • • • 69
  70. 70. • 2 • 3 • 5 • Laravel 10 • 3 • 2 70
  71. 71. 71 UI
  72. 72. 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... } }
  73. 73. Laravel • 
 Service Provider • Laravel 
 73
  74. 74. • 2 • 3 • 5 • 10 • 3 • 2 74
  75. 75. / @okashoi @okashoi 75
  76. 76. • Hacker’s GATE 76
  77. 77. • Oysters 77
  78. 78. • Laravel JP Conference 2020 78https://conference2020.laravel.jp/
  79. 79. / @okashoi @okashoi 79 😄

×