Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Prosta architektura dla nieprostego systemu

Matt Stasch
November 17, 2014

Prosta architektura dla nieprostego systemu

Prezentacja, którą pokazałem na 4Developers 2015.
Wstęp do CQRSa i krótkie omówienie tego co sprawia, że z zewnątrz wygląda na trudny - jego niezgodności z tradycyjnym podejściem.

Wcześniej znajdowała się tutaj wersja z Software Craftsmanship Silesia z listopada.

Matt Stasch

November 17, 2014
Tweet

More Decks by Matt Stasch

Other Decks in Programming

Transcript

  1. DB WRITE Domain Model Commands UI DTO DTO ORM Queries

    SELECT … FROM … WHERE … READ Model
  2. READ DB WRITE Domain Model Commands UI DTO DTO Queries

    SELECT … FROM … WHERE … WRITE DB PROJECTION
  3. READ DB WRITE Domain Model Commands UI DTO DTO Queries

    SELECT … FROM … WHERE … PROJECTION Event Stream
  4. 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(); } } }
  5. 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(); } } }
  6. 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); } }
  7. 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); } }
  8. using(var tx = session.BeginTransaction()) { try { var user =

    repository.GetById<UserDetails>(id); user.Status = newStatus; tx.Commit(); return user; } catch { tx.Rollback(); throw; } }
  9. using(var tx = session.BeginTransaction()) { try { var user =

    repository.GetById<UserDetails>(id); user.Status = newStatus; tx.Commit(); return user; } catch { tx.Rollback(); throw; } }
  10. using(var tx = session.BeginTransaction()) { try { var user =

    repository.GetById<UserDetails>(id); user.Status = newStatus; tx.Commit(); return user; } catch { tx.Rollback(); throw; } }
  11. 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; } } } }
  12. 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; } } } }
  13. Database Infrastructure Domain Querying UI D e p e n

    d e n c y I n j e c t i o n IQuery IQueryDispatcher GetUserDetailsQuery
  14. Database Infrastructure Domain Querying UI IUserRepository ICommand ICommandHandler ICommandDispatcher D

    e p e n d e n c y I n j e c t i o n IQuery IQueryDispatcher UpdateStatusCommand(Handler) GetUserDetailsQuery
  15. Database Infrastructure Domain Querying UI IUserRepository ICommand ICommandHandler ICommandDispatcher D

    e p e n d e n c y I n j e c t i o n IQuery IQueryDispatcher UpdateStatusCommand(Handler) CommandDispatcher UserRepository QueryDispatcher GetUserDetailsQuery
  16. using(var tx = session.BeginTransaction()) { try { var user =

    repository.GetById<UserDetails>(id); user.Status = newStatus; tx.Commit(); return user; } catch { tx.Rollback(); throw; } }
  17. public UpdateUserStatusCommandHandler : ICommandHandler<UpdateUserStatusCommand> { // ... public void Execute(UpdateUserStatusCommand

    command) { var user = repository.GetById(command.Id); user.Status = command.NewStatus; } }
  18. public UpdateUserStatusCommandHandler : ICommandHandler<UpdateUserStatusCommand> { // ... public void Execute(UpdateUserStatusCommand

    command) { var user = repository.GetById(command.Id); user.Status = command.NewStatus; } }
  19. READ DB WRITE Domain Model Command s UI ORM Queries

    SELECT … FROM … WHERE … WRITE DB PROJECTION
  20. READ DB WRITE Domain Model Command s UI ORM Queries

    SELECT … FROM … WHERE … WRITE DB PROJECTION
  21. READ DB WRITE Domain Model Command s UI ORM Queries

    SELECT … FROM … WHERE … WRITE DB PROJECTION Eventual Consistency
  22. DB WRITE Domain Model Command s UI ORM Queries SELECT

    … FROM … WHERE … READ Model
  23. 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(); } } }
  24. 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(); } } }
  25. 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); } }
  26. 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; } }
  27. 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; } }
  28. public class FinalizeTaskCommand { public FinalizeTaskCommand(TaskId id, UserId finalizingUser) {…}

    public TaskId Id { get; private set; } public UserId FinalizingUser { get; private set; } }
  29. 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; } }
  30. 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); } }