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

Prosta architektura dla nieprostego systemu

Avatar for Matt Stasch 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.

Avatar for Matt Stasch

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