SlideShare una empresa de Scribd logo
1 de 74
Prosta architektura
dla nieprostego systemu
Mateusz Stasch
Mateusz Stasch
@mattstasch
http://mattstasch.net
CQRS
CQRS
CQRS
jest trudny
CQRS
jest trudny *
CQRS
CQRS
Implementacja zasady CQS
w postaci wzorca architektonicznego*
DBModel
Business
Logic
UI
DTO
DTO
ORM
DBDomain Model
Commands
UI
DTO
DTO
ORM
Queries
DB
WRITE Domain ModelCommands
UI
DTO
DTO
ORM
Queries READ Model
DB
WRITE Domain ModelCommands
UI
DTO
DTO
ORM
Queries
SELECT … FROM … WHERE …
READ
Model
READ DB
WRITE Domain ModelCommands
UI
DTO
DTO Queries
SELECT … FROM … WHERE …
WRITE DB
PROJECTION
READ DB
WRITE Domain ModelCommands
UI
DTO
DTO Queries
SELECT … FROM … WHERE …
PROJECTION
Event Stream
CQRS != ES
public class UserManager : IUserManager
{
public UserDetails UpdateUserStatus(...)
{
// ...
return user;
}
}
public class UserManager : IUserManager
{
public UserDetails UpdateUserStatus(...)
{
// ...
return user;
}
}
RESPONSIBILITY?
Manager
Command – zmienia stan systemu
Query – odczytuje stan systemu
public interface IQuery<out TResult>
{
TResult Execute();
}
public interface IQuery<out TResult>
{
TResult Execute();
}
public class QueryDispatcher : IQueryDispatcher
{
TResult Run<TResult>(IQuery<TResult> query)
{
using(var tx = session.OpenReadOnlyTransaction())
{
return query.Execute();
}
}
}
public interface IQuery<out TResult>
{
TResult Execute();
}
public class QueryDispatcher : IQueryDispatcher
{
TResult Run<TResult>(IQuery<TResult> query)
{
using(var tx = session.OpenReadOnlyTransaction())
{
return query.Execute();
}
}
}
public interface ICommandHandler<in TCommand>
{
void Execute(TCommand command);
}
public interface ICommandHandler<in TCommand>
{
void Execute(TCommand command);
}
public class CommandDispatcher : ICommandDispatcher
{
public void Execute<in TCommand>(TCommand command)
{
var handler = ResolveCommandHandler<TCommand>();
handler.Execute(command);
}
}
public interface ICommandHandler<in TCommand>
{
void Execute(TCommand command);
}
public class CommandDispatcher : ICommandDispatcher
{
public void Execute<in TCommand>(TCommand command)
{
var handler = ResolveCommandHandler<TCommand>();
handler.Execute(command);
}
}
Semantyka
Ekspresywność kodu
Semantyka
Ekspresywność kodu
Semantyka
Single Responsibility
using(var tx = session.BeginTransaction())
{
try
{
var user = repository.GetById<UserDetails>(id);
user.Status = newStatus;
tx.Commit();
return user;
}
catch
{
tx.Rollback();
throw;
}
}
public class UserManager : IUserManager
{
[Transactional]
public UserDetails UpdateUserStatus(...)
{
// ...
return user;
}
}
using(var tx = session.BeginTransaction())
{
try
{
var user = repository.GetById<UserDetails>(id);
user.Status = newStatus;
tx.Commit();
return user;
}
catch
{
tx.Rollback();
throw;
}
}
using(var tx = session.BeginTransaction())
{
try
{
var user = repository.GetById<UserDetails>(id);
user.Status = newStatus;
tx.Commit();
return user;
}
catch
{
tx.Rollback();
throw;
}
}
public UpdateUserStatusCommandHandler
: ICommandHandler<UpdateUserStatusCommand>
{
public void Execute(UpdateUserStatusCommand command)
{
var user = repository.GetById(command.Id);
user.Status = command.NewStatus;
}
}
public class CommandDispatcher : ICommandDispatcher
{
public void Execute<in TCommand>(TCommand command)
{
var handler = ResolveCommandHandler<TCommand>();
using(var tx = session.OpenTransaction())
{
try
{
handler.Execute(command);
tx.Commit();
}
catch
{
tx.Rollback();
throw;
}
}
}
}
public class TransactionalCommandDispatcherDecorator : ICommandDispatcher
{
public TransactionalCommandDispatcher(ICommandDispatcher …)
{…}
public void Execute<in TCommand>(TCommand command)
{
using(var tx = session.OpenTransaction())
{
try
{
decoratedDispatcher.Execute(command);
tx.Commit();
}
catch
{
tx.Rollback();
throw;
}
}
}
}
Logika biznesowa
Infrastruktura
Database
Infrastructure
Domain
Business Logic
UI
Domena
Database
Infrastructure
Domain
Querying
UI
Database
Infrastructure
Domain
Querying
UI
DependencyInjection
IQuery
IQueryDispatcher
GetUserDetailsQuery
Database
Infrastructure
Domain
Querying
UI
IUserRepository
ICommand ICommandHandler
ICommandDispatcher
DependencyInjection
IQuery
IQueryDispatcher
UpdateStatusCommand(Handler)
GetUserDetailsQuery
Database
Infrastructure
Domain
Querying
UI
IUserRepository
ICommand ICommandHandler
ICommandDispatcher
DependencyInjection
IQuery
IQueryDispatcher
UpdateStatusCommand(Handler)
CommandDispatcher
UserRepository
QueryDispatcher
GetUserDetailsQuery
Domain
Infrastructure
ICommandDispatcher
CommandDispatcher
ICommand
DeactivateUserCommand
IQuery
QueryDispatcher
IUserRepository
UserRepository
…
using(var tx = session.BeginTransaction())
{
try
{
var user = repository.GetById<UserDetails>(id);
user.Status = newStatus;
tx.Commit();
return user;
}
catch
{
tx.Rollback();
throw;
}
}
public UpdateUserStatusCommandHandler
: ICommandHandler<UpdateUserStatusCommand>
{
// ...
public void Execute(UpdateUserStatusCommand command)
{
var user = repository.GetById(command.Id);
user.Status = command.NewStatus;
}
}
public UpdateUserStatusCommandHandler
: ICommandHandler<UpdateUserStatusCommand>
{
// ...
public void Execute(UpdateUserStatusCommand command)
{
var user = repository.GetById(command.Id);
user.Status = command.NewStatus;
}
}
Robienie CRUDa w CQRSie jest bezsensowne!
Robienie CRUDa w CQRSie jest bezsensowne!
public DeactivateUserCommandHandler
: ICommandHandler<DeactivateUserCommand>
{
// ...
public void Execute(DeactivateUserCommand command)
{
var user = repository.GetById(command.Id);
user.Deactivate();
}
}
READ DB
WRITE Domain ModelCommands
UI
ORM
Queries
SELECT … FROM … WHERE …
WRITE DB
PROJECTION
READ DB
WRITE Domain ModelCommands
UI
ORM
Queries
SELECT … FROM … WHERE …
WRITE DB
PROJECTION
READ DB
READ DB WRITE DB!=
READ DB WRITE DB!=
Eager Read Derivation
READ DB ==
READ DB
READ DB
READ DB
READ DB
WRITE Domain ModelCommands
UI
ORM
Queries
SELECT … FROM … WHERE …
WRITE DB
PROJECTION
Eventual Consistency
DB
WRITE Domain ModelCommands
UI
ORM
Queries
SELECT … FROM … WHERE …
READ
Model
Jak zacząć?
Jakiś Framework?
Nope!
Napisz to sam!
To proste!
public interface IQuery<out TResult>
{
TResult Execute();
}
public class QueryDispatcher : IQueryDispatcher
{
TResult Run<out TResult>(IQuery<TResult> query)
{
using(var tx = session.OpenReadOnlyTransaction())
{
return query.Execute();
}
}
}
public interface IQuery<out TResult>
{
TResult Execute();
}
public class QueryDispatcher : IQueryDispatcher
{
TResult Run<out TResult>(IQuery<TResult> query)
{
using(var tx = session.OpenReadOnlyTransaction())
{
return query.Execute();
}
}
}
public interface ICommandHandler<in TCommand>
{
void Execute(TCommand command);
}
public class CommandDispatcher : ICommandDispatcher
{
public void Execute<in TCommand>(TCommand command)
{
var handler = ResolveCommandHandler<TCommand>();
handler.Execute(command);
}
}
public class TaskController
{
public TaskController(TaskManager taskManager) {…}
public ActionResult MarkAsFinalized(TaskId taskId)
{
taskManager.UpdateStatus(taskId, TaskStatuses.Finalized);
taskManager.UpdateFinalizationDate(taskId, DateTime.Now);
taskManager.UpdateFinalizedBy(taskId, CurrentUser.Id);
return Success;
}
}
public class TaskController : Controller
{
public TaskController(CommandDispatcher commandDispatcher) {…}
public ActionResult MarkAsFinalized(TaskId taskId)
{
var finalizeCommand = new FinalizeTaskCommand(taskId,
CurrrentUser.Id);
commandDispatcher.Execute(finalizeCommand);
return Success;
}
}
public class FinalizeTaskCommand
{
public FinalizeTaskCommand(TaskId id, UserId finalizingUser)
{…}
public TaskId Id { get; private set; }
public UserId FinalizingUser { get; private set; }
}
public class FinalizeTaskCommandHandler
: ICommandHandler<FinalizeTaskCommand>
{
public FinalizeTaskCommandHanlder(
ITaskRepository repository,
IDateTimeProvider dtp
) {…}
public void Execute(FinalizeTaskCommand command)
{
var task = repository.GetById(command.Id);
task.Status = TaskStatuses.Done;
task.FinalizedAt = dtp.Now();
task.FinalizedBy = command.FinalizingUser;
}
}
public class FinalizeTaskCommandHandler
: ICommandHandler<FinalizeTaskCommand>
{
public FinalizeTaskCommandHanlder(
ITaskRepository repository,
IDateTimeProvider dtp
) {…}
public void Execute(FinalizeTaskCommand command)
{
var task = repository.GetById(command.Id);
task.Finalize(dtp.Now(), command.FinalizingUser);
}
}
Q&A
Prosta architektura
dla nieprostego systemu
Mateusz Stasch
Dziękuję
za uwagę
Prosta architektura
dla nieprostego systemu
Mateusz Stasch

