SlideShare a Scribd company logo
1 of 183
Download to read offline
Command Bus To
DPC 2015
Awesome Town
Ross Tuck
Command Bus To Awesome Town
This is a story...
...about a refactoring.
$store->purchaseGame($gameId, $customerId);
Domain Model
Service
Controller
View
$store->purchaseGame($gameId, $customerId);
class BUYBUYBUYController
{
public function buyAction(Request $request)
{
$form = $this->getForm();
$form->bindTo($request);
if ($form->isTotallyValid()) {
$store->purchaseGame($gameId, $customerId);
return $this->redirect('thanks_for_money');
}
return ['so_many_errors' => $form->getAllTheErrors()];
}
}
class Store
{
public function purchaseGame($gameId, $customerId)
{
Assert::notNull($gameId);
Assert::notNull($customerId);
$this->security->allowsPurchase($customerId);
$this->logging->debug('purchasing game');
try {
$this->db->beginTransaction();
$purchase = new Purchase($gameId, $customerId);
$this->repository->add($purchase);
$this->db->commitTransaction();
} catch(Exception $e) {
$this->db->rollbackTransaction();
throw $e;
}
}
}
class Store
{
public function purchaseGame($gameId, $customerId)
{
$purchase = new Purchase($gameId, $customerId);
$this->repository->add($purchase);
}
}
$store->purchaseGame($gameId, $customerId);
->purchaseGame($gameId, $customerId);
$store
purchaseGame($gameId, $customerId);
$store->
purchaseGame $gameId, $customerId ;
$store-> ( )
purchaseGame $gameId $customerId
$store-> ( , );
purchaseGame $gameId $customerId
Data
purchaseGame $gameId $customerId
Intent
Information
purchaseGame $gameId $customerId
PurchaseGame $gameId $customerId
PurchaseGame($gameId, $customerId);
new PurchaseGame($gameId, $customerId);
new PurchaseGame($gameId, $customerId);
->getGameId();
->getCustomerId();
new PurchaseGame($gameId, $customerId);
Object
Message
People Paperwork→
Machines Messages→
Different types of messages
Command
Reserve Seat
Reserve Seat
Schedule Appointment
new PurchaseGame($gameId, $customerId);
Reserve Seat
Schedule Appointment
Data Structure
Why object?
+------------+--------------+
| Field | Type |
+------------+--------------+
| id | varchar(60) |
| indication | varchar(255) |
| arrived | tinyint(1) |
| firstName | varchar(255) |
| lastName | varchar(255) |
| birthDate | datetime |
+------------+--------------+
struct purchase_game {
int game_id;
int customer_id;
}
Map[Int, Int]
Tuple[Int, Int]
[
'game_id' => 42,
'customer_id' => 11
]
class PurchaseGame
{
public $gameId;
public $customerId;
}
class PurchaseGame
{
private $gameId;
private $customerId;
public function __construct($gameId, $customerId)
{
$this->gameId = $gameId;
$this->customerId = $customerId;
}
public function getGameId()
{
return $this->gameId;
}
public function getCustomerId()
{
return $this->customerId;
}
}
class PurchaseController
{
public function purchaseGameAction(Request $request)
{
$form = $this->createForm('purchase_game');
$form->bind($request);
if ($form->isValid()) {
$command = $form->getData();
}
}
}
We have intent...
...but no ability to carry out.
Command Handlers
Handlers handle commands
1:1 Command to Handler
class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
Assert::notNull($command->getGameId());
Assert::notNull($command->getCustomerId());
$this->security->allowsPurchase($command->getCustomerId());
$this->logging->debug('purchasing game');
try {
$this->db->beginTransaction();
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
$this->db->commitTransaction();
} catch(Exception $e) {
$this->db->rollbackTransaction();
throw $e;
}
}
}
class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$this->security->allowsPurchase($command->getCustomerId());
$this->logging->debug('purchasing game');
try {
$this->db->beginTransaction();
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
$this->db->commitTransaction();
} catch(Exception $e) {
$this->db->rollbackTransaction();
throw $e;
}
}
}
Command + Handler
$handler->handle(new PurchaseGame($gameId, $customerId));
$store->purchaseGame($gameId, $customerId);
“Extract To Message”
Command Message vs Command Pattern
$command = new PurchaseGame($gameId, $customerId);
$handler->handle($command);
Handler version
$command = new PurchaseGame($gameId, $customerId);
$command = new PurchaseGame($gameId, $customerId);
$command->execute();
Classical version
$command = new PurchaseGame($gameId, $customerId, $repository,
$db, $logger, $security);
$command->execute();
Classical version
●
Game ID
●
Customer ID
Purchase THIS game Purchase ANY game
●
Repository
●
Security
●
Logger
●
DB
I generally advocate Handlers
Connecting the Dots
Command Handler
class PurchaseController
{
public function purchaseGameAction()
{
// form stuff lol
$command = $form->getData();
$this->handler->handle($command);
}
}
Controller
Must be
the RIGHT handler
Mailman
Enter the Bus
Command Bus
Handler
Command Bus
Command
Handler
Command Bus
Command
Handler
Command Bus
Command
♥♥
♥
♥
♥
So, what is this command bus?
new CommandBus(
[
PurchaseGame::class => $purchaseGameHandler,
RegisterUser::class => $registerUserHandler
]
);
$command = new PurchaseGame($gameId, $customerId);
$commandBus->handle($command);
●
Over the Network
●
In a queue
●
Execute in process
class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->handle($command);
}
}
Easier to Wire
Handler Freedom
It's just conventions
class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->handle($command);
}
}
class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->execute($command);
}
}
class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->__invoke($command);
}
}
class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$methodName = 'handle'.$name;
$this->handlers[$name]->{$methodName}($command);
}
}
class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->handle($command);
}
}
class CommandBus
{
private $container = [];
public function __construct($container) {
$this->container = $container;
}
public function handle($command)
{
$name = get_class($command)."Handler";
if (!$this->container->has($name)) {
throw new Exception("No handler for $name");
}
$this->container->get($name)->handle($command);
}
}
It's just conventions
Plugins
Command Bus Uniform Interface→
->handle($command);
Decorator Pattern
Command Bus 3
Command Bus 2
Command Bus
Command Bus 1
Command Bus 3
Command Bus 2
Command Bus 3
Command Bus 2
Command Bus
Command Bus 3
Logging Command Bus
Command Bus
Transaction Command Bus
Logging Command Bus
Command Bus
interface CommandBus
{
public function handle($command);
}
class CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->handle($command);
}
}
class MyCommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->handle($command);
}
}
class MyCommandBus implements CommandBus
{
private $handlers = [];
public function __construct($handlers) {
$this->handlers = $handlers;
}
public function handle($command)
{
$name = get_class($command);
if (!isset($this->handlers[$name])) {
throw new Exception("No handler for $name");
}
$this->handlers[$name]->handle($command);
}
}
What to refactor out?
class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$this->security->allowsPurchase($command->getCustomerId());
$this->logging->debug('purchasing game');
try {
$this->db->beginTransaction();
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
$this->db->commitTransaction();
} catch(Exception $e) {
$this->db->rollbackTransaction();
throw $e;
}
}
}
class LoggingDecorator implements CommandBus
{
private $logger;
private $innerBus;
public function __construct(Logger $logger, CommandBus $innerBus)
{
$this->logger = $logger;
$this->innerBus = $innerBus;
}
public function handle($command)
{
$this->logger->debug('Handling command '.get_class($command));
$this->innerBus->handle($command);
}
}
class LoggingDecorator implements CommandBus
{
private $logger;
private $innerBus;
public function __construct(Logger $logger, CommandBus $innerBus)
{
$this->logger = $logger;
$this->innerBus = $innerBus;
}
public function handle($command)
{
$this->innerBus->handle($command);
$this->logger->debug('Executed command '.get_class($command));
}
}
class LoggingDecorator implements CommandBus
{
private $logger;
private $innerBus;
public function __construct(Logger $logger, CommandBus $innerBus)
{
$this->logger = $logger;
$this->innerBus = $innerBus;
}
public function handle($command)
{
$this->logger->debug('Handling command '.get_class($command));
$this->innerBus->handle($command);
$this->logger->debug('Executed command '.get_class($command));
}
}
$commandBus = new LoggingDecorator(
$logger,
new MyCommandBus(...)
);
$commandBus->handle($command);
class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$this->security->allowsPurchase($command->getCustomerId());
$this->logging->debug('purchasing game');
try {
$this->db->beginTransaction();
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
$this->db->commitTransaction();
} catch(Exception $e) {
$this->db->rollbackTransaction();
throw $e;
}
}
}
class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$this->security->allowsPurchase($command->getCustomerId());
try {
$this->db->beginTransaction();
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
$this->db->commitTransaction();
} catch(Exception $e) {
$this->db->rollbackTransaction();
throw $e;
}
}
}
Ridiculously Powerful
Redonkulously Powerful
Why not Events?
Cohesion
Execution
class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$this->security->allowsPurchase($command->getCustomerId());
try {
$this->db->beginTransaction();
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
$this->db->commitTransaction();
} catch(Exception $e) {
$this->db->rollbackTransaction();
throw $e;
}
}
}
Let's Decoratorize
TM
class TransactionDecorator implements CommandBus
{
private $db;
private $innerBus;
public function __construct($db, $innerBus)
{
$this->db = $db;
$this->innerBus = $innerBus;
}
public function handle($command)
{
try {
$this->db->beginTransaction();
$this->innerBus->handle($command);
$this->db->commitTransaction();
} catch (Exception $e) {
$this->db->rollbackTransaction();
throw $e;
}
}
}
The Handler?
class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$this->security->allowsPurchase($command->getCustomerId());
try {
$this->db->beginTransaction();
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
$this->db->commitTransaction();
} catch(Exception $e) {
$this->db->rollbackTransaction();
throw $e;
}
}
}
class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$this->security->allowsPurchase($command->getCustomerId());
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
}
}
...Wait, all the Commands?
Limiting which decorators run
Marker Interface
$this->security->allowsPurchase($command->getCustomerId());
interface PurchaseCommand
{
public function getCustomerId();
}
class PurchaseGame
{
private $gameId;
private $customerId;
// constructors, getters, etc
}
class PurchaseGame implements PurchaseCommand
{
private $gameId;
private $customerId;
// constructors, getters, etc
}
class AllowedPurchaseDecorator implements CommandBus
{
private $security;
private $innerBus;
public function __construct($security, $innerBus)
{
$this->security = $security;
$this->innerBus = $innerBus;
}
public function handle($command)
{
if ($command instanceof PurchaseCommand) {
$this->security->allowPurchase($command->getCustomerId());
}
$this->innerBus->handle($command);
}
}
class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$this->security->allowsPurchase($command->getCustomerId());
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
}
}
class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
}
}
class PurchaseGameHandler
{
public function handle(PurchaseGame $command)
{
$purchase = new Purchase(
$command->getGameId(),
$command->getCustomerId()
);
$this->repository->add($purchase);
}
}
Stop cutting!
Beyond Decorators
new AllowedPurchaseDecorator(
$security,
new TransactionDecorator(
$db,
new LoggingDecorator(
$logger,
new MyCommandBus(
[
PurchaseGame::class => $purchaseGameHandler
]
)
)
)
)
Constructor Parameter
Method
interface Middleware {
public function handle($command, callable $next);
}
class LoggingMiddleware implements Middleware
{
private $logger;
public function __construct($logger)
{
$this->logger = $logger;
}
public function handle($command, callable $next)
{
$this->logger->debug('handling '.get_class($command));
next($command);
}
}
new CommandBus(
[
new AllowedPurchaseMiddleware($security),
new TransactionMiddleware($db),
new LoggingMiddleware($logger),
new CommandHandlerMiddleware($handlerMapping),
]
);
5 Things That I Have Seen
Thing #1
Handling Commands in Commands
Domain Model
Service
Controller
View
PurchaseGameSendConfirmation
If it needs to happen with the command…
JUST CALL IT
If it needs to happen after the command…
Wait for a domain event
Thing #2
Reading From Commands
Or the lack thereof
“Command Bus should never return anything.”
Command Bus != CQRS
$commandBus->handle(new PurchaseGame($gameId, $customerId));
$store->purchaseGame($gameId, $customerId);
$commandBus->handle(new PurchaseGame($gameId, $customerId));
$id = $this
->domainEvents
->waitFor(GamePurchased::class)
->getId();
Thing #3
Reading with a Command Bus
$handler->handle(new PurchaseGame($gameId, $customerId));
$this->repository->findPurchaseById($id);
$this->readService->findPurchaseVerification($id);
$this->queryBus->find(new PurchaseById($id));
Thing #4
Command Buses Work Great in JS
commandBus.handle({
"command": "purchase_game",
"game_id": gameId,
"customer_id": customerId
});
Thing #5
Single Endpoint “REST”
/commands
/purchase-game
The Meta of Command Buses
Why are there 50 of them?
μ
function createBus($handlers) {
return function ($command) use ($handlers) {
$handlers[get_class($command)]($command);
};
}
$bus = createBus(
[
FooCommand::class => $someClosure,
BarCommand::class => $someOtherClosure
]
);
$cmd = new FooCommand();
$bus($cmd);
But you should use my library.
Command Bus Libraries are useless
...but the plugins aren't.
Me
tactician-doctrine
tactician-logger
named commands
locking
@sagikazarmark
tactician-bernard
tactician-command-events
@boekkooi tactician-amqp
@rdohms
@xtrasmal
@Richard_Tuin
tactician-bundle
@GeeH
@mike_kowalsky
tactician-module
Prasetyo Wicaksono
Eugene Terentev
Jildert Miedema
Nigel Greenway
Frank de Jonge
Ivan Habunek
tactician-service-provider
yii2-tactician
laravel-tactician
tactician-container
tactician-awesome-advice
tactician-pimple
Shared Interfaces
The Future of Tactician
● Simplify Interfaces
● Metadata
● Tracking
● RAD
Domain Model
Service
Controller
View
SimpleBus
Broadway
Command
Handler
Bus
Decorators
executes
connects extends
Command Handler
The End
Images
● http://bj-o23.deviantart.com/art/NOT-Rocket-Science-324795055
● sambabulli.blogsport.de
● https://www.youtube.com/watch?v=XHa6LIUJTPw
● http://khongthe.com/wallpapers/animals/puppy-bow-227081.jpg
● https://www.flickr.com/photos/emptyhighway/7173454/sizes/l
● https://www.flickr.com/photos/jronaldlee/5566380424
domcode.org
Ross Tuck
@rosstuck
joind.in/14219
PHPArchitectureTour.com

