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 との付き合い方 #phpconokinawa

508 views

Published on

※本発表は、PHPカンファレンス北海道2019の発表(https://www.slideshare.net/ShoheiOkada/laravel-phpcondo)と同じ内容です。

最近、設計に対する関心高まりを感じています。
その一方で「名前は聞いたことあるけど、敷居が高そう......」「本は読んだけど実際に実装するイメージがつかない......」と感じている方もいらっしゃるのではないでしょうか?
本セッションでは設計に関するテーマとして「クリーンアーキテクチャ」を扱い、セッション前半ではクリーンアーキテクチャのコアとなる考え方を説明します。
後半では「フレームワーク非依存」を謳うクリーンアーキテクチャの考え方を、Laravelのプロジェクトに適用する方法を提案します。

2019/10/12 開催の PHP カンファレンス沖縄2019 (https://phpcon.okinawa.jp/) の発表資料です。

Published in: Software
  • Be the first to comment

  • Be the first to like this

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

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

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

×