0% found this document useful (0 votes)
14 views37 pages

Segregating Commands and Queries Slides

segregating-commands-and-queries-slides

Uploaded by

lounes.lou20
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views37 pages

Segregating Commands and Queries Slides

segregating-commands-and-queries-slides

Uploaded by

lounes.lou20
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 37

Segregating Commands and Queries

Vladimir Khorikov

@vkhorikov www.enterprisecraftsmanship.com
Agenda

Scalability
Explicit
Task-based
commands Performance
interface
and queries
Simplicity
Commands in CQS vs. Commands in CQRS

EditPersonalInfo
command
StudentController
EditPersonalInfo
command handler

Moved all logic from


controller to handler
Commands in CQS vs. Commands in CQRS

[HttpPut("{id}")]
public IActionResult EditPersonalInfo(long id, [FromBody] StudentPersonalInfoDto dto)
{
var command = new EditPersonalInfoCommand
{
Email = dto.Email,
Name = dto.Name,
Id = id
};
var handler = new EditPersonalInfoCommandHandler(_unitOfWork);
Result result = handler.Handle(command);

return result.IsSuccess ? Ok() : Error(result.Error);


}
Commands in CQS vs. Commands in CQRS

Command

Controller method Class

[HttpPut("{id}")] public sealed class EditPersonalInfoCommand


public IActionResult EditPersonalInfo( : ICommand
long id, {
[FromBody] StudentPersonalInfoDto dto) public long Id { get; set; }
{ public string Name { get; set; }
/* ... */ public string Email { get; set; }
} }

CQS command CQRS command


Commands in CQS vs. Commands in CQRS

Command is a
serializable method call

Is there an analogy for


command handler?
Commands in CQS vs. Commands in CQRS
public sealed class EditPersonalInfoCommandHandler : ICommandHandler<EditPersonalInfoCommand>
{
public Result Handle(EditPersonalInfoCommand command)
{
var repository = new StudentRepository(_unitOfWork);
Student student = repository.GetById(command.Id);

if (student == null)
return Result.Fail($"No student found for Id {command.Id}");

student.Name = command.Name;
student.Email = command.Email;

_unitOfWork.Commit();

return Result.Ok();
}
}
Commands and Queries in CQRS

Messages

Commands : Tell the application to do something

Queries : Ask the application about something

Events : Inform external applications


Commands and Queries in CQRS

External
applications

Events

Application
Commands Queries

Client
Naming Guidelines

Commands Queries Events

Imperative tense Start with “Get” Past tense

EditPersonalInfo PersonalInfo
GetListQuery
Command ChangedEvent
Naming Guidelines

Command vs. Event

Edit personal info Personal info changed

Server can reject Server can’t


a command reject an event
Naming Guidelines

Commands should use


the ubiquitous language

CreateStudentCommand
CRUD-
UpdateStudentCommand based
thinking
DeleteStudentCommand
Naming Guidelines

EditPersonalInfoCommand

GetListQuery

PersonalInfoChangedEvent

Naming convention is enough


to distinguish between them
Commands and Queries in the Onion Architecture
Entities
Aggregates
Value Objects Core
Domain Events domain
Pure Domain
Services

Repositories Non-core
Impure Domain domain
Services

Application
Services
Non-
UI domain
Commands and Queries in the Onion Architecture

All messages are part


of the core domain

Command = An operation to do

Query = A question to ask

Event = An outcome for external apps


Commands and Queries in the Onion Architecture

Commands

Trigger reaction

Push model

Command Core Domain Events


Events

Result of the reaction

Pull model
Commands and Queries in the Onion Architecture
Entities
Aggregates
Value Objects Should be isolated
Domain Events from the outside world
Pure Domain
Services

Repositories
Impure Domain
Services

Application
Services Command handlers
UI go here
Commands vs. DTOs
[HttpPut("{id}")]
public IActionResult EditPersonalInfo(long id, [FromBody] StudentPersonalInfoDto dto) {
var command = new EditPersonalInfoCommand {
Email = dto.Email, Name = dto.Name, Id = id
};
var handler = new EditPersonalInfoCommandHandler(_unitOfWork);
Result result = handler.Handle(command);

return result.IsSuccess ? Ok() : Error(result.Error);


}

[HttpPut("{id}")]
public IActionResult EditPersonalInfo( [FromBody] EditPersonalInfoCommand command) {
var handler = new EditPersonalInfoCommandHandler(_unitOfWork);
Result result = handler.Handle(command);

return result.IsSuccess ? Ok() : Error(result.Error);


}
Commands vs. DTOs

Commands and DTOs


tackle different problems
Commands vs. DTOs

