SlideShare a Scribd company logo
1 of 87
Download to read offline
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

ドメイン駆動設計という仕事の流儀
ドメイン駆動設計という仕事の流儀ドメイン駆動設計という仕事の流儀
ドメイン駆動設計という仕事の流儀増田 亨
 
PostgreSQLの行レベルセキュリティと SpringAOPでマルチテナントの ユーザー間情報漏洩を防止する (JJUG CCC 2021 Spring)
PostgreSQLの行レベルセキュリティと SpringAOPでマルチテナントの ユーザー間情報漏洩を防止する (JJUG CCC 2021 Spring)PostgreSQLの行レベルセキュリティと SpringAOPでマルチテナントの ユーザー間情報漏洩を防止する (JJUG CCC 2021 Spring)
PostgreSQLの行レベルセキュリティと SpringAOPでマルチテナントの ユーザー間情報漏洩を防止する (JJUG CCC 2021 Spring)Koichiro Matsuoka
 
ドメイン駆動設計 本格入門
ドメイン駆動設計 本格入門ドメイン駆動設計 本格入門
ドメイン駆動設計 本格入門増田 亨
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Taku Miyakawa
 
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう増田 亨
 
ドメイン駆動設計(DDD)の実践Part2
ドメイン駆動設計(DDD)の実践Part2ドメイン駆動設計(DDD)の実践Part2
ドメイン駆動設計(DDD)の実践Part2増田 亨
 
Where狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーWhere狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーyoku0825
 
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Springドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring増田 亨
 
AWS Lambdaのテストで役立つ各種ツール
AWS Lambdaのテストで役立つ各種ツールAWS Lambdaのテストで役立つ各種ツール
AWS Lambdaのテストで役立つ各種ツールMasaki Suzuki
 
Using Azure Compute with VMSS, Kubernetes, and Service Fabric
Using Azure Compute with VMSS, Kubernetes, and Service FabricUsing Azure Compute with VMSS, Kubernetes, and Service Fabric
Using Azure Compute with VMSS, Kubernetes, and Service FabricTakeshi Fukuhara
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?Moriharu Ohzu
 
君はyarn.lockをコミットしているか?
君はyarn.lockをコミットしているか?君はyarn.lockをコミットしているか?
君はyarn.lockをコミットしているか?Teppei Sato
 
20160215 04 java ee7徹底入門 jbatch
20160215 04 java ee7徹底入門 jbatch20160215 04 java ee7徹底入門 jbatch
20160215 04 java ee7徹底入門 jbatchJun Inose
 
「ドメイン駆動設計」の複雑さに立ち向かう
「ドメイン駆動設計」の複雑さに立ち向かう「ドメイン駆動設計」の複雑さに立ち向かう
「ドメイン駆動設計」の複雑さに立ち向かう増田 亨
 
5分でわかるクリーンアーキテクチャ
5分でわかるクリーンアーキテクチャ5分でわかるクリーンアーキテクチャ
5分でわかるクリーンアーキテクチャKenji Tanaka
 
【Spring fest 2019】徹底解剖Spring MVCアーキテクチャー
【Spring fest 2019】徹底解剖Spring MVCアーキテクチャー【Spring fest 2019】徹底解剖Spring MVCアーキテクチャー
【Spring fest 2019】徹底解剖Spring MVCアーキテクチャーssuser070fa9
 
