SlideShare uma empresa Scribd logo
1 de 134
Baixar para ler offline
CQRS
Command Query Responsibility Segregation
Manel López Torrent
Ingeniero informática
Desarrollo software
Agile
@mloptor
malotor@gmail.com
EDUMENT
http://cqrs.nu
DDD in PHP
https://github.com/dddinphp/blog-cqrs
https://github.com/dddinphp/last-wishes-gamify
¿CQRS?
CQRS
Patrón de diseño de app
Lecturas / Escrituras
Modelo rico
Mejor rendimiento
Mejor escalabilidad
Objetivos
Greg Young
https://goodenoughsoftware.net/
@gregyoung
DDD (Domain Driven Design)
Modelo rico VS Modelo Anémico
Patrones tácticos
Arquitectura de capas
Arquitectura hexagonal
Requisitos
Cafetería
- Cuandos los clientes entran en el café se sientan en una
mesa , un camarero/a , abre una cuenta para esa mesa
- Los clientes pueden ordenar bebida y/o comidas del
menú
- Una vez ordenadas las bebidas pueden ser servidas de
inmediato.
- La comida debe ser preparada en cocina. Una vez se ha
preparado puede ser servida
- Cuando los clientes terminan de comer pagan la cuenta (
pueden dejar propina ) y la cuenta se cierra
- No se puede cerrar una cuenta si hay bebida o comida
pendientes
Abrir
Ordenar
Preparar
Servir
Pagar
Cerrar
Camarero
Mesa
Cuenta
Bebida / Comida
Trasladar el modelo a objetos ( DDD táctico )
Creamos tests para asegurar su corrección
Arquitectura hexagonal para conectar el modelo con el mundo
exterior
Application Layer
Domain
Model
Application
Service 1
Request
Infrastructure
Layer DataStoreApplication
Service 2
Application
Service n
Response
<?php
class Tab
{
static public function open($table, $waiter): Tab {}
public function placeOrder($orderedItems) {}
public function serveDrinks($drinksServed) {}
public function prepareFood($foodPrepared) {}
public function serveFood($foodServed) {}
public function close(float $amount) {}
}
interface TabRepository
{
public function getById(TabId $tabId);
public function save(Tab $tab);
}
<?php
class OrderedItem
{
public function __construct(int $menuNumber, bool $IsDrink, float $price) {}
public function getMenuNumber(): int {}
public function isDrink(): bool {}
public function getPrice(): float {}
}
interface OrderedItemsRepository
{
public function findById($id): OrderedItem;
}
OK
Nuevos requisitos
Maître
Barman
Cocina
<?php
interface TabRepository
{
public function getById(TabId $tabId);
public function save(Tab $tab);
}
<?php
interface TabRepository
{
public function getById(TabId $tabId);
public function save(Tab $tab);
public function getTabsByWaiter($waiter);
public function getTabsWithDrinkPending();
public function getTabsWithFoodPrepared();
public function getTabsOpen();
public function getTabsClosed(DateTime $date);
}
<?php
use DoctrineORMQuery
interface TabRepository
{
public function getById(TabId $tabId);
public function save(Tab $tab);
public function getTabsByQuery(Query $query)
}
<?php
interface TabRepository
{
public function getById(TabId $tabId);
public function save(Tab $tab);
public function getTabsBySpeficication(Specification $s);
}
<?php
class MysqlTabRepository implements TabRepository { ... }
class RedisTabRepository implements TabRepository { ... }
class MongoDBTabRepository implements TabRepository { ... }
¿?
ORM
Frameworks
Contaminamos el modelo
SRP
SRP
Command Query
Responsibility
Segregation
Read Model Write Model
Read Model Write Model
Lógica de
negocio
Read Model Write Model
Query Command
Commands
OpenTab
PlaceOrder
MarkDrinksServed
MarkFoodPrepared
MarkFoodServed
CloseTab
Querys
AllTabs
OneTab
AllTabsByWaiter
Infrastructure
Layer
Application
Layer
Command
HandlerCommand
Command
Handler
Query
Handle
Read Model
Model
Command
Query
DataStore
Response
Query
Handle
Query
Response
Controladores Comando Bus Command Handler
Command
CommandHandler
class OpenTabCommand
{
private $tabId;
private $tableNumber;
private $waiterId;
public function __construct($tabId, $tableNumber, $waiterId)
{
$this->tabId = $tabId;
$this->tableNumber = $tableNumber;
$this->waiterId = $waiterId;
}
public function getTabId() { }
public function getTableNumber() { }
public function getWaiterId() { }
}
class OpenTabHandler
{
private $tabRepopsitory;
public function __construct(TabRepository $tabRepository)
{
$this->tabRepopsitory = $tabRepository;
}
public function handle(OpenTabCommand $command)
{
$newTab = Tab::openWithId(
TabId::fromString($command->getTabId()),
$command->getTableNumber(),
$command->getWaiterId()
);
$this->tabRepopsitory->add($newTab);
}
}
Query
QueryHandler
class OneTabQuery
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class OneTabQueryHandler
{
private $tabsRepository;
private $dataTransformer;
public function __construct(
TabsRepository $tabsRepostiory,
DataTranformer $dataTransformer
) {
$this->tabsRepository = $tabsRepostiory;
$this->dataTransformer = $dataTransformer;
}
public function handle(OneTabQuery $query)
{
$tab = $this->tabsRepository->find($query->id);
$this->dataTransformer->write($tab);
return $this->dataTransformer->read();
}
}
Modelo Escritura
Tab
TabRepository
OrderedItem
OrderedItemRepository
Modelo Lectura
TabView
TabViewRepository
OrderedItemView
OrderedItemViewRepository
Modelo Escritura
Tab
TabRepository
OrderedItem
OrderedItemRepository
Modelo Lectura
TabView
TabViewRepository
OrderedItemView
OrderedItemViewRepository
Lógica negocio
Modelo Anémico
<?php
interface TabRepository
{
public function getById(TabId $tabId);
public function save(Tab $tab);
}
interface TabViewRepository
{
public function getTabsByWaiter($waiter);
public function getTabsWithDrinkPending();
public function getTabsWithFoodPrepared();
public function getTabsOpen();
public function getTabsClosed(DateTime $date);
}
Modelo rico
Mejor rendimiento
Mejor escalabilidad
¿Mejor rendimiento?
Infrastructure
Layer
Application
Layer
Command
HandlerCommand
Command
Handler
Query
Handle
Read Model
Model
Command
Query
DataStore
Response
Query
Handle
Query
Response
Model Infrastructure
Layer
DataStore
Infrastructure
Layer
DataStore
Application
Layer
Command
HandlerCommand
Command
Handler
Query
Handle
Read Model
Command
Query
Response
Query
Handle
Query
Response
<?php
class RedisTabRepository implements TabRepository { ... }
class MysqlTabViewRepository implements TabViewRepository { ... }
Modelo rico
Mejor rendimiento
Mejor escalabilidad
¿Mejor escalabilidad?
Model Infrastructure
Layer
DataStore
Infrastructure
Layer
DataStore
Application
Layer
Command
HandlerCommand
Command
Handler
Query
Handle
Read Model
Command
Query
Response
Query
Handle
Query
Response
WRITE SERVICE
READ SERVICE
API
GATEWA
Y
READ
SERVICE
WRITE
SERVICE
READ
SERVICE
READ
SERVICE
Modelo rico
Mejor rendimiento
Mejor escalabilidad
¿Consistencia de los datos?
Infrastructure
Layer
Application Layer
Command
HandlerCommand
Command
Handler
Query
Handle
Read Model
Model
Command
Query
DataStore
Response
Query
Handle
Query
Response
Infrastructure
Layer
DataStore
Eventos del dominio
Se ha abierto una cuenta
Se ordenan bebidas y comida
La comida está preparada
Las bebidas se han servido
La comida se ha preparado
La comida se ha servidor
Se ha cerrado una cuenta
TabOpened
DrinksOrdered
FoodOrdered
DrinksServed
FoodPrepared
FoodServed
TabClosed
<?php
class DrinksOrdered extends TabEvent
{
private $items;
public function __construct(TabId $id, $items)
{
$this->id = $id;
$this->items = $items;
}
public function getItems()
{
return $this->items;
}
}
Command Model
Evento
BUS
Model
Evento
Evento
Model Evento Listenner
BUS
DataStore
Model Listenner
BUS
Event sourcing
El estado de nuestro sistema
es la suma de todos los eventos
ocurridos en el.
A1 {
x = 1
y = 2
}
ID X Y
A1 1 2
A2 3 5 A2 {
x = 3
y = 5
}
A2, y = 5
A1, y = 2
A2, x = 3
A1 , y = 7
A2, x = null y = null
A1 , x = 1
A1, x = null y = null
A1 {
x = null
y = null
}
Tiempo
A2, y = 5
A1, y = 2
A2, x = 3
A1 , y = 7
A2, x = null y = null
A1 , x = 1
A1, x = null y = null
A1 {
x = null
y = null
}
A1 {
x = 1
y = null
}
Tiempo
A2, y = 5
A1, y = 2
A2, x = 3
A1 , y = 7
A2, x = null y = null
A1 , x = 1
A1, x = null y = null
A1 {
x = null
y = null
}
A1 {
x = 1
y = null
}
A2 {
x = null
y = null
}
Tiempo
A2, y = 5
A1, y = 2
A2, x = 3
A1 , y = 7
A2, x = null y = null
A1 , x = 1
A1, x = null y = null
A1 {
x = null
y = null
}
A1 {
x = 1
y = null
}
A1 {
x = 1
y = 7
}
A2 {
x = null
y = null
}
Tiempo
A2, y = 5
A1, y = 2
A2, x = 3
A1 , y = 7
A2, x = null y = null
A1 , x = 1
A1, x = null y = null
A1 {
x = null
y = null
}
A1 {
x = 1
y = null
}
A1 {
x = 1
y = 7
}
A2 {
x = null
y = null
}
A2 {
x = 3
y = null
}
Tiempo
A2, y = 5
A1, y = 2
A2, x = 3
A1 , y = 7
A2, x = null y = null
A1 , x = 1
A1, x = null y = null
A1 {
x = null
y = null
}
A1 {
x = 1
y = null
}
A1 {
x = 1
y = 7
}
A1 {
x = 1
y = 2
}
A2 {
x = null
y = null
}
A2 {
x = 3
y = null
}
Tiempo
A2, y = 5
A1, y = 2
A2, x = 3
A1 , y = 7
A2, x = null y = null
A1 , x = 1
A1, x = null y = null
A1 {
x = null
y = null
}
A1 {
x = 1
y = null
}
A1 {
x = 1
y = 7
}
A1 {
x = 1
y = 2
}
A2 {
x = null
y = null
}
A2 {
x = 3
y = null
}
A2 {
x = 3
y = 5
}
Tiempo
A2, y = 5
A1, y = 2
A2, x = 3
A1 , y = 7
A2, x = null y = null
A1 , x = 1
A1, x = null y = null
A1 {
x = null
y = null
}
A1 {
x = 1
y = null
}
A1 {
x = 1
y = 7
}
A1 {
x = 1
y = 2
}
A2 {
x = null
y = null
}
A2 {
x = 3
y = null
}
A2 {
x = 3
y = null
}
Historia
Auditoria
Fácil persistencia
Reconstruimos nuestros agregado a partir de un
flujo de eventos
Command Model
Evento
BUS
Model
Evento
Evento
EventStore
Proyecciones
ID X Y
A1 1 2
A2 3 5
A1, y = 2
A1 , y = 7
A1 , x = 1
A3, y = 5
A2, x = 3
ID X Y
A1 1 2
A2 3 5
A1, x = 2
A1, y = 2
A1 , y = 7
A1 , x = 1
A3, y = 5
A2, x = 3
ID X Y
A1 1 2
A2 3 5
UPDATE table_name
SET x=2 WHERE id =
A1A1, x = 2
A1, y = 2
A1 , y = 7
A1 , x = 1
A3, y = 5
A2, x = 3
ID X Y
A1 2 2
A2 3 5
A1, x = 2
A1, y = 2
A1 , y = 7
A1 , x = 1
Inconsistencia Eventual
¿Dónde generamos los eventos?
Agregados
Entidad raíz
Id del agregado
Almacenar los eventos
Reconstruir desde flujo de eventos
<?php
class Tab
{
static public function open($table, $waiter): Tab {}
public function placeOrder($orderedItems) {}
public function serveDrinks($drinksServed) {}
public function prepareFood($foodPrepared) {}
public function serveFood($foodServed) {}
public function close(float $amount) {}
}
<?php
class Tab
{
// TabOpened
static public function open($table, $waiter): Tab {}
// DrinksOrdered , FoodOrdered
public function placeOrder($orderedItems) {}
// DrinksServed
public function serveDrinks($drinksServed) {}
// FoodPrepared
public function prepareFood($foodPrepared) {}
// FoodServed
public function serveFood($foodServed) {}
// TabClosed
public function close(float $amount) {}
}
<?php
class Tab {
static public function open($table, $waiter): Tab
{
$id = TabId::create();
$newTab = new Tab($id, $table, $waiter);
DomainEventPublisher::instance()->publish(
new TabOpened($id, $table, $waiter)
);
return $newTab;
}
}
<?php
class Tab {
static public function open($table, $waiter): Tab
{
$id = TabId::create();
$newTab = new Tab($id, $table, $waiter);
DomainEventPublisher::instance()->publish(
new TabOpened($id, $table, $waiter)
);
return $newTab;
}
}
<?php
class Tab extends Aggregate {
static public function open($table, $waiter): Tab
{
$id = TabId::create();
$newTab = new Tab($id, $table, $waiter);
$this->recordThat(new TabOpened($id, $table, $waiter));
return $newTab;
}
}
abstract class Aggregate implements AggregateRoot
{
private $recordedEvents = [];
protected function recordThat(DomainEvent $aDomainEvent)
{
$this->recordedEvents[] = $aDomainEvent;
}
public function getRecordedEvents(): DomainEvents
{
return new DomainEvents($this->recordedEvents);
}
public function clearRecordedEvents()
{
$this->recordedEvents = [];
}
}
abstract class Aggregate implements AggregateRoot
{
public static function reconstituteFrom(AggregateHistory $anAggregateHistory) {
$anAggregate = static::createEmptyWithId(
$anAggregateHistory->getAggregateId()
);
foreach ($anAggregateHistory as $anEvent) {
$anAggregate->apply($anEvent);
}
return $anAggregate;
}
private function apply($anEvent)
{
$method = 'apply' . ClassFunctions::short($anEvent);
$this->$method($anEvent);
}
}
class Tab extends Aggregate {
public function applyDrinksServed(DrinksServed $drinksServed)
{
array_walk($drinksServed->getItems(),
function($drinkServedNumber) {
$item = $this->outstandingDrinks[$drinkServedNumber];
unset($this->outstandingDrinks[$drinkServedNumber]);
$this->servedItems[$drinkServedNumber] = $item;
});
}
}
class Tab extends Aggregate {
public function applyDrinksServed(DrinksServed $drinksServed)
{
array_walk($drinksServed->getItems(),
function($drinkServedNumber) {
$item = $this->outstandingDrinks[$drinkServedNumber];
unset($this->outstandingDrinks[$drinkServedNumber]);
$this->servedItems[$drinkServedNumber] = $item;
});
}
}
Refactorizar agregados
<?php
class Tab {
public function serveDrinks($drinksServed)
{
$this->assertDrinksAreOutstanding($drinksServed);
array_walk($drinksServed, function($drinkServedNumber) {
$item = $this->outstandingDrinks[$drinkServedNumber];
unset($this->outstandingDrinks[$drinkServedNumber]);
$this->servedItems[$drinkServedNumber] = $item;
});
}
}
<?php
class Tab extends Aggregate {
public function serveDrinks($drinksServed)
{
$this->assertDrinksAreOutstanding($drinksServed);
array_walk($drinksServed, function($drinkServedNumber) {
$item = $this->outstandingDrinks[$drinkServedNumber];
unset($this->outstandingDrinks[$drinkServedNumber]);
$this->servedItems[$drinkServedNumber] = $item;
});
$this->recordThat(new DrinksServed(
$this->getAggregateId(),
$drinksServed
));
}
}
<?php
class Tab extends Aggregate {
public function applyDrinksServed(DrinksServed $drinksServed)
{
array_walk($drinksServed->getItems(),
function($drinkServedNumber) {
$item = $this->outstandingDrinks[$drinkServedNumber];
unset($this->outstandingDrinks[$drinkServedNumber]);
$this->servedItems[$drinkServedNumber] = $item;
});
}
}
<?php
class Tab extends Aggregate {
public function serveDrinks($drinksServed)
{
$this->assertDrinksAreOutstanding($drinksServed);
array_walk($drinksServed, function($drinkServedNumber) {
$item = $this->outstandingDrinks[$drinkServedNumber];
unset($this->outstandingDrinks[$drinkServedNumber]);
$this->servedItems[$drinkServedNumber] = $item;
});
$this->recordThat(new DrinksServed(
$this->getAggregateId(),
$drinksServed
));
}
}
<?php
class Tab extends Aggregate {
public function serveDrinks($drinksServed)
{
$this->assertDrinksAreOutstanding($drinksServed);
$drinksServedEvend = new DrinksServed(
$this->getAggregateId(),
$drinksServed
);
$this->recordThat($drinksServedEvend);
$this->apply($drinksServedEvend);
}
}
class Tab extends Aggregate {
public function serveDrinks($drinksServed)
{
$this->assertDrinksAreOutstanding($drinksServed);
$this->applyAndRecordThat(new DrinksServed(
$this->getAggregateId(),
$drinksServed
));
}
}
class Tab extends Aggregate {
public function serveDrinks($drinksServed)
{
$this->assertDrinksAreOutstanding($drinksServed);
$this->applyAndRecordThat(new DrinksServed(
$this->getAggregateId(),
$drinksServed
));
}
}
1 - Comprobamos que el evento se puede aplicar
class Tab extends Aggregate {
public function serveDrinks($drinksServed)
{
$this->assertDrinksAreOutstanding($drinksServed);
$this->applyAndRecordThat(new DrinksServed(
$this->getAggregateId(),
$drinksServed
));
}
}
1 - Comprobamos que el evento se puede aplicar
2 - Lo Aplicamos y lo guardamos
Repositorio
Recuperar flujo de eventos
Persistir eventos guardados
Publicar el flujo eventos
<?php
interface AggregateRepository
{
public function get(IdentifiesAggregate $aggregateId):
AggregateRoot;
public function add(RecordsEvents $aggregate);
}
<?php
class TabEventSourcingRepository implements TabRepository
{
private $eventStore;
private $projector;
public function __construct(
EventStore $eventStore,
$projector
) {
$this->eventStore = $eventStore;
$this->projector = $projector;
}
}
Event Store
<?php
interface EventStore
{
public function commit(DomainEvents $events);
public function getAggregateHistoryFor(IdentifiesAggregate $id);
}
Serializar
{
"type": "TabOpened",
"created_on": 1495579156,
"data": {
"id" : "8b486a7b-2e32-4e17-ad10-e90841286722",
"waiter" : "Jhon Doe",
"table" : 1
}
}
{
"type": "DrinksOrdered",
"created_on": 1495579200,
"data": {
"id" : "8b486a7b-2e32-4e17-ad10-e90841286722",
"items" : [1,2]
}
}
8b486a7b-2e32-4e17-ad10-e90841286722
Proyecciones
<?php
interface Projection
{
public function eventType();
public function project($event);
}
<?php
class TabOpenedProjection implements Projection
{
private $pdo;
public function __construct($pdo)
{
$this->pdo = $pdo;
}
public function project($event)
{
$stmt = $this->pdo->prepare("INSERT INTO tabs (tab_id, waiter, tableNumber, open) VALUES
(:tab_id, :waiter, :tableNumber, 1)");
$stmt->execute([
':tab_id' => $event->getAggregateId(),
':waiter' => $event->getWaiterId(),
':tableNumber' => $event->getTableNumber(),
]);
}
public function eventType()
{
return TabOpened::class;
}
}
<?php
class Projector
{
private $projections = [];
public function register(array $projections)
{
foreach ($projections as $projection) {
$this->projections[$projection->eventType()] = $projection;
}
}
public function project(DomainEvents $events)
{
foreach ($events as $event) {
if (!isset($this->projections[get_class($event)]))
throw new NoProjectionExists();
$this->projections[get_class($event)]->project($event);
}
}
}
Modelo lectura
Modelo anémico
DTO
Entidades generadas ORM
Repositorios generados ORM
Frameworks
There are no dumb questions ...
https://github.com/malotor/cafe_events
PHP 7.1
Phpunit 6
Docker
☁ events_cafe [master] tree -L 1
.
├── README.md
├── bootstrap.php
├── build
├── cache
├── cli-config.php
├── composer.json
├── composer.lock
├── coverage
├── docker-compose.yml
├── phpunit.xml
├── public
├── resources
├── scripts
├── src
├── tests
└── vendor
☁ events_cafe [master] tree -L 2 src
src
├── Application
│ ├── Command
│ ├── DataTransformer
│ └── Query
├── Domain
│ ├── Model
│ └── ReadModel
└── Infrastructure
├── CommandBus
├── Persistence
├── Serialize
└── ui
☁ events_cafe [master] tree -L 2 src/Application
src/Application
├── Command
│ ├── CloseTab.php
│ ├── CloseTabHandler.php
│ ├── MarkDrinksServedCommand.php
│ ├── MarkDrinksServedHandler.php
│ ├── MarkFoodServedCommand.php
│ ├── MarkFoodServedHandler.php
│ ├── OpenTabCommand.php
│ ├── OpenTabHandler.php
│ ├── PlaceOrderCommand.php
│ ├── PlaceOrderHandler.php
│ ├── PrepareFoodCommand.php
│ └── PrepareFoodHandler.php
├── DataTransformer
│ ├── DataTranformer.php
│ └── TabToArrayDataTransformer.php
└── Query
├── AllTabsQuery.php
├── AllTabsQueryHandler.php
├── OneTabQuery.php
└── OneTabQueryHandler.php
☁ events_cafe [master] tree -L 4 src/Infrastructure
src/Infrastructure
├── CommandBus
│ └── CustomInflector.php
├── Persistence
│ ├── Domain
│ │ └── Model
│ │ ├── DoctrineOrderedItemRepository.php
│ │ ├── InMemoryTabRepository.php
│ │ └── TabEventSourcingRepository.php
│ ├── EventStore
│ │ ├── EventStore.php
│ │ ├── PDOEventStore.php
│ │ └── RedisEventStore.php
│ └── Projection
│ ├── BaseProjection.php
│ ├── DrinksOrderedProjection.php
│ ├── Projection.php
│ ├── Projector.php
│ ├── TabOpenedProjection.php
│ └── TabProjection.php
├── Serialize
│ ├── JsonSerializer.php
│ └── Serializer.php
└── ui
└── web
└── app.php
☁ events_cafe [master] tree -L 2 src/Domain
src/Domain
├── Model
│ ├── Aggregate
│ ├── Events
│ ├── OrderedItem
│ └── Tab
└── ReadModel
├── Items.php
└── Tabs.php
☁ events_cafe [master] tree -L 2 src/Domain/Model
src/Domain/Model
├── Aggregate
│ ├── Aggregate.php
│ └── AggregateId.php
├── Events
│ ├── DrinksOrdered.php
│ ├── DrinksServed.php
│ ├── FoodOrdered.php
│ ├── FoodPrepared.php
│ ├── FoodServed.php
│ ├── TabClosed.php
│ ├── TabEvent.php
│ └── TabOpened.php
├── OrderedItem
│ ├── OrderedItem.php
│ ├── OrderedItemNotExists.php
│ └── OrderedItemsRepository.php
└── Tab
├── DrinkIsNotOutstanding.php
├── FoodIsNotPrepared.php
├── FoodNotOutstanding.php
├── MustPayEnoughException.php
├── Tab.php
├── TabHasUnservedItems.php
├── TabId.php
├── TabNotExists.php
├── TabNotOpenException.php
└── TabRepository.php
<?php
$app->post('/tab', function (Request $request) use ($app) {
// …
$command = new CommandOpenTabCommand(
RamseyUuidUuid::uuid4(),
$data['table'],
$data['waiter']
);
$app['command_bus']->handle($command);
// …
})
<?php
$app->get('/tab/{id}', function (Request $request, $id) use ($app)
{
$query = new QueryOneTabQuery($id);
$response = $app['query_bus']->handle($query);
return $app->json([
'tab' => $response
]);
});
Gracias y ..
Que la fuerza os acompañe.

Mais conteúdo relacionado

Mais procurados

GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...
GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...
GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...luisw19
 
The redux saga begins
The redux saga beginsThe redux saga begins
The redux saga beginsDaniel Franz
 
JavaScript Event Loop
JavaScript Event LoopJavaScript Event Loop
JavaScript Event LoopDesignveloper
 
Node Architecture and Getting Started with Express
Node Architecture and Getting Started with ExpressNode Architecture and Getting Started with Express
Node Architecture and Getting Started with Expressjguerrero999
 
Angular & RXJS: examples and use cases
Angular & RXJS: examples and use casesAngular & RXJS: examples and use cases
Angular & RXJS: examples and use casesFabio Biondi
 
Reducing Microservice Complexity with Kafka and Reactive Streams
Reducing Microservice Complexity with Kafka and Reactive StreamsReducing Microservice Complexity with Kafka and Reactive Streams
Reducing Microservice Complexity with Kafka and Reactive Streamsjimriecken
 
Introducing Swagger
Introducing SwaggerIntroducing Swagger
Introducing SwaggerTony Tam
 
Understanding Reactive Programming
Understanding Reactive ProgrammingUnderstanding Reactive Programming
Understanding Reactive ProgrammingAndres Almiray
 
MongoDB Aggregation Framework
MongoDB Aggregation FrameworkMongoDB Aggregation Framework
MongoDB Aggregation FrameworkCaserta
 
Introduction to Swagger
Introduction to SwaggerIntroduction to Swagger
Introduction to SwaggerKnoldus Inc.
 
Resilience4j with Spring Boot
Resilience4j with Spring BootResilience4j with Spring Boot
Resilience4j with Spring BootKnoldus Inc.
 
ASP.NET Web API
ASP.NET Web APIASP.NET Web API
ASP.NET Web APIhabib_786
 
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代Shengyou Fan
 
Documenting your REST API with Swagger - JOIN 2014
Documenting your REST API with Swagger - JOIN 2014Documenting your REST API with Swagger - JOIN 2014
Documenting your REST API with Swagger - JOIN 2014JWORKS powered by Ordina
 
Service Mesh - Why? How? What?
Service Mesh - Why? How? What?Service Mesh - Why? How? What?
Service Mesh - Why? How? What?Orkhan Gasimov
 
webpack 101 slides
webpack 101 slideswebpack 101 slides
webpack 101 slidesmattysmith
 

Mais procurados (20)

GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...
GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...
GraphQL as an alternative approach to REST (as presented at Java2Days/CodeMon...
 
The redux saga begins
The redux saga beginsThe redux saga begins
The redux saga begins
 
JavaScript Event Loop
JavaScript Event LoopJavaScript Event Loop
JavaScript Event Loop
 
Node Architecture and Getting Started with Express
Node Architecture and Getting Started with ExpressNode Architecture and Getting Started with Express
Node Architecture and Getting Started with Express
 
Angular & RXJS: examples and use cases
Angular & RXJS: examples and use casesAngular & RXJS: examples and use cases
Angular & RXJS: examples and use cases
 
Reducing Microservice Complexity with Kafka and Reactive Streams
Reducing Microservice Complexity with Kafka and Reactive StreamsReducing Microservice Complexity with Kafka and Reactive Streams
Reducing Microservice Complexity with Kafka and Reactive Streams
 
Introducing Swagger
Introducing SwaggerIntroducing Swagger
Introducing Swagger
 
Java 8 Workshop
Java 8 WorkshopJava 8 Workshop
Java 8 Workshop
 
Understanding Reactive Programming
Understanding Reactive ProgrammingUnderstanding Reactive Programming
Understanding Reactive Programming
 
PHP MVC
PHP MVCPHP MVC
PHP MVC
 
MongoDB Aggregation Framework
MongoDB Aggregation FrameworkMongoDB Aggregation Framework
MongoDB Aggregation Framework
 
Introduction to Swagger
Introduction to SwaggerIntroduction to Swagger
Introduction to Swagger
 
Resilience4j with Spring Boot
Resilience4j with Spring BootResilience4j with Spring Boot
Resilience4j with Spring Boot
 
MongoDB and Node.js
MongoDB and Node.jsMongoDB and Node.js
MongoDB and Node.js
 
ASP.NET Web API
ASP.NET Web APIASP.NET Web API
ASP.NET Web API
 
An Introduction To REST API
An Introduction To REST APIAn Introduction To REST API
An Introduction To REST API
 
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
 
Documenting your REST API with Swagger - JOIN 2014
Documenting your REST API with Swagger - JOIN 2014Documenting your REST API with Swagger - JOIN 2014
Documenting your REST API with Swagger - JOIN 2014
 
Service Mesh - Why? How? What?
Service Mesh - Why? How? What?Service Mesh - Why? How? What?
Service Mesh - Why? How? What?
 
webpack 101 slides
webpack 101 slideswebpack 101 slides
webpack 101 slides
 

Semelhante a CQRS + Event Sourcing in PHP

Tips on how to improve the performance of your custom modules for high volume...
Tips on how to improve the performance of your custom modules for high volume...Tips on how to improve the performance of your custom modules for high volume...
Tips on how to improve the performance of your custom modules for high volume...Odoo
 
R Programming: Mathematical Functions In R
R Programming: Mathematical Functions In RR Programming: Mathematical Functions In R
R Programming: Mathematical Functions In RRsquared Academy
 
Reactive Programming - ReactFoo 2020 - Aziz Khambati
Reactive Programming - ReactFoo 2020 - Aziz KhambatiReactive Programming - ReactFoo 2020 - Aziz Khambati
Reactive Programming - ReactFoo 2020 - Aziz KhambatiAziz Khambati
 
Compose Async with RxJS
Compose Async with RxJSCompose Async with RxJS
Compose Async with RxJSKyung Yeol Kim
 
Hybrid rule engines (rulesfest 2010)
Hybrid rule engines (rulesfest 2010)Hybrid rule engines (rulesfest 2010)
Hybrid rule engines (rulesfest 2010)Geoffrey De Smet
 
The Ring programming language version 1.6 book - Part 9 of 189
The Ring programming language version 1.6 book - Part 9 of 189The Ring programming language version 1.6 book - Part 9 of 189
The Ring programming language version 1.6 book - Part 9 of 189Mahmoud Samir Fayed
 
The Ring programming language version 1.7 book - Part 10 of 196
The Ring programming language version 1.7 book - Part 10 of 196The Ring programming language version 1.7 book - Part 10 of 196
The Ring programming language version 1.7 book - Part 10 of 196Mahmoud Samir Fayed
 
Unit test candidate solutions
Unit test candidate solutionsUnit test candidate solutions
Unit test candidate solutionsbenewu
 
Sparkling Water Meetup
Sparkling Water MeetupSparkling Water Meetup
Sparkling Water MeetupSri Ambati
 
Causal Inference in R
Causal Inference in RCausal Inference in R
Causal Inference in RAna Daglis
 
COCOA: Communication-Efficient Coordinate Ascent
COCOA: Communication-Efficient Coordinate AscentCOCOA: Communication-Efficient Coordinate Ascent
COCOA: Communication-Efficient Coordinate Ascentjeykottalam
 
Clean code & design patterns
Clean code & design patternsClean code & design patterns
Clean code & design patternsPascal Larocque
 
CS101- Introduction to Computing- Lecture 35
CS101- Introduction to Computing- Lecture 35CS101- Introduction to Computing- Lecture 35
CS101- Introduction to Computing- Lecture 35Bilal Ahmed
 
Performance measurement and tuning
Performance measurement and tuningPerformance measurement and tuning
Performance measurement and tuningAOE
 
R Programming: Comparing Objects In R
R Programming: Comparing Objects In RR Programming: Comparing Objects In R
R Programming: Comparing Objects In RRsquared Academy
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with GroovyArturo Herrero
 
Intravert Server side processing for Cassandra
Intravert Server side processing for CassandraIntravert Server side processing for Cassandra
Intravert Server side processing for CassandraEdward Capriolo
 

Semelhante a CQRS + Event Sourcing in PHP (20)

CQRS + ES. Más allá del hexágono
CQRS + ES. Más allá del hexágonoCQRS + ES. Más allá del hexágono
CQRS + ES. Más allá del hexágono
 
Tips on how to improve the performance of your custom modules for high volume...
Tips on how to improve the performance of your custom modules for high volume...Tips on how to improve the performance of your custom modules for high volume...
Tips on how to improve the performance of your custom modules for high volume...
 
R Programming: Mathematical Functions In R
R Programming: Mathematical Functions In RR Programming: Mathematical Functions In R
R Programming: Mathematical Functions In R
 
Reactive Programming - ReactFoo 2020 - Aziz Khambati
Reactive Programming - ReactFoo 2020 - Aziz KhambatiReactive Programming - ReactFoo 2020 - Aziz Khambati
Reactive Programming - ReactFoo 2020 - Aziz Khambati
 
Compose Async with RxJS
Compose Async with RxJSCompose Async with RxJS
Compose Async with RxJS
 
Hybrid rule engines (rulesfest 2010)
Hybrid rule engines (rulesfest 2010)Hybrid rule engines (rulesfest 2010)
Hybrid rule engines (rulesfest 2010)
 
The Ring programming language version 1.6 book - Part 9 of 189
The Ring programming language version 1.6 book - Part 9 of 189The Ring programming language version 1.6 book - Part 9 of 189
The Ring programming language version 1.6 book - Part 9 of 189
 
The Ring programming language version 1.7 book - Part 10 of 196
The Ring programming language version 1.7 book - Part 10 of 196The Ring programming language version 1.7 book - Part 10 of 196
The Ring programming language version 1.7 book - Part 10 of 196
 
Unit test candidate solutions
Unit test candidate solutionsUnit test candidate solutions
Unit test candidate solutions
 
00_Introduction to Java.ppt
00_Introduction to Java.ppt00_Introduction to Java.ppt
00_Introduction to Java.ppt
 
Sparkling Water Meetup
Sparkling Water MeetupSparkling Water Meetup
Sparkling Water Meetup
 
Causal Inference in R
Causal Inference in RCausal Inference in R
Causal Inference in R
 
COCOA: Communication-Efficient Coordinate Ascent
COCOA: Communication-Efficient Coordinate AscentCOCOA: Communication-Efficient Coordinate Ascent
COCOA: Communication-Efficient Coordinate Ascent
 
Clean code & design patterns
Clean code & design patternsClean code & design patterns
Clean code & design patterns
 
CS101- Introduction to Computing- Lecture 35
CS101- Introduction to Computing- Lecture 35CS101- Introduction to Computing- Lecture 35
CS101- Introduction to Computing- Lecture 35
 
Laravel tips-2019-04
Laravel tips-2019-04Laravel tips-2019-04
Laravel tips-2019-04
 
Performance measurement and tuning
Performance measurement and tuningPerformance measurement and tuning
Performance measurement and tuning
 
R Programming: Comparing Objects In R
R Programming: Comparing Objects In RR Programming: Comparing Objects In R
R Programming: Comparing Objects In R
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
Intravert Server side processing for Cassandra
Intravert Server side processing for CassandraIntravert Server side processing for Cassandra
Intravert Server side processing for Cassandra
 

Último

Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$
Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$
Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$kojalkojal131
 
On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024APNIC
 
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip CallDelhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Callshivangimorya083
 
10.pdfMature Call girls in Dubai +971563133746 Dubai Call girls
10.pdfMature Call girls in Dubai +971563133746 Dubai Call girls10.pdfMature Call girls in Dubai +971563133746 Dubai Call girls
10.pdfMature Call girls in Dubai +971563133746 Dubai Call girlsstephieert
 
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRLLucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRLimonikaupta
 
AlbaniaDreamin24 - How to easily use an API with Flows
AlbaniaDreamin24 - How to easily use an API with FlowsAlbaniaDreamin24 - How to easily use an API with Flows
AlbaniaDreamin24 - How to easily use an API with FlowsThierry TROUIN ☁
 
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
AWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptxAWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptxellan12
 
FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607
FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607
FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607dollysharma2066
 
Top Rated Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
Top Rated  Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...Top Rated  Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
Top Rated Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...Call Girls in Nagpur High Profile
 
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...APNIC
 
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort ServiceEnjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort ServiceDelhi Call girls
 
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663Call Girls Mumbai
 
horny (9316020077 ) Goa Call Girls Service by VIP Call Girls in Goa
horny (9316020077 ) Goa  Call Girls Service by VIP Call Girls in Goahorny (9316020077 ) Goa  Call Girls Service by VIP Call Girls in Goa
horny (9316020077 ) Goa Call Girls Service by VIP Call Girls in Goasexy call girls service in goa
 
Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
Russian Call girls in Dubai +971563133746 Dubai Call girls
Russian  Call girls in Dubai +971563133746 Dubai  Call girlsRussian  Call girls in Dubai +971563133746 Dubai  Call girls
Russian Call girls in Dubai +971563133746 Dubai Call girlsstephieert
 
VIP 7001035870 Find & Meet Hyderabad Call Girls Dilsukhnagar high-profile Cal...
VIP 7001035870 Find & Meet Hyderabad Call Girls Dilsukhnagar high-profile Cal...VIP 7001035870 Find & Meet Hyderabad Call Girls Dilsukhnagar high-profile Cal...
VIP 7001035870 Find & Meet Hyderabad Call Girls Dilsukhnagar high-profile Cal...aditipandeya
 
Networking in the Penumbra presented by Geoff Huston at NZNOG
Networking in the Penumbra presented by Geoff Huston at NZNOGNetworking in the Penumbra presented by Geoff Huston at NZNOG
Networking in the Penumbra presented by Geoff Huston at NZNOGAPNIC
 

Último (20)

Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$
Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$
Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$
 
On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024
 
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip CallDelhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
Delhi Call Girls Rohini 9711199171 ☎✔👌✔ Whatsapp Hard And Sexy Vip Call
 
10.pdfMature Call girls in Dubai +971563133746 Dubai Call girls
10.pdfMature Call girls in Dubai +971563133746 Dubai Call girls10.pdfMature Call girls in Dubai +971563133746 Dubai Call girls
10.pdfMature Call girls in Dubai +971563133746 Dubai Call girls
 
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRLLucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
 
AlbaniaDreamin24 - How to easily use an API with Flows
AlbaniaDreamin24 - How to easily use an API with FlowsAlbaniaDreamin24 - How to easily use an API with Flows
AlbaniaDreamin24 - How to easily use an API with Flows
 
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
 
AWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptxAWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptx
 
FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607
FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607
FULL ENJOY Call Girls In Mayur Vihar Delhi Contact Us 8377087607
 
Top Rated Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
Top Rated  Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...Top Rated  Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
Top Rated Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
 
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
 
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
 
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort ServiceEnjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
 
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
 
horny (9316020077 ) Goa Call Girls Service by VIP Call Girls in Goa
horny (9316020077 ) Goa  Call Girls Service by VIP Call Girls in Goahorny (9316020077 ) Goa  Call Girls Service by VIP Call Girls in Goa
horny (9316020077 ) Goa Call Girls Service by VIP Call Girls in Goa
 
Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Saket Delhi 💯Call Us 🔝8264348440🔝
 
Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Pratap Nagar Delhi 💯Call Us 🔝8264348440🔝
 
Russian Call girls in Dubai +971563133746 Dubai Call girls
Russian  Call girls in Dubai +971563133746 Dubai  Call girlsRussian  Call girls in Dubai +971563133746 Dubai  Call girls
Russian Call girls in Dubai +971563133746 Dubai Call girls
 
VIP 7001035870 Find & Meet Hyderabad Call Girls Dilsukhnagar high-profile Cal...
VIP 7001035870 Find & Meet Hyderabad Call Girls Dilsukhnagar high-profile Cal...VIP 7001035870 Find & Meet Hyderabad Call Girls Dilsukhnagar high-profile Cal...
VIP 7001035870 Find & Meet Hyderabad Call Girls Dilsukhnagar high-profile Cal...
 
Networking in the Penumbra presented by Geoff Huston at NZNOG
Networking in the Penumbra presented by Geoff Huston at NZNOGNetworking in the Penumbra presented by Geoff Huston at NZNOG
Networking in the Penumbra presented by Geoff Huston at NZNOG
 

CQRS + Event Sourcing in PHP