Más contenido relacionado

Similar a 4Developers 2015: CQRS - Prosta architektura dla nieprostego systemu! - Mateusz Stasch

Similar a 4Developers 2015: CQRS - Prosta architektura dla nieprostego systemu! - Mateusz Stasch (20)

Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenches
 
JDBC Tutorial
JDBC TutorialJDBC Tutorial
JDBC Tutorial
 
My way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionMy way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca edition
 
Projet d'accès aux résultats des étudiant via client mobile
Projet d'accès aux résultats des étudiant via client mobile Projet d'accès aux résultats des étudiant via client mobile
Projet d'accès aux résultats des étudiant via client mobile
 
Enabling Microservices @Orbitz - DockerCon 2015
Enabling Microservices @Orbitz - DockerCon 2015Enabling Microservices @Orbitz - DockerCon 2015
Enabling Microservices @Orbitz - DockerCon 2015
 
Inversion Of Control
Inversion Of ControlInversion Of Control
Inversion Of Control
 
The Developer Conference - CloudKit, entendendo a Cloud da Apple
The Developer Conference - CloudKit, entendendo a Cloud da AppleThe Developer Conference - CloudKit, entendendo a Cloud da Apple
The Developer Conference - CloudKit, entendendo a Cloud da Apple
 
Docker Swarm & Machine
Docker Swarm & MachineDocker Swarm & Machine
Docker Swarm & Machine
 