More Related Content

What's hot

The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of DjangoJacob Kaplan-Moss
 
PHP Functions & Arrays
PHP Functions & ArraysPHP Functions & Arrays
PHP Functions & ArraysHenry Osborne
 
Learning jQuery in 30 minutes
Learning jQuery in 30 minutesLearning jQuery in 30 minutes
Learning jQuery in 30 minutesSimon Willison
 
C* Summit 2013: The World's Next Top Data Model by Patrick McFadin
C* Summit 2013: The World's Next Top Data Model by Patrick McFadinC* Summit 2013: The World's Next Top Data Model by Patrick McFadin
C* Summit 2013: The World's Next Top Data Model by Patrick McFadinDataStax Academy
 
Introduction to jQuery
Introduction to jQueryIntroduction to jQuery
Introduction to jQueryZeeshan Khan
 
Programmation orientée objet en PHP 5
Programmation orientée objet en PHP 5Programmation orientée objet en PHP 5
Programmation orientée objet en PHP 5Kristen Le Liboux
 
Optimizing MariaDB for maximum performance
Optimizing MariaDB for maximum performanceOptimizing MariaDB for maximum performance
Optimizing MariaDB for maximum performanceMariaDB plc
 
Distributed Load Testing with k6 - DevOps Barcelona
Distributed Load Testing with k6 - DevOps BarcelonaDistributed Load Testing with k6 - DevOps Barcelona
Distributed Load Testing with k6 - DevOps BarcelonaThijs Feryn
 
