Advertisement
Advertisement

More Related Content

Advertisement
Advertisement

Domain Driven Design using Laravel

  1. Domain Driven Design Using Laravel by Waqar Alamgir
  2. Managing Complexity AKA Engineering
  3. Functional Requirement
  4. Lets Look at some Concepts 1. MVC Design Pattern 2. Entities 3. Active Records
  5. MVC Design Pattern
  6. Entities “Many objects are found fundamentally by their attributes but rather by a thread of continuity and identity” – Eric Evans
  7. Person Waqar Alamgir Age 26 From Karachi Waqar Alamgir Age 26 From Karachi
  8. Active Records
  9. Person Waqar Alamgir Age 26 From Karachi Waqar Alamgir Age 26 From Karachi ID NAME AGE LOCATION 1 Waqar Alamgir 26 Karachi 2 Waqar Alamgir 26 Karachi
  10. Laravel Framewrok Laravel is a free, open source PHP web application framework, designed for the development of model–view– controller (MVC) web applications. Laravel is listed as the most popular PHP framework in 2013. Eloquent ORM (object-relational mapping) is an advanced PHP implementation of the active record pattern. Better Routing. Restful controllers provide an optional way for separating the logic behind serving HTTP GET and POST requests. Class auto loading. Migrations provide a version control system for database schemas.
  11. That’s not DDD
  12. Philosophy In building large scale web applications MVC seems like a good solution in the initial design phase. However after having built a few large apps that have multiple entry points (web, cli, api etc) you start to find that MVC breaks down. Start using Domain Driven Design.
  13. A Common Application PRESENTATION LAYER Controllers Artisan Commands Queue Listeners SERVICE LAYER Sending Email Queuing up Jobs Repository Implementations COMMANDS / COMMAND BUS DOMAIN Entities Repository Interface
  14. What is Command Meat of the application Controller Artisan Command Queue Worker Whatever
  15. What is Command Meat of the application Commands i.e. Register Member Command
  16. What is Command Meat of the application Commands i.e. Register Member Command
  17. Advantages 1. No business policy in your controller 2. Your code shows intent 3. A single dedicated flow per user case 4. A single point of entry per user case 5. Easy to see which use cased are implemented
  18. Register Command class RegisterMemberCommand { public $displayName; public $email; public $password; public function __construct($displayName , $email , $password) { $this->displayName = $displayName; $this->email = $email; $this->password = $password; } }
  19. Register Command class RegisterMemberCommand { public $displayName; public $email; public $password; public function __construct($displayName , $email , $password) { $this->displayName = $displayName; $this->email = $email; $this->password = $password; } }
  20. The Final Destination Register Member Handler Register Member Command Meat of the application
  21. The Final Destination Register Member Handler Register Member Command Meat of the application Command Bus
  22. Implementing Command Bus
  23. 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); } public function getHandler($command) { $class = $this->mapper- >getHandlerClassFor($command); return $this->container->make($class); } }
  24. How Does The Mapper Know?
  25. One Handle Per Command
  26. Let’s Look at very basic Register Member Command *with out any sequence*
  27. 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); } }
  28. class Member extends Eloquent { public static function register($displayName , $email , $password) { $member = new static([ ‘display_name’ => $displayName, ‘email’ => $email, ‘password’ => $password ]); return $member; } }
  29. Flow Review
  30. Flow Review PRESENTATION LAYER Command SERVICE LAYER COMMAND BUS Command Handler DOMAIN Entities Repositories
  31. Simple Sequence
  32. Simple Sequence Member Registers Subscribe to Mail Chimp Send Welcome Email Queue up 7 Day Email
  33. Domain Events Trigger Listeners Raise Event Typical PUB-SUB pattern Dispatch Event
  34. A Common Application PRESENTATION LAYER Controllers Artisan Commands Queue Listeners SERVICE LAYER Sending Email Queuing up Jobs Repository Implementations COMMANDS / COMMAND BUS Event Dispatcher DOMAIN Entities Repository Interface Domain Events
  35. Events/ Listener Breakdown Member Registers Subscribe to Mail Chimp Send Welcome Email Queue up 7 Day Email
  36. class MemberRegistered { public $member; public function __construct(Member $member) { $this->member = $member; } } class SendWelcomeEmail implements Listener { public function handle($event) { Mailer ::Queue(…); } }
  37. Throwing Domain Events
  38. class EventGenerator { protected $pendingEvents = []; public function raise($event) { $this->pendingEvents = $event; } public function releaseEvents() { $events = $this->pendingEvents; $this->pendingEvents = [] ; return $events; } }
  39. 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; } }
  40. Interface Dispatcher { public function addListener($eventName , Listener $listener) ; public function dispatch($events) ; } // Register Listeners $dispatcher = new Dispatcher() ; $dispatcher-> addListener(‘MemberRegistered’ , new SubscribeToMailchimp) ; $dispatcher-> addListener(‘MemberRegistered’ , new SendWelcomeEmail) ; $dispatcher-> addListener(‘MemberRegistered’ , new SendOneWeekEmail) ;
  41. 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()) ; } }
  42. More Information About DDD Domain-Driven Design: Tackling Complexity in the Heart of Software - Eric Evans Implementing Domain-Driven Design- Vaughn Vernon
  43. Thank You! Have more questions? Email: walamgir@folio3.com Twitter: @wajrcs
Advertisement