Commands DTOs

Serializable
Data contracts
method calls

Backward
compatibility
Commands vs. DTOs

Commands DTOs

Mapping

Backward compatible

Easy to refactor
Commands vs. DTOs

The use of commands The use of entities


as DTOs = as DTOs

Hinder refactoring
Commands vs. DTOs

public sealed class EditPersonalInfoCommand : ICommand


{
public long Id { get; } FirstName
public string Name { get; }
public string Email { get; } LastName
public EditPersonalInfoCommand(long id, string name, string email)
{
Id = id;
Name = name;
Email = email;
}
}

Can’t modify the command


Commands vs. DTOs

Backward
DTOs = compatibility

Actions upon
Commands = the application
Commands vs. DTOs

It’s fine not to have


DTOs if you don’t need
backward compatibility

A single client which


you develop yourself

Can deploy both the API and


the client simultaneously
Recap: Introducing Commands and Queries

Refactored the student


controller

Uses explicit command and


query objects

In theory, you could even


remove the controller
Recap: Introducing Commands and Queries

[HttpPut("{id}")]
public IActionResult EditPersonalInfo(
long id, [FromBody] StudentPersonalInfoDto dto)
{
var command = new EditPersonalInfoCommand(id, dto.Email, dto.Name);
Result result = _messages.Dispatch(command);

return FromResult(result);
}

Use the controller for ASP.NET wiring only


Recap: Introducing Commands and Queries
public sealed class Messages
{
private readonly IServiceProvider _provider;

public Messages(IServiceProvider provider)


{
_provider = provider;
}

public Result Dispatch(ICommand command)


{
Type type = typeof(ICommandHandler<>);
Type[] typeArgs = { command.GetType() };
Type handlerType = type.MakeGenericType(typeArgs);

dynamic handler = _provider.GetService(handlerType);


Result result = handler.Handle((dynamic)command);

return result;
}
}
Recap: Introducing Commands and Queries

public void ConfigureServices(IServiceCollection services)


{
services.AddMvc();

services.AddSingleton(new SessionFactory(Configuration["ConnectionString"]));
services.AddTransient<UnitOfWork>();
services.AddTransient<ICommandHandler<EditPersonalInfoCommand>, EditPersonalInfoCommandHandler>();
services.AddTransient<ICommandHandler<RegisterCommand>, RegisterCommandHandler>();
services.AddTransient<ICommandHandler<UnregisterCommand>, UnregisterCommandHandler>();
services.AddTransient<ICommandHandler<EnrollCommand>, EnrollCommandHandler>();
services.AddTransient<ICommandHandler<TransferCommand>, TransferCommandHandler>();
services.AddTransient<ICommandHandler<DisenrollCommand>, DisenrollCommandHandler>();
services.AddTransient<IQueryHandler<GetListQuery, List<StudentDto>>, GetListQueryHandler>();
services.AddSingleton<Messages>();
}
Recap: Introducing Commands and Queries
public interface ICommand public interface IQuery<TResult>
{ {
} }

public interface ICommandHandler<TCommand> public interface IQueryHandler<TQuery, TResult>


where TCommand : ICommand where TQuery : IQuery<TResult>
{ {
Result Handle(TCommand command); TResult Handle(TQuery query);
} }

Success of failure
public sealed class GetListQuery :
IQuery<List<StudentDto>>
{
/* ... */
}
Recap: Introducing Commands and Queries

public interface ICommandHandler<TCommand>


where TCommand : ICommand
{
Result Handle(TCommand command);
}

public interface IQueryHandler<TQuery, TResult>


where TQuery : IQuery<TResult>
{
Result<TResult> Handle(TQuery query);
}
Refactored towards explicit commands and
queries
Introduced unified interface for command
and query handlers

Summary Leveraged ASP.NET dependency injection


mechanism for resolving the handlers

Difference between commands and queries


in CQS and CQRS taxonomies
- CQS: command is a method that mutates
state
- CQRS: command represents what you can
do with the application
Command: serializable method call

Command handler: an ASP.NET controller


with a single method that is a CQS command
Messages: commands, queries, and events
- Command tells the application to do
something
Summary - Query asks the application about
something
- Event is an informational message

Name all 3 types of messages properly:


- Commands should be in the imperative
tense
- Events should be in the past tense
- Queries: same as commands, start with
"Get“
Commands and queries in the onion
architecture
- Commands, queries, and events should
Summary reside in the core domain layer
- Commands: push model
- Events: pull model

Commands vs DTOs
- DTOs help achieve backward
compatibility
- Commands explicitly state what the
application can do
In the Next Module

Implementing decorators upon


command and query handlers

You might also like