Class 3 - PHP Functions
Class 3 - PHP FunctionsClass 3 - PHP Functions
Class 3 - PHP FunctionsAhmed Swilam
 
Php pattern matching
Php pattern matchingPhp pattern matching
Php pattern matchingJIGAR MAKHIJA
 
Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Matt Raible
 

What's hot (20)

Cours php
Cours php Cours php
Cours php
 
The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of Django
 
Fundamentos de JDBC
Fundamentos de JDBCFundamentos de JDBC
Fundamentos de JDBC
 
PHP - PDO.pdf
PHP - PDO.pdfPHP - PDO.pdf
PHP - PDO.pdf
 
jQuery
jQueryjQuery
jQuery
 
PHP Functions & Arrays
PHP Functions & ArraysPHP Functions & Arrays
PHP Functions & Arrays
 
Spring Batch - concepts de base
Spring Batch - concepts de baseSpring Batch - concepts de base
Spring Batch - concepts de base
 
Learning jQuery in 30 minutes
Learning jQuery in 30 minutesLearning jQuery in 30 minutes
Learning jQuery in 30 minutes
 
C* Summit 2013: The World's Next Top Data Model by Patrick McFadin
C* Summit 2013: The World's Next Top Data Model by Patrick McFadinC* Summit 2013: The World's Next Top Data Model by Patrick McFadin
C* Summit 2013: The World's Next Top Data Model by Patrick McFadin
 
