A simple architecture is perfect for a simple application. But, as the application grows in its complexity, the architecture must become more complex in order to prevent it from becoming unmaintainable.
In this talk we discuss some ideas for simplifying complex code bases.
We also discuss the important distinctions between presentation, service, and domain layers and strategies for separating high-level business policy from implementation.
Some Domain-Driven Design topics are discussed, but this is not a talk about DDD. DDD is not about design patterns, but rather is about business analysis, communication, and much more.
2. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
HI, I’M SHAWN
3. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
LARAVEL.IO ORIGIN
4. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
Laravel.IO Now
LARAVEL.IO FORUM
from Nick Spelt and myself
LIONA (LioBot)
from Sam Evaskitas and Matthew Machuga
LARAVEL WEEKLY NEWSLETTER
by Dries Vints
PODCAST
http://bit.ly/laravelio-podcast
Assets available for contribution at: https://github.com/LaravelIO
5. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
AKA ENGINEERING
MANAGING COMPLEXITY
6. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
FUNCTIONAL REQUIREMENTS
7. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
USE CASES
8. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
ENTITIES
Many objects are not fundamentally defined by their attributes,
but rather by a thread of continuity and identity.
- Eric Evans
“
9. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
PeoplePERSON
10. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
Jane Doe
People
Jane Doe
PERSON
11. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
Jane Doe
People
Jane DoeJane Doe
PERSON
Jane Doe
12. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
Jane Doe
PERSON
Age: 27
Jane Doe
Age: 27
13. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
Jane Doe
PERSON
Age: 27
From: NYC
Jane Doe
Age: 27
From: NYC
14. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
THE ACTIVERECORD PATTERN
15. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
ID: 1 ID: 2
Jane Doe
PERSON
Age: 27
From: NYC
Jane Doe
Age: 27
From: NYC
People Table
ID
1
2
Age
27
27
From
NYC
NYC
Name
Jane Doe
Jane Doe
16. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
ENTITIES AND ACTIVERECORD
17. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
THIS IS NOT DDD
18. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
LAYERED ARCHITECTURE
19. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
A COMMON APPLICATION
PRESENTATION LAYER
Controllers
Artisan Commands
Queue Listeners
20. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
PRESENTATION LAYER
Controllers
Artisan Commands
Queue Listeners
DOMAIN
Entities
Repository Interfaces
A COMMON APPLICATION
21. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
PRESENTATION LAYER
Controllers
Artisan Commands
Queue Listeners
SERVICE LAYER
Sending Email
Queueing up Jobs
Repository Implementations
DOMAIN
Entities
Repository Interfaces
A COMMON APPLICATION
22. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
PRESENTATION LAYER
Controllers
Artisan Commands
Queue Listeners
SERVICE LAYER
Sending Email
Queueing up Jobs
Repository Implementations
Commands / Command Bus
DOMAIN
Entities
Repository Interfaces
A COMMON APPLICATION
23. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
A COMMAND ORIENTED INTERFACE
24. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MEAT OF THE APPLICATION
WHAT IS A COMMAND
25. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
Controller
Artisan Command
Queue Worker
Whatever
MEAT OF THE APPLICATION
WHAT IS A COMMAND
26. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
WHAT IS A COMMAND
MEAT OF THE APPLICATION
REGISTER MEMBER
COMMAND
27. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
WHAT IS A COMMAND
MEAT OF THE APPLICATION
REGISTER MEMBER
COMMAND
28. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
WHAT IS A COMMAND
REGISTER MEMBER
COMMAND
MEAT OF THE APPLICATION
29. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
Some Advantages
- No business policy in your controllers
- Your code shows intent
- A single dedicated flow per use case
- A single point of entry per use case
- Easy to see which use cases are implemented
30. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
COMMAND ANATOMY
31. class RegisterMemberCommand
{
public $displayName;
public $email;
public $password;
public function __construct($displayName, $email, $password)
{
$this->displayName = $displayName;
$this->email = $email;
$this->password = $password;
}
}
32. class RegisterMemberCommand
{
public $displayName;
public $email;
public $password;
public function __construct($displayName, $email, $password)
{
$this->displayName = $displayName;
$this->email = $email;
$this->password = $password;
}
}
33. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
WHAT IS HAPPENING INSIDE?
MEAT OF THE APPLICATION
REGISTER MEMBER
COMMAND
34. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
THE FINAL DESTINATION
MEAT OF THE APPLICATION
REGISTER MEMBER
HANDLER
REGISTER MEMBER
COMMAND
35. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
THE FINAL DESTINATION
MEAT OF THE APPLICATION
?REGISTER MEMBER
COMMAND
REGISTER MEMBER
HANDLER
36. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
THE TRANSPORT MECHANISM
MEAT OF THE APPLICATION
COMMAND BUSREGISTER MEMBER
COMMAND
REGISTER MEMBER
HANDLER
37. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
COMMAND BUS IMPLEMENTATION
38. class ExecutionCommandBus implements CommandBus
{
private $container;
private $mapper;
public function __construct(Container $container,Mapper $mapper)
{
$this->container = $container;
$this->mapper = $mapper;
}
public function execute($command)
{
$this->getHandler($command)->handle($command);
}
private function getHandler($command)
{
$class = $this->mapper->getHandlerClassFor($command);
return $this->container->make($class);
}
}
39. class ExecutionCommandBus implements CommandBus
{
private $container;
private $mapper;
public function __construct(Container $container,Mapper $mapper)
{
$this->container = $container;
$this->mapper = $mapper;
}
public function execute($command)
{
$this->getHandler($command)->handle($command);
}
private function getHandler($command)
{
$class = $this->mapper->getHandlerClassFor($command);
return $this->container->make($class);
}
}
40. class ExecutionCommandBus implements CommandBus
{
private $container;
private $mapper;
public function __construct(Container $container,Mapper $mapper)
{
$this->container = $container;
$this->mapper = $mapper;
}
public function execute($command)
{
$this->getHandler($command)->handle($command);
}
private function getHandler($command)
{
$class = $this->mapper->getHandlerClassFor($command);
return $this->container->make($class);
}
}
41. class ExecutionCommandBus implements CommandBus
{
private $container;
private $mapper;
public function __construct(Container $container,Mapper $mapper)
{
$this->container = $container;
$this->mapper = $mapper;
}
public function execute($command)
{
$this->getHandler($command)->handle($command);
}
private function getHandler($command)
{
$class = $this->mapper->getHandlerClassFor($command);
return $this->container->make($class);
}
}
42. class ExecutionCommandBus implements CommandBus
{
private $container;
private $mapper;
public function __construct(Container $container,Mapper $mapper)
{
$this->container = $container;
$this->mapper = $mapper;
}
public function execute($command)
{
$this->getHandler($command)->handle($command);
}
private function getHandler($command)
{
$class = $this->mapper->getHandlerClassFor($command);
return $this->container->make($class);
}
}
43. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
HOW DOES THE MAPPER KNOW?
44. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
ONE HANDLER PER COMMAND
45. class RegisterMemberHandler implements Handler
{
private $memberRepository;
public function __construct(MemberRepository $memberRepository)
{
$this->memberRepository = $memberRepository;
}
public function handle($command)
{
$member = Member::register(
$command->displayName,
$command->email,
$command->password);
$this->memberRepository->save($member);
}
}
46. class RegisterMemberHandler implements Handler
{
private $memberRepository;
public function __construct(MemberRepository $memberRepository)
{
$this->memberRepository = $memberRepository;
}
public function handle($command)
{
$member = Member::register(
$command->displayName,
$command->email,
$command->password);
$this->memberRepository->save($member);
}
}
47. class RegisterMemberHandler implements Handler
{
private $memberRepository;
public function __construct(MemberRepository $memberRepository)
{
$this->memberRepository = $memberRepository;
}
public function handle($command)
{
$member = Member::register(
$command->displayName,
$command->email,
$command->password);
$this->memberRepository->save($member);
}
}
48. class RegisterMemberHandler implements Handler
{
private $memberRepository;
public function __construct(MemberRepository $memberRepository)
{
$this->memberRepository = $memberRepository;
}
public function handle($command)
{
$member = Member::register(
$command->displayName,
$command->email,
$command->password);
$this->memberRepository->save($member);
}
}
49. class Member extends Eloquent
{
public static function register($displayName, $email, $password)
{
$member = new static([
'display_name' => $displayName,
'email' => $email,
'password' => $password,
]);
return $member;
}
}
50. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
DOMAIN IMPLICATION
51. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
FLOW REVIEW
PRESENTATION
LAYER
SERVICE LAYER DOMAIN
52. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
FLOW REVIEW
PRESENTATION
LAYER
SERVICE LAYER DOMAIN
COMMAND
53. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
FLOW REVIEW
PRESENTATION
LAYER
SERVICE LAYER DOMAIN
COMMAND
COMMAND
BUS
54. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
FLOW REVIEW
PRESENTATION
LAYER
SERVICE LAYER DOMAIN
COMMAND
COMMAND
BUS
COMMAND
HANDLER
55. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
FLOW REVIEW
PRESENTATION
LAYER
SERVICE LAYER DOMAIN
COMMAND
COMMAND
BUS
COMMAND
HANDLER
ENTITIES
REPOSITORIES
56. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
HANDLING COMPLEX SEQUENCES
57. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MEMBER REGISTERS
SEND WELCOME EMAIL
SUBSCRIBE TO MAILCHIMP
QUEUE UP 7 DAY EMAIL
SIMPLE SEQUENCE
58. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MEMBER REPLIES TO THREAD
NOTIFY THREAD SUBSCRIBERS
w
NOTIFY TAGGED USERS
COMPLEX SEQUENCE
59. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MEMBER REPLIES TO THREAD
NOTIFY THREAD SUBSCRIBERS
w
NOTIFY TAGGED USERS
COMPLEX SEQUENCE
SEND NOTIFICATION
EMAIL
ADD NOTIFICATION DIGEST
QUEUE ENTRY
SEND NO NOTIFICATION
60. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
DOMAIN EVENTS
61. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
TYPICAL PUB-SUB PATTERN
DISPATCH EVENTRAISE EVENT TRIGGER LISTENERS
62. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
PRESENTATION LAYER
Controllers
Artisan Commands
Queue Listeners
SERVICE LAYER
Sending Email
Queueing up Jobs
Repository Implementations
Commands / Command Bus
DOMAIN
Entities
Repository Interfaces
A COMMON APPLICATION
63. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
PRESENTATION LAYER
Controllers
Artisan Commands
Queue Listeners
SERVICE LAYER
Sending Email
Queueing up Jobs
Repository Implementations
Commands / Command Bus
Event Dispatcher
DOMAIN
Entities
Repository Interfaces
Domain Events
A COMMON APPLICATION
64. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MEMBER REGISTERS
SEND WELCOME EMAIL
SUBSCRIBE TO MAILCHIMP
QUEUE UP 7 DAY EMAIL
DOMAIN EVENTS
65. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MEMBER REGISTERS
SEND WELCOME EMAIL
SUBSCRIBE TO MAILCHIMP
QUEUE UP 7 DAY EMAIL
EVENT / LISTENER BREAKDOWN
66. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MemberRegistered
SEND WELCOME EMAIL
SUBSCRIBE TO MAILCHIMP
QUEUE UP 7 DAY EMAIL
EVENT / LISTENER BREAKDOWN
67. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MemberRegistered
SEND WELCOME EMAIL
SUBSCRIBE TO MAILCHIMP
QUEUE UP 7 DAY EMAIL
EVENT / LISTENER BREAKDOWN
68. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MemberRegistered
SendWelcomeMail
SubscribeToMailchimp
SendOneWeekEmail
EVENT / LISTENER BREAKDOWN
69. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MemberRegistered SendWelcomeMail
SendOneWeekEmail
SubscribeToMailchimp
EVENTS LISTENERS
EVENT / LISTENER BREAKDOWN
70. class MemberRegistered
{
public $member;
public function __construct(Member $member)
{
$this->member = $member;
}
}
class SendWelcomeEmail implements Listener
{
public function handle($event)
{
Mailer::queue(...);
}
}
71. class MemberRegistered
{
public $member;
public function __construct(Member $member)
{
$this->member = $member;
}
}
class SendWelcomeEmail implements Listener
{
public function handle($event)
{
Mailer::queue(...);
}
}
72. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
THROWING DOMAIN EVENTS
73. trait EventGenerator
{
protected $pendingEvents = [];
protected function raise($event)
{
$this->pendingEvents[] = $event;
}
public function releaseEvents()
{
$events = $this->pendingEvents;
$this->pendingEvents = [];
return $events;
}
}
74. trait EventGenerator
{
protected $pendingEvents = [];
protected function raise($event)
{
$this->pendingEvents[] = $event;
}
public function releaseEvents()
{
$events = $this->pendingEvents;
$this->pendingEvents = [];
return $events;
}
}
75. trait EventGenerator
{
protected $pendingEvents = [];
protected function raise($event)
{
$this->pendingEvents[] = $event;
}
public function releaseEvents()
{
$events = $this->pendingEvents;
$this->pendingEvents = [];
return $events;
}
}
76. trait EventGenerator
{
protected $pendingEvents = [];
protected function raise($event)
{
$this->pendingEvents[] = $event;
}
public function releaseEvents()
{
$events = $this->pendingEvents;
$this->pendingEvents = [];
return $events;
}
}
77. class Member extends Eloquent
{
use EventGenerator;
public static function register($displayName, $email, $password)
{
$member = new static([
'display_name' => $displayName,
'email' => $email,
'password' => $password,
]);
$member->raise(new MemberJoined($member));
return $member;
}
}
78. class Member extends Eloquent
{
use EventGenerator;
public static function register($displayName, $email, $password)
{
$member = new static([
'display_name' => $displayName,
'email' => $email,
'password' => $password,
]);
$member->raise(new MemberRegistered($member));
return $member;
}
}
79. class Member extends Eloquent
{
use EventGenerator;
public static function register($displayName, $email, $password)
{
$member = new static([
'display_name' => $displayName,
'email' => $email,
'password' => $password,
]);
$member->raise(new MemberRegistered($member));
return $member;
}
}
80. class Member extends Eloquent
{
use EventGenerator;
public static function register($displayName, $email, $password)
{
$member = new static([
'display_name' => $displayName,
'email' => $email,
'password' => $password,
]);
$member->raise(new MemberRegistered($member));
return $member;
}
}
81. class Member extends Eloquent
{
use EventGenerator;
public static function register($displayName, $email, $password)
{
$member = new static([
'display_name' => $displayName,
'email' => $email,
'password' => $password,
]);
$member->raise(new MemberRegistered($member));
return $member;
}
}
82. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
EVENT DISPATCHING
83. interface Dispatcher
{
public function addListener($eventName, Listener $listener);
public function dispatch($events);
}
// Register Listeners
$dispatcher = new Dispatcher;
$dispatcher->addListener('MemberRegistered', new SendWelcomeEmail);
$dispatcher->addListener('MemberRegistered', new SubscribeToMailchimp);
$dispatcher->addListener('MemberRegistered', new SendOneWeekEmail);
// Dispatch Events
$dispatcher->dispatch($events);
84. interface Dispatcher
{
public function addListener($eventName, Listener $listener);
public function dispatch($events);
}
// Register Listeners
$dispatcher = new Dispatcher;
$dispatcher->addListener('MemberRegistered', new SendWelcomeEmail);
$dispatcher->addListener('MemberRegistered’, new SubscribeToMailchimp);
$dispatcher->addListener('MemberRegistered', new SendOneWeekEmail);
// Dispatch Events
$dispatcher->dispatch($events);
85. interface Dispatcher
{
public function addListener($eventName, Listener $listener);
public function dispatch($events);
}
// Register Listeners
$dispatcher = new Dispatcher;
$dispatcher->addListener('MemberRegistered', new SendWelcomeEmail);
$dispatcher->addListener('MemberRegistered’, new SubscribeToMailchimp);
$dispatcher->addListener('MemberRegistered', new SendOneWeekEmail);
// Dispatch Events
$dispatcher->dispatch($events);
86. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
THE FULL COMMAND HANDLER
Heads Up...
87. class RegisterMemberHandler implements Handler
{
private $memberRepository;
private $dispatcher;
public function __construct(MemberRepository $memberRepository,
Dispatcher $dispatcher)
{
$this->memberRepository = $memberRepository;
$this->dispatcher = $dispatcher;
}
public function handle($command)
{
$member = Member::register(
$command->displayName,
$command->email,
$command->password);
$this->memberRepository->save($member);
$this->dispatcher->dispatch($member->releaseEvents());
}
}
88. class RegisterMemberHandler implements Handler
{
private $memberRepository;
private $dispatcher;
public function __construct(MemberRepository $memberRepository,
Dispatcher $dispatcher)
{
$this->memberRepository = $memberRepository;
$this->dispatcher = $dispatcher;
}
public function handle($command)
{
$member = Member::register(
$command->displayName,
$command->email,
$command->password);
$this->memberRepository->save($member);
$this->dispatcher->dispatch($member->releaseEvents());
}
}
89. class RegisterMemberHandler implements Handler
{
private $memberRepository;
private $dispatcher;
public function __construct(MemberRepository $memberRepository,
Dispatcher $dispatcher)
{
$this->memberRepository = $memberRepository;
$this->dispatcher = $dispatcher;
}
public function handle($command)
{
$member = Member::register(
$command->displayName,
$command->email,
$command->password);
$this->memberRepository->save($member);
$this->dispatcher->dispatch($member->releaseEvents());
}
}
90. class RegisterMemberHandler implements Handler
{
private $memberRepository;
private $dispatcher;
public function __construct(MemberRepository $memberRepository,
Dispatcher $dispatcher)
{
$this->memberRepository = $memberRepository;
$this->dispatcher = $dispatcher;
}
public function handle($command)
{
$member = Member::register(
$command->displayName,
$command->email,
$command->password);
$this->memberRepository->save($member);
$this->dispatcher->dispatch($member->releaseEvents());
}
}
91. class RegisterMemberHandler implements Handler
{
private $memberRepository;
private $dispatcher;
public function __construct(MemberRepository $memberRepository,
Dispatcher $dispatcher)
{
$this->memberRepository = $memberRepository;
$this->dispatcher = $dispatcher;
}
public function handle($command)
{
$member = Member::register(
$command->displayName,
$command->email,
$command->password);
$this->memberRepository->save($member);
$this->dispatcher->dispatch($member->releaseEvents());
}
}
92. class RegisterMemberHandler implements Handler
{
private $memberRepository;
private $dispatcher;
public function __construct(MemberRepository $memberRepository,
Dispatcher $dispatcher)
{
$this->memberRepository = $memberRepository;
$this->dispatcher = $dispatcher;
}
public function handle($command)
{
$member = Member::register(
$command->displayName,
$command->email,
$command->password);
$this->memberRepository->save($member);
$this->dispatcher->dispatch($member->releaseEvents());
}
}
93. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MEMBER REPLIES TO THREAD
NOTIFY THREAD SUBSCRIBERS
w
NOTIFY TAGGED USERS
COMPLEX SEQUENCE
SEND NOTIFICATION
EMAIL
ADD NOTIFICATION DIGEST
QUEUE ENTRY
SEND NO NOTIFICATION
94. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MEMBER REPLIES TO THREAD
NOTIFY THREAD SUBSCRIBERS
w
NOTIFY TAGGED USERS
COMPLEX SEQUENCE
95. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MEMBER REPLIES TO THREAD
NOTIFY THREAD SUBSCRIBERS
w
NOTIFY TAGGED USERS
COMPLEX SEQUENCE
96. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MemberRepliedToThread
NOTIFY THREAD SUBSCRIBERS
w
NOTIFY TAGGED USERS
COMPLEX SEQUENCE
97. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MemberRepliedToThread
NOTIFY THREAD SUBSCRIBERS
NOTIFY TAGGED USERS
COMPLEX SEQUENCE
98. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MemberRepliedToThread
NotifyThreadSubscribers
NotifyTaggedUsers
COMPLEX SEQUENCE
99. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MEMBER IS NOTIFIED
COMPLEX SEQUENCE
SEND NOTIFICATION
EMAIL
100. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MEMBER IS NOTIFIED
COMPLEX SEQUENCE
SEND NOTIFICATION
EMAIL
101. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MemberNotificationSent
COMPLEX SEQUENCE
SEND NOTIFICATION
EMAIL
102. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MemberNotificationSent
COMPLEX SEQUENCE
SEND NOTIFICATION
EMAIL
103. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MemberNotificationSent
COMPLEX SEQUENCE
SendNotificationEmail
104. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
DOMAIN EVENTS
MemberRepliedToThread NotifyThreadSubscribers
SendNotificationEmail
NotifyTaggedMembers
EVENTS LISTENERS
MemberNotificationSent
105. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
Some Disadvantages
- Can be harder to understand what’s happening
- Requires more infrastructure
- Events can be hard to debug
106. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
DOMAIN-DRIVEN DESIGN
107. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
MORE INFORMATION ABOUT DDD
http://verraes.net
http://rosstuck.com
http://dddinphp.org
Domain-Driven Design
by Eric Evans
Implementing Domain-Driven Design
by Vaughn Vernon
108. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
Even More Information
A very quick read + it’s free
http://www.infoq.com/minibooks/domain-driven-design-quickly
Martin Fowler
http://martinfowler.com/bliki/CommandOrientedInterface.html
http://martinfowler.com/eaaDev/DomainEvent.html
110. Laravel.IO, A Use Case Architecture By Shawn McCool Laracon 2014 in NYC
Thank you Laracon 2014!
Hopefully, I talked so ridiculously fast
that there’s time for questions.
Twitter @ShawnMcCool
Special Thanks to Nick Spelt and Mitchell van Wijngaarden