SlideShare a Scribd company logo
Laravel
PHP Conference Fukuoka 2019
@okashoi WILLGATE, Inc.
•
• 🙆
•
• #phpconfuk #hall_fu
2
• 2
• 3
• 5
• 10
• 3
• 2
3
• 2
• 3
• 5
• 10
• 3
• 2
4
🏁
•
•
• Laravel


5
🙅
• Laravel
•
6
• 2
• 3
• 5
• 10
• 3
• 2
7
8
2017 2018
”The Clean Architecture - The Clean Code Blog”,
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
9
• 

•
•
10
•
•
•
※ PHP
11
“ 

”
12
• 2
• 3
• 5
• 10
• 3
• 2
13
14
15
16
🙅
17
18
•
•
•
•
19
20
21
↑
22
package foo;
import bar;
class Foo {
bar.Bar x;
function doFoo() {
x.process();
}
}
23
package bar;
class Bar {
function process() {
// do something...
}
}
package foo;
import bar;
class Foo {
bar.Bar x;
function doFoo() {
x.process();
}
}
24
package bar;
class Bar {
function process() {
// do something...
}
}
foo bar = foo → bar
package foo;
import bar;
class Foo {
bar.Bar x;
function doFoo() {
x.process();
}
}
25
package bar;
class Bar {
function process() {
// do something...
}
}
foo bar = foo → bar
package foo;
import bar;
class Foo {
bar.Bar x;
function doFoo() {
x.process();
}
}
26
package bar;
class Bar {
function process() {
// do something...
}
}
foo → bar
foo → bar
package foo;
class Foo {
Buz x;
function doFoo() {
x.process();
}
}
interface Buz {
function process();
}
27
package bar;
import foo;
class Bar implements foo.Buz {
function process() {
// do something...
}
}
package foo;
class Foo {
Buz x;
function doFoo() {
x.process();
}
}
interface Buz {
function process();
}
28
package bar;
import foo;
class Bar implements foo.Buz {
function process() {
// do something...
}
}
package foo;
class Foo {
Buz x;
function doFoo() {
x.process();
}
}
interface Buz {
function process();
}
29
package bar;
import foo;
class Bar implements foo.Buz {
function process() {
// do something...
}
}
foo bar = foo → bar
package foo;
class Foo {
Buz x;
function doFoo() {
x.process();
}
}
interface Buz {
function process();
}
30
package bar;
import foo;
class Bar implements foo.Buz {
function process() {
// do something...
}
}
bar foo = foo ← bar
package foo;
class Foo {
Buz x;
function doFoo() {
x.process();
}
}
interface Buz {
function process();
}
31
package bar;
import foo;
class Bar implements foo.Buz {
function process() {
// do something...
}
}
foo → bar
foo ← bar
“ 



”
32
• 

➡ 

33
34
UI
• 2
• 3
• 5
• 10
• 3
• 2
35
CleanArchitecture
Clean Architecture
Kindle No. 3228/6016 36
•
• https://github.com/okashoi/laravel-clean-
architecture
•
•
37
38
•
•
ID 

