SlideShare una empresa de Scribd logo
1 de 183
Descargar para leer sin conexión
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

Más contenido relacionado

La actualidad más candente

Introducing Clean Architecture
Introducing Clean ArchitectureIntroducing Clean Architecture
Introducing Clean ArchitectureRoc Boronat
 
Visual Studio 2019で始める「WPF on .NET Core 3.0」開発
Visual Studio 2019で始める「WPF on .NET Core 3.0」開発Visual Studio 2019で始める「WPF on .NET Core 3.0」開発
Visual Studio 2019で始める「WPF on .NET Core 3.0」開発Atsushi Nakamura
 
Angular 2.0 forms
Angular 2.0 formsAngular 2.0 forms
Angular 2.0 formsEyal Vardi
 
いまなぜドメイン駆動設計か
いまなぜドメイン駆動設計かいまなぜドメイン駆動設計か
いまなぜドメイン駆動設計か増田 亨
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean ArchitectureBadoo
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass SlidesNir Kaufman
 
あの日見たMVCを僕たちはまだ知らない for RoR
あの日見たMVCを僕たちはまだ知らない for RoRあの日見たMVCを僕たちはまだ知らない for RoR
あの日見たMVCを僕たちはまだ知らない for RoRshinnosuke kugimiya
 
PHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object CalisthenicsPHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object CalisthenicsGuilherme Blanco
 
Hexagonal architecture with Spring Boot
Hexagonal architecture with Spring BootHexagonal architecture with Spring Boot
Hexagonal architecture with Spring BootMikalai Alimenkou
 
GUI アプリケーションにおける MVC
GUI アプリケーションにおける MVCGUI アプリケーションにおける MVC
GUI アプリケーションにおける MVCYu Nobuoka
 
Quick tour of PHP from inside
Quick tour of PHP from insideQuick tour of PHP from inside
Quick tour of PHP from insidejulien pauli
 
MVVM in iOS presentation
MVVM in iOS presentationMVVM in iOS presentation
MVVM in iOS presentationG ABHISEK
 
Angular Framework présentation PPT LIGHT
Angular Framework présentation PPT LIGHTAngular Framework présentation PPT LIGHT
Angular Framework présentation PPT LIGHTtayebbousfiha1
 

La actualidad más candente (20)

Angular 2
Angular 2Angular 2
Angular 2
 
Building with Gradle
Building with GradleBuilding with Gradle
Building with Gradle
 
Introducing Clean Architecture
Introducing Clean ArchitectureIntroducing Clean Architecture
Introducing Clean Architecture
 
Clean architecture
Clean architectureClean architecture
Clean architecture
 
Visual Studio 2019で始める「WPF on .NET Core 3.0」開発
Visual Studio 2019で始める「WPF on .NET Core 3.0」開発Visual Studio 2019で始める「WPF on .NET Core 3.0」開発
Visual Studio 2019で始める「WPF on .NET Core 3.0」開発
 
PL/SQL:les curseurs
PL/SQL:les curseursPL/SQL:les curseurs
PL/SQL:les curseurs
 
Angular 2.0 forms
Angular 2.0 formsAngular 2.0 forms
Angular 2.0 forms
 
いまなぜドメイン駆動設計か
いまなぜドメイン駆動設計かいまなぜドメイン駆動設計か
いまなぜドメイン駆動設計か
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean Architecture
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass Slides
 
Eloquent ORM
Eloquent ORMEloquent ORM
Eloquent ORM
 
あの日見たMVCを僕たちはまだ知らない for RoR
あの日見たMVCを僕たちはまだ知らない for RoRあの日見たMVCを僕たちはまだ知らない for RoR
あの日見たMVCを僕たちはまだ知らない for RoR
 
PHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object CalisthenicsPHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object Calisthenics
 
JAVA
JAVAJAVA
JAVA
 
Hexagonal architecture with Spring Boot
Hexagonal architecture with Spring BootHexagonal architecture with Spring Boot
Hexagonal architecture with Spring Boot
 
GUI アプリケーションにおける MVC
GUI アプリケーションにおける MVCGUI アプリケーションにおける MVC
GUI アプリケーションにおける MVC
 
Quick tour of PHP from inside
Quick tour of PHP from insideQuick tour of PHP from inside
Quick tour of PHP from inside
 
MVVM in iOS presentation
MVVM in iOS presentationMVVM in iOS presentation
MVVM in iOS presentation
 
Clean Architecture
Clean ArchitectureClean Architecture
Clean Architecture
 
Angular Framework présentation PPT LIGHT
Angular Framework présentation PPT LIGHTAngular Framework présentation PPT LIGHT
Angular Framework présentation PPT LIGHT
 

Destacado

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
 

Destacado (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 a 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 a 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
 

Último

Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DaySri Ambati
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 

Último (20)

Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 

Command Bus To Awesome Town