Me deparei com o design de Event Sourcing e gostaria de usá-lo em um aplicativo em que um cliente REST é necessário (RESTful para ser preciso). No entanto, não consigo conectá-los, pois o REST é bastante CRUD e a fonte de eventos é baseada em tarefas. Eu queria saber como você pode projetar a criação de comandos com base em solicitações ao servidor REST. Considere este exemplo:
Com o REST, você pode colocar um novo estado no recurso chamado Arquivo. Em uma solicitação, você pode enviar um novo nome de arquivo, alterar a pasta pai e / ou alterar o proprietário do arquivo e assim por diante.
Como construir o servidor para que eu possa usar a fonte de eventos. Eu estava pensando sobre estas possibilidades:
Determinar no servidor que os campos foram alteradas e criar comandos apropriados (
RenameFileCommand
,MoveFileCommand
,ChangeOwnerCommand
, ...) e despachar estes individualmente. No entanto, nessa configuração, cada um dos comandos pode falhar, deixando outros fora da transação e, portanto, fora da alteração "atômica" do recurso.Despacho apenas um comando (
UpdateFileCommand
) e no manipulador de comando, mais precisamente, no total, determinar quais campos foram alterados e enviar eventos individuais em vez (FileRenamedEvent
,FileMovedEvent
,OwnerChangedEvent
, ...)Este não é o que eu mais gosto: na solicitação ao servidor, especificaria nos cabeçalhos que comando usar, porque a interface do usuário ainda é baseada em tarefas (mas a comunicação é feita via REST). No entanto, ele falhará em qualquer outro uso da comunicação REST (por exemplo, em aplicativos externos), pois eles não são obrigados a alterar apenas o campo único em uma solicitação. Também trago um grande acoplamento ao back-end baseado em UI, REST e ES.
Qual você prefere ou existe alguma maneira melhor de lidar com isso?
Nota lateral: aplicativo escrito em Java e Axon Framework para fornecimento de eventos.
fonte
Respostas:
Eu acho que você pode ter um processo de usuário para incompatibilidade de implementação aqui.
Primeiro: um usuário honestamente deseja executar várias alterações em um arquivo simultaneamente? Uma renomeação (que pode ou não incluir uma mudança de caminho?), Mudança de propriedade e talvez alteração do conteúdo do arquivo (por uma questão de argumento) parecem ações separadas.
Vamos considerar o caso em que a resposta é "sim" - seus usuários realmente desejam fazer essas alterações simultaneamente.
Nesse caso, eu recomendo fortemente contra qualquer implementação que envia vários eventos -
RenameFileCommand
,MoveFileCommand
,ChangeOwnerCommand
- para representar essa única intenção do usuário.Por quê? Porque os eventos podem falhar. Talvez seja extremamente raro, mas seu usuário enviou uma operação que parecia atômica - se um dos eventos posteriores falhar, o estado do seu aplicativo agora é inválido.
Você também está convidando riscos de corrida em um recurso claramente compartilhado entre cada um dos manipuladores de eventos. Você precisará escrever "ChangeOwnerCommand" de forma que o nome e o caminho do arquivo não importem, pois podem estar desatualizados no momento em que o comando é recebido.
Ao implementar um sistema tranqüilo não orientado a eventos com arquivos em movimento e renomear, prefiro garantir consistência usando algo como um sistema eTag - verifique se a versão do recurso que está sendo editado é a versão que o usuário recuperou pela última vez e falha se foi modificado desde então. Mas se você estiver despachando vários comandos para esta operação de usuário único, precisará incrementar a versão do recurso após cada comando - para que você não tenha como saber que o recurso que o usuário está editando é realmente a mesma versão do recurso que foi lido pela última vez .
O que quero dizer com isso é - e se outra pessoa executar outra operação no arquivo quase ao mesmo tempo. Os 6 comandos podem ser empilhados em qualquer ordem. Se tivéssemos apenas 2 comandos atômicos, o comando anterior poderia ter sucesso e o comando posterior poderia falhar "o recurso foi modificado desde a última vez que foi recuperado". Mas não há proteção contra isso quando os comandos não são atômicos, portanto a consistência do sistema é violada.
Curiosamente, existe um movimento em direção a algo como a arquitetura baseada em eventos no REST, chamada "Descansar sem PUT", recomendada no radar da tecnologia Thoughtworks, janeiro de 2015 . Há um blog consideravelmente mais longo sobre o Rest without PUT aqui .
Essencialmente, a idéia é que POST, PUT, DELETE e GET sejam adequados para aplicativos pequenos, mas quando você precisar começar a supor que a colocação, a postagem e a exclusão podem ser interpretadas na outra extremidade, você introduz o acoplamento. (por exemplo, "quando EXCLUIR o recurso associado à minha conta bancária, a conta deve ser fechada") E a solução proposta é tratar o REST de uma maneira mais originada por evento. Permite POST a intenção do usuário como um único recurso de evento.
O outro caso é mais simples. Se seus usuários não quiserem executar todas essas operações simultaneamente, não permita. POST um evento para cada intenção do usuário. Agora você pode usar o etag versioning em seus recursos.
Quanto aos outros aplicativos que estão usando uma API muito diferente dos seus recursos. Isso cheira a problemas. Você pode construir uma fachada da API antiga em cima da API RESTful e apontá-las para a fachada? expor um serviço que executa várias atualizações em um arquivo em sequência através do servidor REST?
Se você não criar a interface RESTful na parte superior da solução antiga, nem construir uma fachada da interface antiga na parte superior da solução REST e tentar manter as duas APIs apontando para um recurso de dados compartilhado, ocorrerá grandes dores de cabeça.
fonte
Acabei de ler o artigo a seguir, que incentiva a especificação dos nomes de comando na solicitação ao servidor no cabeçalho Content-Type (enquanto segue 5 níveis do tipo de mídia).
No artigo, eles mencionam que o estilo RPC é ruim para o REST e sugerem a extensão do Content-Type para especificar o nome do comando:
O artigo está aqui: http://www.infoq.com/articles/rest-api-on-cqrs
Você pode ler mais sobre 5 níveis de tipo de mídia aqui: http://byterot.blogspot.co.uk/2012/12/5-levels-of-media-type-rest-csds.html
Embora eles estejam expondo os eventos de domínio à API REST, o que eu consideraria uma prática ruim, gosto da solução, pois ela não cria um novo "protocolo" apenas para o CQRS, seja enviando nomes de comandos no corpo ou extra cabeçalho e permanece fiel aos princípios RESTful.
fonte