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

74
Prosta architektura dla nieprostego systemu Mateusz Stasch

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

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

Prosta architektura dla nieprostego systemu

Mateusz Stasch

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

Mateusz Stasch

@mattstasch

http://mattstasch.net

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

CQRS

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

CQRS

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

CQRSjest trudny

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

CQRSjest trudny *

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

CQRS

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

CQRSImplementacja zasady CQS

w postaci wzorca architektonicznego*

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

DBModelBusiness

LogicUI

DTO

DTO

ORM

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

DBDomain Model

Commands

UI

DTO

DTO

ORM

Queries

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

DB

WRITE Domain ModelCommands

UI

DTO

DTO

ORM

Queries READ Model

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

DB

WRITE Domain ModelCommands

UI

DTO

DTO

ORM

Queries

SELECT … FROM … WHERE …

READ Model

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

READ DB

WRITE Domain ModelCommands

UI

DTO

DTO QueriesSELECT … FROM … WHERE …

WRITE DB

PROJECTION

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

READ DB

WRITE Domain ModelCommands

UI

DTO

DTO QueriesSELECT … FROM … WHERE …

PROJECTION

Event Stream

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

CQRS != ES

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

public class UserManager : IUserManager{

public UserDetails UpdateUserStatus(...) {

// ...

return user; }

}

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

public class UserManager : IUserManager{

public UserDetails UpdateUserStatus(...) {

// ...

return user; }

}

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

RESPONSIBILITY?

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

Manager

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

Command – zmienia stan systemu

Query – odczytuje stan systemu

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

public interface IQuery<out TResult>{

TResult Execute();}

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

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();}

}}

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

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();}

}}

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

public interface ICommandHandler<in TCommand>{

void Execute(TCommand command);}

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

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);}

}

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

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);}

}

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

Semantyka

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

Ekspresywność kodu

Semantyka

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

Ekspresywność kodu

Semantyka

Single Responsibility

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

using(var tx = session.BeginTransaction()){

try{

var user = repository.GetById<UserDetails>(id);

user.Status = newStatus;

tx.Commit();

return user;}catch{

tx.Rollback();throw;

}}

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

public class UserManager : IUserManager{

[Transactional]public UserDetails UpdateUserStatus(...) {

// ...

return user; }

}

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

using(var tx = session.BeginTransaction()){

try{

var user = repository.GetById<UserDetails>(id);

user.Status = newStatus;

tx.Commit();

return user;}catch{

tx.Rollback();throw;

}}

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

using(var tx = session.BeginTransaction()){

try{

var user = repository.GetById<UserDetails>(id);

user.Status = newStatus;

tx.Commit();

return user;}catch{

tx.Rollback();throw;

}}

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

public UpdateUserStatusCommandHandler: ICommandHandler<UpdateUserStatusCommand>

{public void Execute(UpdateUserStatusCommand command){

var user = repository.GetById(command.Id);user.Status = command.NewStatus;

}}

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

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;

}}

}}

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

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;

}}

}}

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

Logika biznesowa

Infr

astr

ukt

ura

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

Database

Infrastructure

Domain

Business Logic

UI

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

Domena

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

Database

Infrastructure

Domain

Querying

UI

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

Database

Infrastructure

Domain

Querying

UI

De

pe

nd

en

cy

In

je

ct

io

n

IQuery

IQueryDispatcher

GetUserDetailsQuery

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

Database

Infrastructure

Domain

Querying

UI

IUserRepository

ICommand ICommandHandler

ICommandDispatcher

De

pe

nd

en

cy

In

je

ct

io

n

IQuery

IQueryDispatcher

UpdateStatusCommand(Handler)

GetUserDetailsQuery

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

Database

Infrastructure

Domain

Querying

UI

IUserRepository

ICommand ICommandHandler

ICommandDispatcher

De

pe

nd

en

cy

In

je

ct

io

n

IQuery

IQueryDispatcher

UpdateStatusCommand(Handler)

CommandDispatcherUserRepository

QueryDispatcher

GetUserDetailsQuery

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

Domain

Infrastructure

ICommandDispatcher

CommandDispatcher

ICommand

DeactivateUserCommand

IQuery

QueryDispatcher

IUserRepository

UserRepository

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

using(var tx = session.BeginTransaction()){

try{

var user = repository.GetById<UserDetails>(id);

user.Status = newStatus;

tx.Commit();

return user;}catch{

tx.Rollback();throw;

}}

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

public UpdateUserStatusCommandHandler: ICommandHandler<UpdateUserStatusCommand>

{// ...public void Execute(UpdateUserStatusCommand command){

var user = repository.GetById(command.Id);user.Status = command.NewStatus;

}}

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

public UpdateUserStatusCommandHandler: ICommandHandler<UpdateUserStatusCommand>

{// ...public void Execute(UpdateUserStatusCommand command){

var user = repository.GetById(command.Id);user.Status = command.NewStatus;

}}

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

Robienie CRUDa w CQRSie jest bezsensowne!

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

Robienie CRUDa w CQRSie jest bezsensowne!

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

public DeactivateUserCommandHandler: ICommandHandler<DeactivateUserCommand>

{// ...public void Execute(DeactivateUserCommand command){

var user = repository.GetById(command.Id);

user.Deactivate();}

}

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

READ DB

WRITE Domain ModelCommands

UI

ORM

QueriesSELECT … FROM … WHERE …

WRITE DB

PROJECTION

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

READ DB

WRITE Domain ModelCommands

UI

ORM

QueriesSELECT … FROM … WHERE …

WRITE DB

PROJECTION

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

READ DB

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

READ DB WRITE DB!=

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

READ DB WRITE DB!=

Eager Read Derivation

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

READ DB ==

READ DB

READ DB

READ DB

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

READ DB

WRITE Domain ModelCommands

UI

ORM

QueriesSELECT … FROM … WHERE …

WRITE DB

PROJECTION

Eventual Consistency

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

DB

WRITE Domain ModelCommands

UI

ORM

Queries

SELECT … FROM … WHERE …

READ Model

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

Jak zacząć?

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

Jakiś Framework?

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

Nope!

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

Napisz to sam!

To proste!

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

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();}

}}

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

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();}

}}

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

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);}

}

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

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;}

}

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

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;}

}

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

public class FinalizeTaskCommand{

public FinalizeTaskCommand(TaskId id, UserId finalizingUser) {…}

public TaskId Id { get; private set; }

public UserId FinalizingUser { get; private set; }}

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

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;

}}

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

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);}

}

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

Q&AProsta architektura

dla nieprostego systemu

Mateusz Stasch

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

Dziękuję za uwagę

Prosta architektura dla nieprostego systemu

Mateusz Stasch