(Tech DeepDive #1) Java Flight Recorder を活用した問題解決
(Tech DeepDive #1) Java Flight Recorder を活用した問題解決(Tech DeepDive #1) Java Flight Recorder を活用した問題解決
(Tech DeepDive #1) Java Flight Recorder を活用した問題解決オラクルエンジニア通信
 
商流物流金流.pdf
商流物流金流.pdf商流物流金流.pdf
商流物流金流.pdfZenji Kanzaki
 

What's hot (20)

ドメイン駆動設計という仕事の流儀
ドメイン駆動設計という仕事の流儀ドメイン駆動設計という仕事の流儀
ドメイン駆動設計という仕事の流儀
 
SpringBootTest入門
SpringBootTest入門SpringBootTest入門
SpringBootTest入門
 
PostgreSQLの行レベルセキュリティと SpringAOPでマルチテナントの ユーザー間情報漏洩を防止する (JJUG CCC 2021 Spring)
PostgreSQLの行レベルセキュリティと SpringAOPでマルチテナントの ユーザー間情報漏洩を防止する (JJUG CCC 2021 Spring)PostgreSQLの行レベルセキュリティと SpringAOPでマルチテナントの ユーザー間情報漏洩を防止する (JJUG CCC 2021 Spring)
PostgreSQLの行レベルセキュリティと SpringAOPでマルチテナントの ユーザー間情報漏洩を防止する (JJUG CCC 2021 Spring)
 
ドメイン駆動設計 本格入門
ドメイン駆動設計 本格入門ドメイン駆動設計 本格入門
ドメイン駆動設計 本格入門
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
 
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう
 
ドメイン駆動設計(DDD)の実践Part2
ドメイン駆動設計(DDD)の実践Part2ドメイン駆動設計(DDD)の実践Part2
ドメイン駆動設計(DDD)の実践Part2
 
Where狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーWhere狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキー
 
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Springドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
 
AWS Lambdaのテストで役立つ各種ツール
AWS Lambdaのテストで役立つ各種ツールAWS Lambdaのテストで役立つ各種ツール
AWS Lambdaのテストで役立つ各種ツール
 
Using Azure Compute with VMSS, Kubernetes, and Service Fabric
Using Azure Compute with VMSS, Kubernetes, and Service FabricUsing Azure Compute with VMSS, Kubernetes, and Service Fabric
Using Azure Compute with VMSS, Kubernetes, and Service Fabric
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
 
君はyarn.lockをコミットしているか?
君はyarn.lockをコミットしているか?君はyarn.lockをコミットしているか?
君はyarn.lockをコミットしているか?
 
20160215 04 java ee7徹底入門 jbatch
20160215 04 java ee7徹底入門 jbatch20160215 04 java ee7徹底入門 jbatch
20160215 04 java ee7徹底入門 jbatch
 
「ドメイン駆動設計」の複雑さに立ち向かう
「ドメイン駆動設計」の複雑さに立ち向かう「ドメイン駆動設計」の複雑さに立ち向かう
「ドメイン駆動設計」の複雑さに立ち向かう
 
5分でわかるクリーンアーキテクチャ
5分でわかるクリーンアーキテクチャ5分でわかるクリーンアーキテクチャ
5分でわかるクリーンアーキテクチャ
 
【Spring fest 2019】徹底解剖Spring MVCアーキテクチャー
【Spring fest 2019】徹底解剖Spring MVCアーキテクチャー【Spring fest 2019】徹底解剖Spring MVCアーキテクチャー
【Spring fest 2019】徹底解剖Spring MVCアーキテクチャー
 
(Tech DeepDive #1) Java Flight Recorder を活用した問題解決
(Tech DeepDive #1) Java Flight Recorder を活用した問題解決(Tech DeepDive #1) Java Flight Recorder を活用した問題解決
(Tech DeepDive #1) Java Flight Recorder を活用した問題解決
 
Vue.js で XSS
Vue.js で XSSVue.js で XSS
Vue.js で XSS
 
商流物流金流.pdf
商流物流金流.pdf商流物流金流.pdf
商流物流金流.pdf
 

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

クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumai
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumaiクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumai
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #shuuumaiShohei Okada
 
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondo
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondoクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondo
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpcondoShohei Okada
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy CodeRowan Merewood
 
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawaクリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawa
クリーンアーキテクチャの考え方にもとづく Laravel との付き合い方 #phpconokinawaShohei Okada
 
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
 
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 PHPStormMichelangelo 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 ImplementationAbdul 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 frameworkChristian 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 gtk2Elizabeth 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 - phpbelfastMichelangelo van Dam
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applicationschartjes
 
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 tek12Michelangelo 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 Symfony2Hugo 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
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyoShohei Okada
 
スペシャリストとして組織をつくる、というキャリア
スペシャリストとして組織をつくる、というキャリアスペシャリストとして組織をつくる、というキャリア
スペシャリストとして組織をつくる、というキャリアShohei Okada
 
PHP でも活用できる Makefile
PHP でも活用できる MakefilePHP でも活用できる Makefile
PHP でも活用できる MakefileShohei 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 勉強会 #1Shohei 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

Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendArshad QA
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfCionsystems
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 

Recently uploaded (20)

Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and Backend
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdf
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 

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