Introduction to jQuery
Introduction to jQueryIntroduction to jQuery
Introduction to jQuery
 
Programmation orientée objet en PHP 5
Programmation orientée objet en PHP 5Programmation orientée objet en PHP 5
Programmation orientée objet en PHP 5
 
4.2 PHP Function
4.2 PHP Function4.2 PHP Function
4.2 PHP Function
 
Optimizing MariaDB for maximum performance
Optimizing MariaDB for maximum performanceOptimizing MariaDB for maximum performance
Optimizing MariaDB for maximum performance
 
Distributed Load Testing with k6 - DevOps Barcelona
Distributed Load Testing with k6 - DevOps BarcelonaDistributed Load Testing with k6 - DevOps Barcelona
Distributed Load Testing with k6 - DevOps Barcelona
 
Php functions
Php functionsPhp functions
Php functions
 
Class 3 - PHP Functions
Class 3 - PHP FunctionsClass 3 - PHP Functions
Class 3 - PHP Functions
 
Php pattern matching
Php pattern matchingPhp pattern matching
Php pattern matching
 
Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2
 
Scala fundamentals
Scala fundamentalsScala fundamentals
Scala fundamentals
 
Drools
DroolsDrools
Drools
 

Viewers also liked

Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)Ryan Weaver
 
Composer in monolithic repositories
Composer in monolithic repositoriesComposer in monolithic repositories
Composer in monolithic repositoriesSten Hiedel
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsRoss Tuck
 