When Docker Engine 1.12 features unleashes software architecture
When Docker Engine 1.12 features unleashes software architectureWhen Docker Engine 1.12 features unleashes software architecture
When Docker Engine 1.12 features unleashes software architecture
 
Command pattern vs. MVC: Lean Beans (are made of this)
Command pattern vs. MVC: Lean Beans (are made of this)Command pattern vs. MVC: Lean Beans (are made of this)
Command pattern vs. MVC: Lean Beans (are made of this)
 
Dont break the glass
Dont break the glassDont break the glass
Dont break the glass
 
Using linuxKit to build custom rancherOS systems
Using linuxKit to build custom rancherOS systems Using linuxKit to build custom rancherOS systems
Using linuxKit to build custom rancherOS systems
 
The Next Step in AS3 Framework Evolution
The Next Step in AS3 Framework EvolutionThe Next Step in AS3 Framework Evolution
The Next Step in AS3 Framework Evolution
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
 
Terrific Frontends
Terrific FrontendsTerrific Frontends
Terrific Frontends
 
Defcon_Oracle_The_Making_of_the_2nd_sql_injection_worm
Defcon_Oracle_The_Making_of_the_2nd_sql_injection_wormDefcon_Oracle_The_Making_of_the_2nd_sql_injection_worm
Defcon_Oracle_The_Making_of_the_2nd_sql_injection_worm
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the Trenches
 
HashiStack. To the cloud and beyond...
HashiStack. To the cloud and beyond...HashiStack. To the cloud and beyond...
HashiStack. To the cloud and beyond...
 
Brad Wood - CommandBox CLI
Brad Wood - CommandBox CLI Brad Wood - CommandBox CLI
Brad Wood - CommandBox CLI
 
Developing and deploying applications with Spring Boot and Docker (@oakjug)
Developing and deploying applications with Spring Boot and Docker (@oakjug)Developing and deploying applications with Spring Boot and Docker (@oakjug)
Developing and deploying applications with Spring Boot and Docker (@oakjug)
 

Último

Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
chiefasafspells
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
masabamasaba
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 

Último (20)

WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaS
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
 

4Developers 2015: CQRS - Prosta architektura dla nieprostego systemu! - Mateusz Stasch