Single Blog

Fail Fast Validations em Commands no CQRS

Como você trata as validações na sua API quando trabalhamos com DDD e CQRS? Será que conseguimos otimizar estas validações antecipando suas falhas?

Validar as informações da nossa UI é algo imprescindível em nossas aplicações. Sempre devemos fazer a checagem do lado do servidor, visto que o JavaScript pode ser burlado, ou o usuário até mesmo pode utilizar aplicativos como Postman para simular requisições a nossas APIs sem passar pelas validações da UI.

Sabemos que o uso dos princípios do DDD e da implementação do CQRS tornam nossas aplicações mais robustas e blá blá blá, mas também sabemos que o o cliente gosta muito daquilo que vê, e da praticidade, performance e responsividade da aplicação. Então como balancear estes mundos?

Fail Fast

Trabalhando com CQRS, temos os inputs como Commands (Comandos), que serão manipulados pelos Command Handlers, onde será criada o fluxo, entidade e persistência do que for necessário.

Sabemos que devemos tratar a complexidade no coração do Software, ou seja, no domínio, mas será que não podemos melhorar as respostas das nossas APIs?

Vamos pegar um cenário bem comum, de um pedido de compra, onde recebemos o usuário autenticado, um Id de um produto e uma determinada quantidade do mesmo, como um comando para dar início ao fluxo.

Temos que validar se o produto existe, se a quantidade existe, se a mesma é válida, se o usuário é válido e por aí vai.

A questão aqui é, quais destas validações podemos antecipar, e assim já retornar ao usuário, de forma rápida, sem mesmo consultar o banco de dados, quais itens já falhariam.

De cara, conseguimos imaginar, que uma quantidade menor que zero falharia antes mesmo de chegar ao domínio, que um Id inválido (Seja ele um inteiro ou um Guid) falharia da mesma forma, para o produto e para o usuário.

Sendo assim, precisamos mesmo descer até o domínio para fazer simples validações de inputs?

O Fail Fast (Falhar Rapidamente) é justamente esta abordagem, onde temos as validações dos inputs do Command sendo feitas antes de qualquer coisa em nossos Controllers, e, caso elas falhem, já retornamos para o usuário na hora! Muito mais rápido e prático.

Evite Exceptions

Bom, já conversamos sobre este assunto antes, correto? As Exceptions geram um custo excessivo para máquina e sempre interrompem a execução, causando uma parada a cada exceção. Imagina um cadastro de usuário com 30 validações sendo executadas uma a uma? O usuário não iria gostar.

Pois bem, temos uma maneira mais simples de implementar a troca de mensagens, por meio do Notification Pattern, como descrito pelo Martin Fowler (http://martinfowler.com/articles/replaceThrowWithNotification.html).

O Notification Pattern é algo bem simples, na verdade já substitui ele em vários cenários por apenas um Dicionário (Chave/Valor), mas é interessante ter um objeto para notificação para facilitar a vida.

Sendo assim, vamos criar a classe Notification.cs.

Você pode incrementar mais sua classe, com data/hora, GUID e afins, mas eu prefiro manter simples, até por que serializaremos as notificações como JSON para retorno a UI posteriormente.

Implementando as notificações

O Notification Pattern é um padrão de troca de mensagens que não necessariamente deve pertencer a uma camada ou coisa do tipo. Podemos utilizá-lo em diversos lugares, e pensando nisso, vamos criar uma classe abstrata (Que não pode ser instanciada, apenas herdada), onde faremos as implementações básicas como adicionar notificações e obter as notificações.

Para isto, vamos criar a classe Notifiable.cs.

Aplicando as validações nos Commands

Quem acompanha os cursos do site e artigos por aqui sabe que gosto bastante das implementações do Vernon Vaughan, incluindo o Assertion Concern, que ele mostra no livro Implementing Domain Driven Design.

Os Assertions nada mais são do que validações mais elegantes, parecidas com os antigos Contracts, mas que retornam notificações. Para este exemplo, vou utilizar meu Assert que está no meu GitHub. Isto vai evitar aquele monte de IFs no código, e permitir testes mais bonitos <3.

Então vamos criar o comando para registrar um novo usuário, e incluir nele um método IsValid (Contido na interface ICommand), que fará a validação dos inputs. A classe RegisterCustomer.cs também herda de Notifiable, que acabamos de criar, o que adiciona a ela as notificações.

Pronto, simples assim temos uma validação rápida e prática, que vai evitar processamento e as vezes até acesso à banco na API.

Validando o comando na API

Com tudo pronto, basta validar o comando chamando o método IsValid como mostrado na linha 5 abaixo.

Considerações

Falhar rapidamente é uma excelente estratégia quando falamos de performance na validação dos inputs. Neste modelo, temos o mínimo de processamento, otimizando o retorno para o usuário.

Porém, temos que ter cuidado para cenários onde temos a validação em múltiplos contextos, afinal, podem haver falhas no input, que acarretariam em um retorno precoce para o usuário, sem as validações do domínio.

De qualquer forma, você pode aplicar o Notification Pattern nos Commands, CommandHandlers, Entidades, Value Objects e por aí vai. Inclusive você pode omitir a validação, basta não chamar o método IsValid.

E aí, o que achou desta implementação? O que você mudaria ou acrescentaria?

Comments (3)

Post a Comment

© Copyright - balta.io