Hexagonal architecture message-oriented software design
Hexagonal architecture   message-oriented software designHexagonal architecture   message-oriented software design
Hexagonal architecture message-oriented software designMatthias Noback
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm OldRoss Tuck
 
Techniques d'accélération des pages web
Techniques d'accélération des pages webTechniques d'accélération des pages web
Techniques d'accélération des pages webJean-Pierre Vincent
 
Get Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP StreamsGet Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP StreamsDavey Shafik
 
Automation using-phing
Automation using-phingAutomation using-phing
Automation using-phingRajat Pandit
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP GeneratorsMark Baker
 
The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)Matthias Noback
 
Top tips my_sql_performance
Top tips my_sql_performanceTop tips my_sql_performance
Top tips my_sql_performanceafup Paris
 
Why elasticsearch rocks!
Why elasticsearch rocks!Why elasticsearch rocks!
Why elasticsearch rocks!tlrx
 
Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015Marcello Duarte
 
Writing infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQLWriting infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQLGabriele Bartolini
 
Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015Bruno Boucard
 
L'ABC du BDD (Behavior Driven Development)
L'ABC du BDD (Behavior Driven Development)L'ABC du BDD (Behavior Driven Development)
L'ABC du BDD (Behavior Driven Development)Arnauld Loyer
 

Viewers also liked (20)

Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)
 
Composer in monolithic repositories
Composer in monolithic repositoriesComposer in monolithic repositories
Composer in monolithic repositories
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and Hobgoblins
 