39
readme
40
•
•
• POPO Plain Old PHP Object
➡
41
• PHP
42
<?php
namespace MyAppComponentsTasksEntities;
use DatetimeImmutable;
/**
* Class Inbox
* @package MyAppComponentsTasksEntities
*/
final class Inbox extends Task
{
/**
* @var EstimatedTime|null
*/
private $estimatedTime;
•
•
43
/**
* @test
* @expectedException MyAppComponentsTasksEntitiesEstimatedTimeNotSet
*/
public function 「Inbox」に対して「見積もり時間」が未設定のまま「着手日」を設定できないこと()
{
$id = Mockery::mock(Id::class);
$name = new Name('test');
$inbox = new Inbox($id, $name);
$startDate = new StartDate(new DateTimeImmutable('tomorrow'));
$inbox->convertToScheduled($startDate);
}
44
45
•
• 

• 

46
InputBoundary / OutputBoundary
• 

47
<?php
namespace MyAppComponentsTasksUseCasesCreateInbox;
/**
* Interface InputBoundary
* @package MyAppComponentsTasksUseCasesCreateInbox
*/
interface InputBoundary
{
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void;
}
InputBoundary / OutputBoundary
• 

48
<?php
namespace MyAppComponentsTasksUseCasesCreateInbox;
/**
* Interface NormalOutputBoundary
* @package MyAppComponentsTasksUseCasesCreateInbox
*/
interface NormalOutputBoundary
{
/**
* @param NormalOutputData $output
*/
public function __invoke(NormalOutputData $output): void;
}
Interactor
49
<?php
namespace MyAppComponentsTasksUseCasesCreateInbox;
use MyAppComponentsTasksEntities{Inbox, Task, Name, Note};
use MyAppComponentsTasksUseCases{IdProvider, TaskRepository};
/**
* Class Interactor
* @package MyAppComponentsTasksUseCasesCreateInbox
*/
final class Interactor implements InputBoundary
{
/**
* @var IdProvider
*/
private $idProvider;
/**
* @var TaskRepository
*/
private $taskRepository;
/**
* @var NormalOutputBoundary
*/
private $normalOutputBoundary;
/**
* Interactor constructor.
* @param IdProvider $idProvider
* @param TaskRepository $taskRepository
* @param NormalOutputBoundary $normalOutputBoundary
*/
public function __construct(IdProvider $idProvider, TaskRepository $t
{
$this->idProvider = $idProvider;
$this->taskRepository = $taskRepository;
$this->normalOutputBoundary = $normalOutputBoundary;
}
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
/**
* @param InputData $input
* @return Task
Interactor
50
<?php
namespace MyAppComponentsTasksUseCasesCreateInbox;
use MyAppComponentsTasksEntities{Inbox, Task, Name, Note};
use MyAppComponentsTasksUseCases{IdProvider, TaskRepository};
/**
* Class Interactor
* @package MyAppComponentsTasksUseCasesCreateInbox
*/
final class Interactor implements InputBoundary
{
/**
* @var IdProvider
*/
private $idProvider;
/**
* @var TaskRepository
*/
private $taskRepository;
/**
* @var NormalOutputBoundary
*/
private $normalOutputBoundary;
/**
* Interactor constructor.
* @param IdProvider $idProvider
* @param TaskRepository $taskRepository
* @param NormalOutputBoundary $normalOutputBoundary
*/
public function __construct(IdProvider $idProvider, TaskRepository $t
{
$this->idProvider = $idProvider;
$this->taskRepository = $taskRepository;
$this->normalOutputBoundary = $normalOutputBoundary;
}
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
/**
* @param InputData $input
* @return Task
InputBoundary
Interactor
51
<?php
namespace MyAppComponentsTasksUseCasesCreateInbox;
use MyAppComponentsTasksEntities{Inbox, Task, Name, Note};
use MyAppComponentsTasksUseCases{IdProvider, TaskRepository};
/**
* Class Interactor
* @package MyAppComponentsTasksUseCasesCreateInbox
*/
final class Interactor implements InputBoundary
{
/**
* @var IdProvider
*/
private $idProvider;
/**
* @var TaskRepository
*/
private $taskRepository;
/**
* @var NormalOutputBoundary
*/
private $normalOutputBoundary;
/**
* Interactor constructor.
* @param IdProvider $idProvider
* @param TaskRepository $taskRepository
* @param NormalOutputBoundary $normalOutputBoundary
*/
public function __construct(IdProvider $idProvider, TaskRepository $t
{
$this->idProvider = $idProvider;
$this->taskRepository = $taskRepository;
$this->normalOutputBoundary = $normalOutputBoundary;
}
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
/**
* @param InputData $input
* @return Task
DI
※ 

Interactor
52
<?php
namespace MyAppComponentsTasksUseCasesCreateInbox;
use MyAppComponentsTasksEntities{Inbox, Task, Name, Note};
use MyAppComponentsTasksUseCases{IdProvider, TaskRepository};
/**
* Class Interactor
* @package MyAppComponentsTasksUseCasesCreateInbox
*/
final class Interactor implements InputBoundary
{
/**
* @var IdProvider
*/
private $idProvider;
/**
* @var TaskRepository
*/
private $taskRepository;
/**
* @var NormalOutputBoundary
*/
private $normalOutputBoundary;
/**
* Interactor constructor.
* @param IdProvider $idProvider
* @param TaskRepository $taskRepository
* @param NormalOutputBoundary $normalOutputBoundary
*/
public function __construct(IdProvider $idProvider, TaskRepository $t
{
$this->idProvider = $idProvider;
$this->taskRepository = $taskRepository;
$this->normalOutputBoundary = $normalOutputBoundary;
}
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
/**
* @param InputData $input
* @return Task


Interactor::__invoke()


53
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
Interactor::__invoke()


54
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
Interactor::__invoke()


55
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
Interactor::__invoke()
OutputBoundary 

56
/**
* @param InputData $input
*/
public function __invoke(InputData $input): void
{
$inbox = $this->produceEntity($input);
$this->taskRepository->save($inbox);
$normalOutput = $this->produceNormalOutputData($inbox);
($this->normalOutputBoundary)($normalOutput);
}
57
•
• Repository
• 🙆
• Eloquent
58
Web UI
59
Web UI
•
• Controller 

void
• 

60
Controller
61
<?php
namespace MyAppWebControllers;
use IlluminateHttpRequest;
use MyAppComponentsTasksUseCasesCreateInboxInputData;
use MyAppComponentsTasksUseCasesCreateInboxInputBoundary;
/**
* Class CreateInbox
* @package MyAppWebControllers
*/
final class CreateInbox extends Controller
{
/**
* @param Request $request
* @param InputBoundary $interactor
*/
public function __invoke(Request $request, InputBoundary $interactor)
{
$validated = $this->validate($request, [
'name' => 'required|string|max:255',
'note' => 'string|nullable',
]);
$input = new InputData($validated['name'], $validated['note'] ?? '');
$interactor($input);
}
}
Controller
62
<?php
namespace MyAppWebControllers;
use IlluminateHttpRequest;
use MyAppComponentsTasksUseCasesCreateInboxInputData;
use MyAppComponentsTasksUseCasesCreateInboxInputBoundary;
/**
* Class CreateInbox
* @package MyAppWebControllers
*/
final class CreateInbox extends Controller
{
/**
* @param Request $request
* @param InputBoundary $interactor
*/
public function __invoke(Request $request, InputBoundary $interactor)
{
$validated = $this->validate($request, [
'name' => 'required|string|max:255',
'note' => 'string|nullable',
]);
$input = new InputData($validated['name'], $validated['note'] ?? '');
$interactor($input);
}
}
Laravel HttpControllers
Controller
63
<?php
namespace MyAppWebControllers;
use IlluminateHttpRequest;
use MyAppComponentsTasksUseCasesCreateInboxInputData;
use MyAppComponentsTasksUseCasesCreateInboxInputBoundary;
/**
* Class CreateInbox
* @package MyAppWebControllers
*/
final class CreateInbox extends Controller
{
/**
* @param Request $request
* @param InputBoundary $interactor
*/
public function __invoke(Request $request, InputBoundary $interactor)
{
$validated = $this->validate($request, [
'name' => 'required|string|max:255',
'note' => 'string|nullable',
]);
$input = new InputData($validated['name'], $validated['note'] ?? '');
$interactor($input);
}
}
HTTP
Controller
64
<?php
namespace MyAppWebControllers;
use IlluminateHttpRequest;
use MyAppComponentsTasksUseCasesCreateInboxInputData;
use MyAppComponentsTasksUseCasesCreateInboxInputBoundary;
/**
* Class CreateInbox
* @package MyAppWebControllers
*/
final class CreateInbox extends Controller
{
/**
* @param Request $request
* @param InputBoundary $interactor
*/
public function __invoke(Request $request, InputBoundary $interactor)
{
$validated = $this->validate($request, [
'name' => 'required|string|max:255',
'note' => 'string|nullable',
]);
$input = new InputData($validated['name'], $validated['note'] ?? '');
$interactor($input);
}
}
InputBoundary Interactor
Controller
65
<?php
namespace MyAppWebControllers;
use IlluminateHttpRequest;
use MyAppComponentsTasksUseCasesCreateInboxInputData;
use MyAppComponentsTasksUseCasesCreateInboxInputBoundary;
/**
* Class CreateInbox
* @package MyAppWebControllers
*/
final class CreateInbox extends Controller
{
/**
* @param Request $request
* @param InputBoundary $interactor
*/
public function __invoke(Request $request, InputBoundary $interactor)
{
$validated = $this->validate($request, [
'name' => 'required|string|max:255',
'note' => 'string|nullable',
]);
$input = new InputData($validated['name'], $validated['note'] ?? '');
$interactor($input);
}
}
Presenter
•
66
<?php
namespace MyAppWebPresentersCreateInbox;
use IlluminateViewFactory;
use MyAppWebPresentersPresenter as BasePresenter;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputData;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary;
/**
* Class CreateInboxPresenter
* @package MyAppWebPresenters
*/
final class Presenter extends BasePresenter implements NormalOutputBoundary
{
// 中略
/**
* @param NormalOutputData $output
*/
public function __invoke(NormalOutputData $output): void
{
$viewModel = new ViewModel(
$output->taskId(),
$output->taskName(),
$output->taskNote(),
);
$this->respond($this->view->make('web::tasks.create', compact(['viewModel'])));
}
}
Presenter
•
67
<?php
namespace MyAppWebPresentersCreateInbox;
use IlluminateViewFactory;
use MyAppWebPresentersPresenter as BasePresenter;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputData;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary;
/**
* Class CreateInboxPresenter
* @package MyAppWebPresenters
*/
final class Presenter extends BasePresenter implements NormalOutputBoundary
{
// 中略
/**
* @param NormalOutputData $output
*/
public function __invoke(NormalOutputData $output): void
{
$viewModel = new ViewModel(
$output->taskId(),
$output->taskName(),
$output->taskNote(),
);
$this->respond($this->view->make('web::tasks.create', compact(['viewModel'])));
}
}
Interactor ViewModel
Presenter
•
68
<?php
namespace MyAppWebPresentersCreateInbox;
use IlluminateViewFactory;
use MyAppWebPresentersPresenter as BasePresenter;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputData;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary;
/**
* Class CreateInboxPresenter
* @package MyAppWebPresenters
*/
final class Presenter extends BasePresenter implements NormalOutputBoundary
{
// 中略
/**
* @param NormalOutputData $output
*/
public function __invoke(NormalOutputData $output): void
{
$viewModel = new ViewModel(
$output->taskId(),
$output->taskName(),
$output->taskNote(),
);
$this->respond($this->view->make('web::tasks.create', compact(['viewModel'])));
}
}
View
※ Controller 

void ……🙇
•
• ServiceProvider
69
70
<?php
namespace AppProviders;
use IlluminateSupportServiceProvider;
use MyAppComponentsTasksUseCasesCreateInboxInputBoundary;
use MyAppComponentsTasksUseCasesCreateInboxInteractor;
use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary;
use MyAppComponentsTasksUseCasesIdProvider;
use MyAppComponentsTasksUseCasesTaskRepository as TaskRepositoryInterface;
use MyAppDatabaseRepositoriesAutoIncrementTaskIdProvider;
use MyAppDatabaseRepositoriesTaskRepository;
use MyAppWebPresentersCreateInboxPresenter;
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);
$this->app->bind(InputBoundary::class, Interactor::class);
$this->app->bind(NormalOutputBoundary::class, Presenter::class);
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
}
}
Laravel
• Laravel
• DI ServiceContainer
• 

ServiceProvider
• 

71
@Laravel JP Conference 2019
https://speakerdeck.com/mikakane/laravel-package-
development 72
73
74
packages 

75


76




77
web routes 

views
• 2
• 3
• 5
• 10
• 3
• 2
78
79
UI
package foo;
class Foo {
Buz x;
function doFoo() {
x.process();
}
}
interface Buz {
function process();
}
80
package bar;
import foo;
class Bar implements foo.Buz {
function process() {
// do something...
}
}
🏁
•
•
• Laravel


81
• 2
• 3
• 5
• 10
• 3
• 2
82
/
@okashoi
@okashoi
83
• Hacker’s GATE
84
• Oysters
85
• Laravel JP Conference 2020
86https://conference2020.laravel.jp/
Ask the Speaker 

😂
87

More Related Content

What's hot

イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
Yoshitaka Kawashima
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
Takuto Wada
 
Where狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーWhere狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキー
yoku0825
 
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
NTT DATA Technology & Innovation
 
オブジェクト指向プログラミングのためのモデリング入門
オブジェクト指向プログラミングのためのモデリング入門オブジェクト指向プログラミングのためのモデリング入門
オブジェクト指向プログラミングのためのモデリング入門
増田 亨
 
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
NTT DATA Technology & Innovation
 
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
onozaty
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ増田 亨
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
Takafumi ONAKA
 
どこに何を書くのか?
どこに何を書くのか?どこに何を書くのか?
どこに何を書くのか?
pospome
 
設計してますか?
設計してますか?設計してますか?
設計してますか?
ke-m kamekoopa
 
Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsug
Masatoshi Tada
 
データベース設計徹底指南
データベース設計徹底指南データベース設計徹底指南
データベース設計徹底指南
Mikiya Okuno
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
Taku Miyakawa
 
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門
増田 亨
 
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
NTT DATA Technology & Innovation
 
ドメイン駆動設計サンプルコードの徹底解説
ドメイン駆動設計サンプルコードの徹底解説ドメイン駆動設計サンプルコードの徹底解説
ドメイン駆動設計サンプルコードの徹底解説
増田 亨
 
世界でいちばんわかりやすいドメイン駆動設計
世界でいちばんわかりやすいドメイン駆動設計世界でいちばんわかりやすいドメイン駆動設計
世界でいちばんわかりやすいドメイン駆動設計
増田 亨
 
DDD sample code explained in Java
DDD sample code explained in JavaDDD sample code explained in Java
DDD sample code explained in Java
増田 亨
 
O/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐO/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐ
kwatch
 

What's hot (20)

イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
Where狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーWhere狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキー
 
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
 
オブジェクト指向プログラミングのためのモデリング入門
オブジェクト指向プログラミングのためのモデリング入門オブジェクト指向プログラミングのためのモデリング入門
オブジェクト指向プログラミングのためのモデリング入門
 
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
 
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
 
どこに何を書くのか?
どこに何を書くのか?どこに何を書くのか?
どこに何を書くのか?
 
設計してますか?
設計してますか?設計してますか?
設計してますか?
 
Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsug
 
データベース設計徹底指南
データベース設計徹底指南データベース設計徹底指南
データベース設計徹底指南
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
 
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門
 
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
 
ドメイン駆動設計サンプルコードの徹底解説
ドメイン駆動設計サンプルコードの徹底解説ドメイン駆動設計サンプルコードの徹底解説
ドメイン駆動設計サンプルコードの徹底解説
 
世界でいちばんわかりやすいドメイン駆動設計
世界でいちばんわかりやすいドメイン駆動設計世界でいちばんわかりやすいドメイン駆動設計
世界でいちばんわかりやすいドメイン駆動設計
 
DDD sample code explained in Java
DDD sample code explained in JavaDDD sample code explained in Java
DDD sample code explained in Java
 
O/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐO/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐ
 

Similar to Laravel でやってみるクリーンアーキテクチャ #phpconfuk

クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumai
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumaiクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumai
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumai
Shohei Okada
 
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondo
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondoクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondo
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondo
Shohei Okada
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
Rowan Merewood
 
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawaクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
Shohei Okada
 
New in php 7
New in php 7New in php 7
New in php 7
Vic Metcalfe
 
2012 coscup - Build your PHP application on Heroku
2012 coscup - Build your PHP application on Heroku2012 coscup - Build your PHP application on Heroku
2012 coscup - Build your PHP application on Herokuronnywang_tw
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest UpdatesIftekhar Eather
 
The Beauty of Java Script
The Beauty of Java ScriptThe Beauty of Java Script
The Beauty of Java Script
Michael Girouard
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStorm
Michelangelo van Dam
 
The Beauty Of Java Script V5a
The Beauty Of Java Script V5aThe Beauty Of Java Script V5a
The Beauty Of Java Script V5arajivmordani
 
Codeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept ImplementationCodeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept Implementation
Abdul Malik Ikhsan
 
Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)
Damien Seguy
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
把鐵路開進視窗裡
把鐵路開進視窗裡把鐵路開進視窗裡
把鐵路開進視窗裡Wei Jen Lu
 
TYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase frameworkTYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase framework
Christian Trabold
 
Php on the desktop and php gtk2
Php on the desktop and php gtk2Php on the desktop and php gtk2
Php on the desktop and php gtk2
Elizabeth Smith
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfast
Michelangelo van Dam
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
chartjes
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
Michelangelo van Dam
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
Hugo Hamon
 

Similar to Laravel でやってみるクリーンアーキテクチャ #phpconfuk (20)

クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumai
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumaiクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumai
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumai
 
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondo
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondoクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondo
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondo
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawaクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
 
New in php 7
New in php 7New in php 7
New in php 7
 
2012 coscup - Build your PHP application on Heroku
2012 coscup - Build your PHP application on Heroku2012 coscup - Build your PHP application on Heroku
2012 coscup - Build your PHP application on Heroku
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest Updates
 
The Beauty of Java Script
The Beauty of Java ScriptThe Beauty of Java Script
The Beauty of Java Script
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStorm
 
The Beauty Of Java Script V5a
The Beauty Of Java Script V5aThe Beauty Of Java Script V5a
The Beauty Of Java Script V5a
 
Codeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept ImplementationCodeigniter : Two Step View - Concept Implementation
Codeigniter : Two Step View - Concept Implementation
 
Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
把鐵路開進視窗裡
把鐵路開進視窗裡把鐵路開進視窗裡
把鐵路開進視窗裡
 
TYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase frameworkTYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase framework
 
Php on the desktop and php gtk2
Php on the desktop and php gtk2Php on the desktop and php gtk2
Php on the desktop and php gtk2
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfast
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 

More from Shohei Okada

「登壇しているひとは偉い」という話
「登壇しているひとは偉い」という話「登壇しているひとは偉い」という話
「登壇しているひとは偉い」という話
Shohei Okada
 
PHP-FPM の子プロセス制御方法と設定をおさらいしよう
PHP-FPM の子プロセス制御方法と設定をおさらいしようPHP-FPM の子プロセス制御方法と設定をおさらいしよう
PHP-FPM の子プロセス制御方法と設定をおさらいしよう
Shohei Okada
 
PHP 8.0 の新記法を試してみよう!
PHP 8.0 の新記法を試してみよう!PHP 8.0 の新記法を試してみよう!
PHP 8.0 の新記法を試してみよう!
Shohei Okada
 
自分たちのコードを Composer パッケージに分割して開発する
自分たちのコードを Composer パッケージに分割して開発する自分たちのコードを Composer パッケージに分割して開発する
自分たちのコードを Composer パッケージに分割して開発する
Shohei Okada
 
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyoエラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
Shohei Okada
 
スペシャリストとして組織をつくる、というキャリア
スペシャリストとして組織をつくる、というキャリアスペシャリストとして組織をつくる、というキャリア
スペシャリストとして組織をつくる、というキャリア
Shohei Okada
 
PHP でも活用できる Makefile
PHP でも活用できる MakefilePHP でも活用できる Makefile
PHP でも活用できる Makefile
Shohei Okada
 
はじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよ
はじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよはじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよ
はじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよ
Shohei Okada
 
Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered archi...
Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered archi...Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered archi...
Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered archi...
Shohei Okada
 
働き方が大きく変わった 入社3年目のときのとあるエピソード
働き方が大きく変わった 入社3年目のときのとあるエピソード働き方が大きく変わった 入社3年目のときのとあるエピソード
働き方が大きく変わった 入社3年目のときのとあるエピソード
Shohei Okada
 
Laravel で API バージョニングを実装するなら
Laravel で API バージョニングを実装するならLaravel で API バージョニングを実装するなら
Laravel で API バージョニングを実装するなら
Shohei Okada
 
Laravel における Blade 拡張のツラミ
Laravel における Blade 拡張のツラミLaravel における Blade 拡張のツラミ
Laravel における Blade 拡張のツラミ
Shohei Okada
 
Laravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのかLaravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのか
Shohei Okada
 
2017 年度を振り返って ~アウトプット編~
2017 年度を振り返って ~アウトプット編~2017 年度を振り返って ~アウトプット編~
2017 年度を振り返って ~アウトプット編~
Shohei Okada
 
Laravel × レイヤードアーキテクチャをやってみている話
Laravel × レイヤードアーキテクチャをやってみている話Laravel × レイヤードアーキテクチャをやってみている話
Laravel × レイヤードアーキテクチャをやってみている話
Shohei Okada
 
Laravel 5.6 デフォルトの例外ハンドリング処理をまとめてみた
Laravel 5.6 デフォルトの例外ハンドリング処理をまとめてみたLaravel 5.6 デフォルトの例外ハンドリング処理をまとめてみた
Laravel 5.6 デフォルトの例外ハンドリング処理をまとめてみた
Shohei Okada
 
チームで「きちんと」Laravel を使っていくための取り組み
チームで「きちんと」Laravel を使っていくための取り組みチームで「きちんと」Laravel を使っていくための取り組み
チームで「きちんと」Laravel を使っていくための取り組み
Shohei Okada
 
プロダクトに 1 から Vue.js を導入した話
プロダクトに 1 から Vue.js を導入した話プロダクトに 1 から Vue.js を導入した話
プロダクトに 1 から Vue.js を導入した話
Shohei Okada
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!
Shohei Okada
 
Laravel Mix とは何なのか? - Laravel/Vue 勉強会 #1
Laravel Mix とは何なのか? - Laravel/Vue 勉強会 #1Laravel Mix とは何なのか? - Laravel/Vue 勉強会 #1
Laravel Mix とは何なのか? - Laravel/Vue 勉強会 #1
Shohei Okada
 

More from Shohei Okada (20)

「登壇しているひとは偉い」という話
「登壇しているひとは偉い」という話「登壇しているひとは偉い」という話
「登壇しているひとは偉い」という話
 
PHP-FPM の子プロセス制御方法と設定をおさらいしよう
PHP-FPM の子プロセス制御方法と設定をおさらいしようPHP-FPM の子プロセス制御方法と設定をおさらいしよう
PHP-FPM の子プロセス制御方法と設定をおさらいしよう
 
PHP 8.0 の新記法を試してみよう!
PHP 8.0 の新記法を試してみよう!PHP 8.0 の新記法を試してみよう!
PHP 8.0 の新記法を試してみよう!
 
自分たちのコードを Composer パッケージに分割して開発する
自分たちのコードを Composer パッケージに分割して開発する自分たちのコードを Composer パッケージに分割して開発する
自分たちのコードを Composer パッケージに分割して開発する
 
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyoエラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
 
スペシャリストとして組織をつくる、というキャリア
スペシャリストとして組織をつくる、というキャリアスペシャリストとして組織をつくる、というキャリア
スペシャリストとして組織をつくる、というキャリア
 
PHP でも活用できる Makefile
PHP でも活用できる MakefilePHP でも活用できる Makefile
PHP でも活用できる Makefile
 
はじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよ
はじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよはじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよ
はじめての Go 言語のプロジェクトを AWS Lambda + API Gateway でやったのでパッケージ構成を晒すよ
 
Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered archi...
Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered archi...Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered archi...
Laravel × レイヤードアーキテクチャを実践して得られた知見と反省 / Practice of Laravel with layered archi...
 
働き方が大きく変わった 入社3年目のときのとあるエピソード
働き方が大きく変わった 入社3年目のときのとあるエピソード働き方が大きく変わった 入社3年目のときのとあるエピソード
働き方が大きく変わった 入社3年目のときのとあるエピソード
 
Laravel で API バージョニングを実装するなら
Laravel で API バージョニングを実装するならLaravel で API バージョニングを実装するなら
Laravel で API バージョニングを実装するなら
 
Laravel における Blade 拡張のツラミ
Laravel における Blade 拡張のツラミLaravel における Blade 拡張のツラミ
Laravel における Blade 拡張のツラミ
 
Laravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのかLaravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのか
 
2017 年度を振り返って ~アウトプット編~
2017 年度を振り返って ~アウトプット編~2017 年度を振り返って ~アウトプット編~
2017 年度を振り返って ~アウトプット編~
 
Laravel × レイヤードアーキテクチャをやってみている話
Laravel × レイヤードアーキテクチャをやってみている話Laravel × レイヤードアーキテクチャをやってみている話
Laravel × レイヤードアーキテクチャをやってみている話
 
Laravel 5.6 デフォルトの例外ハンドリング処理をまとめてみた
Laravel 5.6 デフォルトの例外ハンドリング処理をまとめてみたLaravel 5.6 デフォルトの例外ハンドリング処理をまとめてみた
Laravel 5.6 デフォルトの例外ハンドリング処理をまとめてみた
 
チームで「きちんと」Laravel を使っていくための取り組み
チームで「きちんと」Laravel を使っていくための取り組みチームで「きちんと」Laravel を使っていくための取り組み
チームで「きちんと」Laravel を使っていくための取り組み
 
プロダクトに 1 から Vue.js を導入した話
プロダクトに 1 から Vue.js を導入した話プロダクトに 1 から Vue.js を導入した話
プロダクトに 1 から Vue.js を導入した話
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!
 
Laravel Mix とは何なのか? - Laravel/Vue 勉強会 #1
Laravel Mix とは何なのか? - Laravel/Vue 勉強会 #1Laravel Mix とは何なのか? - Laravel/Vue 勉強会 #1
Laravel Mix とは何なのか? - Laravel/Vue 勉強会 #1
 

Recently uploaded

AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
Google
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
Drona Infotech
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Crescat
 
APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)
Boni García
 
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
Łukasz Chruściel
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOMLORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
lorraineandreiamcidl
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Łukasz Chruściel
 
Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
TheSMSPoint
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
Donna Lenk
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
Aftab Hussain
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Neo4j
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
Ayan Halder
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
Philip Schwarz
 
Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
Deuglo Infosystem Pvt Ltd
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
Neo4j
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
Octavian Nadolu
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
Aftab Hussain
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
Paco van Beckhoven
 

Recently uploaded (20)

AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
 
APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)
 
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOMLORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
 
Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
 
Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
 

Laravel でやってみるクリーンアーキテクチャ #phpconfuk

  • 1. Laravel PHP Conference Fukuoka 2019 @okashoi WILLGATE, Inc.
  • 3. • 2 • 3 • 5 • 10 • 3 • 2 3
  • 4. • 2 • 3 • 5 • 10 • 3 • 2 4
  • 7. • 2 • 3 • 5 • 10 • 3 • 2 7
  • 9. ”The Clean Architecture - The Clean Code Blog”, https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html 9
  • 13. • 2 • 3 • 5 • 10 • 3 • 2 13
  • 14. 14
  • 15. 15
  • 17. 17
  • 18. 18
  • 20. 20
  • 22. 22
  • 23. package foo; import bar; class Foo { bar.Bar x; function doFoo() { x.process(); } } 23 package bar; class Bar { function process() { // do something... } }
  • 24. package foo; import bar; class Foo { bar.Bar x; function doFoo() { x.process(); } } 24 package bar; class Bar { function process() { // do something... } } foo bar = foo → bar
  • 25. package foo; import bar; class Foo { bar.Bar x; function doFoo() { x.process(); } } 25 package bar; class Bar { function process() { // do something... } } foo bar = foo → bar
  • 26. package foo; import bar; class Foo { bar.Bar x; function doFoo() { x.process(); } } 26 package bar; class Bar { function process() { // do something... } } foo → bar foo → bar
  • 27. package foo; class Foo { Buz x; function doFoo() { x.process(); } } interface Buz { function process(); } 27 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } }
  • 28. package foo; class Foo { Buz x; function doFoo() { x.process(); } } interface Buz { function process(); } 28 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } }
  • 29. package foo; class Foo { Buz x; function doFoo() { x.process(); } } interface Buz { function process(); } 29 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } } foo bar = foo → bar
  • 30. package foo; class Foo { Buz x; function doFoo() { x.process(); } } interface Buz { function process(); } 30 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } } bar foo = foo ← bar
  • 31. package foo; class Foo { Buz x; function doFoo() { x.process(); } } interface Buz { function process(); } 31 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } } foo → bar foo ← bar
  • 34. 34 UI
  • 35. • 2 • 3 • 5 • 10 • 3 • 2 35
  • 38. 38
  • 41. • • • POPO Plain Old PHP Object ➡ 41
  • 42. • PHP 42 <?php namespace MyAppComponentsTasksEntities; use DatetimeImmutable; /** * Class Inbox * @package MyAppComponentsTasksEntities */ final class Inbox extends Task { /** * @var EstimatedTime|null */ private $estimatedTime;
  • 43. • • 43 /** * @test * @expectedException MyAppComponentsTasksEntitiesEstimatedTimeNotSet */ public function 「Inbox」に対して「見積もり時間」が未設定のまま「着手日」を設定できないこと() { $id = Mockery::mock(Id::class); $name = new Name('test'); $inbox = new Inbox($id, $name); $startDate = new StartDate(new DateTimeImmutable('tomorrow')); $inbox->convertToScheduled($startDate); }
  • 44. 44
  • 45. 45
  • 47. InputBoundary / OutputBoundary • 
 47 <?php namespace MyAppComponentsTasksUseCasesCreateInbox; /** * Interface InputBoundary * @package MyAppComponentsTasksUseCasesCreateInbox */ interface InputBoundary { /** * @param InputData $input */ public function __invoke(InputData $input): void; }
  • 48. InputBoundary / OutputBoundary • 
 48 <?php namespace MyAppComponentsTasksUseCasesCreateInbox; /** * Interface NormalOutputBoundary * @package MyAppComponentsTasksUseCasesCreateInbox */ interface NormalOutputBoundary { /** * @param NormalOutputData $output */ public function __invoke(NormalOutputData $output): void; }
  • 49. Interactor 49 <?php namespace MyAppComponentsTasksUseCasesCreateInbox; use MyAppComponentsTasksEntities{Inbox, Task, Name, Note}; use MyAppComponentsTasksUseCases{IdProvider, TaskRepository}; /** * Class Interactor * @package MyAppComponentsTasksUseCasesCreateInbox */ final class Interactor implements InputBoundary { /** * @var IdProvider */ private $idProvider; /** * @var TaskRepository */ private $taskRepository; /** * @var NormalOutputBoundary */ private $normalOutputBoundary; /** * Interactor constructor. * @param IdProvider $idProvider * @param TaskRepository $taskRepository * @param NormalOutputBoundary $normalOutputBoundary */ public function __construct(IdProvider $idProvider, TaskRepository $t { $this->idProvider = $idProvider; $this->taskRepository = $taskRepository; $this->normalOutputBoundary = $normalOutputBoundary; } /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); } /** * @param InputData $input * @return Task
  • 50. Interactor 50 <?php namespace MyAppComponentsTasksUseCasesCreateInbox; use MyAppComponentsTasksEntities{Inbox, Task, Name, Note}; use MyAppComponentsTasksUseCases{IdProvider, TaskRepository}; /** * Class Interactor * @package MyAppComponentsTasksUseCasesCreateInbox */ final class Interactor implements InputBoundary { /** * @var IdProvider */ private $idProvider; /** * @var TaskRepository */ private $taskRepository; /** * @var NormalOutputBoundary */ private $normalOutputBoundary; /** * Interactor constructor. * @param IdProvider $idProvider * @param TaskRepository $taskRepository * @param NormalOutputBoundary $normalOutputBoundary */ public function __construct(IdProvider $idProvider, TaskRepository $t { $this->idProvider = $idProvider; $this->taskRepository = $taskRepository; $this->normalOutputBoundary = $normalOutputBoundary; } /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); } /** * @param InputData $input * @return Task InputBoundary
  • 51. Interactor 51 <?php namespace MyAppComponentsTasksUseCasesCreateInbox; use MyAppComponentsTasksEntities{Inbox, Task, Name, Note}; use MyAppComponentsTasksUseCases{IdProvider, TaskRepository}; /** * Class Interactor * @package MyAppComponentsTasksUseCasesCreateInbox */ final class Interactor implements InputBoundary { /** * @var IdProvider */ private $idProvider; /** * @var TaskRepository */ private $taskRepository; /** * @var NormalOutputBoundary */ private $normalOutputBoundary; /** * Interactor constructor. * @param IdProvider $idProvider * @param TaskRepository $taskRepository * @param NormalOutputBoundary $normalOutputBoundary */ public function __construct(IdProvider $idProvider, TaskRepository $t { $this->idProvider = $idProvider; $this->taskRepository = $taskRepository; $this->normalOutputBoundary = $normalOutputBoundary; } /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); } /** * @param InputData $input * @return Task DI ※ 

  • 52. Interactor 52 <?php namespace MyAppComponentsTasksUseCasesCreateInbox; use MyAppComponentsTasksEntities{Inbox, Task, Name, Note}; use MyAppComponentsTasksUseCases{IdProvider, TaskRepository}; /** * Class Interactor * @package MyAppComponentsTasksUseCasesCreateInbox */ final class Interactor implements InputBoundary { /** * @var IdProvider */ private $idProvider; /** * @var TaskRepository */ private $taskRepository; /** * @var NormalOutputBoundary */ private $normalOutputBoundary; /** * Interactor constructor. * @param IdProvider $idProvider * @param TaskRepository $taskRepository * @param NormalOutputBoundary $normalOutputBoundary */ public function __construct(IdProvider $idProvider, TaskRepository $t { $this->idProvider = $idProvider; $this->taskRepository = $taskRepository; $this->normalOutputBoundary = $normalOutputBoundary; } /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); } /** * @param InputData $input * @return Task 

  • 53. Interactor::__invoke() 
 53 /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); }
  • 54. Interactor::__invoke() 
 54 /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); }
  • 55. Interactor::__invoke() 
 55 /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); }
  • 56. Interactor::__invoke() OutputBoundary 
 56 /** * @param InputData $input */ public function __invoke(InputData $input): void { $inbox = $this->produceEntity($input); $this->taskRepository->save($inbox); $normalOutput = $this->produceNormalOutputData($inbox); ($this->normalOutputBoundary)($normalOutput); }
  • 57. 57
  • 60. Web UI • • Controller 
 void • 
 60
  • 61. Controller 61 <?php namespace MyAppWebControllers; use IlluminateHttpRequest; use MyAppComponentsTasksUseCasesCreateInboxInputData; use MyAppComponentsTasksUseCasesCreateInboxInputBoundary; /** * Class CreateInbox * @package MyAppWebControllers */ final class CreateInbox extends Controller { /** * @param Request $request * @param InputBoundary $interactor */ public function __invoke(Request $request, InputBoundary $interactor) { $validated = $this->validate($request, [ 'name' => 'required|string|max:255', 'note' => 'string|nullable', ]); $input = new InputData($validated['name'], $validated['note'] ?? ''); $interactor($input); } }
  • 62. Controller 62 <?php namespace MyAppWebControllers; use IlluminateHttpRequest; use MyAppComponentsTasksUseCasesCreateInboxInputData; use MyAppComponentsTasksUseCasesCreateInboxInputBoundary; /** * Class CreateInbox * @package MyAppWebControllers */ final class CreateInbox extends Controller { /** * @param Request $request * @param InputBoundary $interactor */ public function __invoke(Request $request, InputBoundary $interactor) { $validated = $this->validate($request, [ 'name' => 'required|string|max:255', 'note' => 'string|nullable', ]); $input = new InputData($validated['name'], $validated['note'] ?? ''); $interactor($input); } } Laravel HttpControllers
  • 63. Controller 63 <?php namespace MyAppWebControllers; use IlluminateHttpRequest; use MyAppComponentsTasksUseCasesCreateInboxInputData; use MyAppComponentsTasksUseCasesCreateInboxInputBoundary; /** * Class CreateInbox * @package MyAppWebControllers */ final class CreateInbox extends Controller { /** * @param Request $request * @param InputBoundary $interactor */ public function __invoke(Request $request, InputBoundary $interactor) { $validated = $this->validate($request, [ 'name' => 'required|string|max:255', 'note' => 'string|nullable', ]); $input = new InputData($validated['name'], $validated['note'] ?? ''); $interactor($input); } } HTTP
  • 64. Controller 64 <?php namespace MyAppWebControllers; use IlluminateHttpRequest; use MyAppComponentsTasksUseCasesCreateInboxInputData; use MyAppComponentsTasksUseCasesCreateInboxInputBoundary; /** * Class CreateInbox * @package MyAppWebControllers */ final class CreateInbox extends Controller { /** * @param Request $request * @param InputBoundary $interactor */ public function __invoke(Request $request, InputBoundary $interactor) { $validated = $this->validate($request, [ 'name' => 'required|string|max:255', 'note' => 'string|nullable', ]); $input = new InputData($validated['name'], $validated['note'] ?? ''); $interactor($input); } } InputBoundary Interactor
  • 65. Controller 65 <?php namespace MyAppWebControllers; use IlluminateHttpRequest; use MyAppComponentsTasksUseCasesCreateInboxInputData; use MyAppComponentsTasksUseCasesCreateInboxInputBoundary; /** * Class CreateInbox * @package MyAppWebControllers */ final class CreateInbox extends Controller { /** * @param Request $request * @param InputBoundary $interactor */ public function __invoke(Request $request, InputBoundary $interactor) { $validated = $this->validate($request, [ 'name' => 'required|string|max:255', 'note' => 'string|nullable', ]); $input = new InputData($validated['name'], $validated['note'] ?? ''); $interactor($input); } }
  • 66. Presenter • 66 <?php namespace MyAppWebPresentersCreateInbox; use IlluminateViewFactory; use MyAppWebPresentersPresenter as BasePresenter; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputData; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary; /** * Class CreateInboxPresenter * @package MyAppWebPresenters */ final class Presenter extends BasePresenter implements NormalOutputBoundary { // 中略 /** * @param NormalOutputData $output */ public function __invoke(NormalOutputData $output): void { $viewModel = new ViewModel( $output->taskId(), $output->taskName(), $output->taskNote(), ); $this->respond($this->view->make('web::tasks.create', compact(['viewModel']))); } }
  • 67. Presenter • 67 <?php namespace MyAppWebPresentersCreateInbox; use IlluminateViewFactory; use MyAppWebPresentersPresenter as BasePresenter; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputData; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary; /** * Class CreateInboxPresenter * @package MyAppWebPresenters */ final class Presenter extends BasePresenter implements NormalOutputBoundary { // 中略 /** * @param NormalOutputData $output */ public function __invoke(NormalOutputData $output): void { $viewModel = new ViewModel( $output->taskId(), $output->taskName(), $output->taskNote(), ); $this->respond($this->view->make('web::tasks.create', compact(['viewModel']))); } } Interactor ViewModel
  • 68. Presenter • 68 <?php namespace MyAppWebPresentersCreateInbox; use IlluminateViewFactory; use MyAppWebPresentersPresenter as BasePresenter; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputData; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary; /** * Class CreateInboxPresenter * @package MyAppWebPresenters */ final class Presenter extends BasePresenter implements NormalOutputBoundary { // 中略 /** * @param NormalOutputData $output */ public function __invoke(NormalOutputData $output): void { $viewModel = new ViewModel( $output->taskId(), $output->taskName(), $output->taskNote(), ); $this->respond($this->view->make('web::tasks.create', compact(['viewModel']))); } } View ※ Controller 
 void ……🙇
  • 70. 70 <?php namespace AppProviders; use IlluminateSupportServiceProvider; use MyAppComponentsTasksUseCasesCreateInboxInputBoundary; use MyAppComponentsTasksUseCasesCreateInboxInteractor; use MyAppComponentsTasksUseCasesCreateInboxNormalOutputBoundary; use MyAppComponentsTasksUseCasesIdProvider; use MyAppComponentsTasksUseCasesTaskRepository as TaskRepositoryInterface; use MyAppDatabaseRepositoriesAutoIncrementTaskIdProvider; use MyAppDatabaseRepositoriesTaskRepository; use MyAppWebPresentersCreateInboxPresenter; 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); $this->app->bind(InputBoundary::class, Interactor::class); $this->app->bind(NormalOutputBoundary::class, Presenter::class); } /** * Bootstrap any application services. * * @return void */ public function boot() { // } }
  • 71. Laravel • Laravel • DI ServiceContainer • 
 ServiceProvider • 
 71
  • 72. @Laravel JP Conference 2019 https://speakerdeck.com/mikakane/laravel-package- development 72
  • 73. 73
  • 78. • 2 • 3 • 5 • 10 • 3 • 2 78
  • 79. 79 UI
  • 80. package foo; class Foo { Buz x; function doFoo() { x.process(); } } interface Buz { function process(); } 80 package bar; import foo; class Bar implements foo.Buz { function process() { // do something... } }
  • 82. • 2 • 3 • 5 • 10 • 3 • 2 82
  • 86. • Laravel JP Conference 2020 86https://conference2020.laravel.jp/
  • 87. Ask the Speaker 
 😂 87