Hexagonal architecture message-oriented software design
Hexagonal architecture   message-oriented software designHexagonal architecture   message-oriented software design
Hexagonal architecture message-oriented software design
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm Old
 
Elastic Searching With PHP
Elastic Searching With PHPElastic Searching With PHP
Elastic Searching With PHP
 
Diving deep into twig
Diving deep into twigDiving deep into twig
Diving deep into twig
 
Techniques d'accélération des pages web
Techniques d'accélération des pages webTechniques d'accélération des pages web
Techniques d'accélération des pages web
 
Get Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP StreamsGet Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP Streams
 
PHP5.5 is Here
PHP5.5 is HerePHP5.5 is Here
PHP5.5 is Here
 
Automation using-phing
Automation using-phingAutomation using-phing
Automation using-phing
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)
 
Mocking Demystified
Mocking DemystifiedMocking Demystified
Mocking Demystified
 
Top tips my_sql_performance
Top tips my_sql_performanceTop tips my_sql_performance
Top tips my_sql_performance
 
Why elasticsearch rocks!
Why elasticsearch rocks!Why elasticsearch rocks!
Why elasticsearch rocks!
 
Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015
 
Writing infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQLWriting infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQL
 
Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015
 
L'ABC du BDD (Behavior Driven Development)
L'ABC du BDD (Behavior Driven Development)L'ABC du BDD (Behavior Driven Development)
L'ABC du BDD (Behavior Driven Development)
 

Similar to Command Bus To Awesome Town

Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsSam Hennessy
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design PatternsHugo Hamon
 
The Art of Transduction
The Art of TransductionThe Art of Transduction
The Art of TransductionDavid Stockton
 
Symfony2 - extending the console component
Symfony2 - extending the console componentSymfony2 - extending the console component
Symfony2 - extending the console componentHugo Hamon
 
The command dispatcher pattern
The command dispatcher patternThe command dispatcher pattern
The command dispatcher patternolvlvl
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your CodeAbbas Ali
 
Code moi une RH! (PHP tour 2017)
Code moi une RH! (PHP tour 2017)Code moi une RH! (PHP tour 2017)
Code moi une RH! (PHP tour 2017)Arnaud Langlade
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにYuya Takeyama
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConRafael Dohms
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in actionJace Ju
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
Command-Oriented Architecture
Command-Oriented ArchitectureCommand-Oriented Architecture
Command-Oriented ArchitectureLuiz Messias
 
PHPUnit elevato alla Symfony2
PHPUnit elevato alla Symfony2PHPUnit elevato alla Symfony2
PHPUnit elevato alla Symfony2eugenio pombi
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolveXSolve
 

Similar to Command Bus To Awesome Town (20)

Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
Taming Command Bus
Taming Command BusTaming Command Bus
Taming Command Bus
 
The Art of Transduction
The Art of TransductionThe Art of Transduction
The Art of Transduction
 
Symfony2 - extending the console component
Symfony2 - extending the console componentSymfony2 - extending the console component
Symfony2 - extending the console component
 
The command dispatcher pattern
The command dispatcher patternThe command dispatcher pattern
The command dispatcher pattern
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your Code
 
Code moi une RH! (PHP tour 2017)
Code moi une RH! (PHP tour 2017)Code moi une RH! (PHP tour 2017)
Code moi une RH! (PHP tour 2017)
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くために
 
Functional programming with php7
Functional programming with php7Functional programming with php7
Functional programming with php7
 
Bacbkone js
Bacbkone jsBacbkone js
Bacbkone js
 
Min-Maxing Software Costs
Min-Maxing Software CostsMin-Maxing Software Costs
Min-Maxing Software Costs
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnCon
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
Command-Oriented Architecture
Command-Oriented ArchitectureCommand-Oriented Architecture
Command-Oriented Architecture
 
PHPUnit elevato alla Symfony2
PHPUnit elevato alla Symfony2PHPUnit elevato alla Symfony2
PHPUnit elevato alla Symfony2
 
Smelling your code
Smelling your codeSmelling your code
Smelling your code
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
 
linieaire regressie
linieaire regressielinieaire regressie
linieaire regressie
 

Recently uploaded

Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 

Recently uploaded (20)

Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 

Command Bus To Awesome Town