A modularidade dos sistemas que estamos construindo é muito importante, mas para atingi-la devemos lidar com forças que são contra a modularidade. Aumentar a dívida técnica pegando atalhos e dividindo um sistema em microservices sem considerar os domínios de negócios, são duas destas forças. Em uma apresentação na Conferência de Microservices Orientada a Eventos em Amsterdã, realizada pela AxonIQ, Allard Buijze compartilhou os pensamentos e experiências na construção de sistemas baseados em DDD, CQRS, microservices e event sourcing.
Para Buijze, CTO da AxonIQ, outro exemplo de anti modularidade é o design orientado a substantivos. Normalmente, é usado para encontrar os objetos em uma aplicação, mas, em vez dos objetos, estamos criando serviços. Se precisarmos reimplantar vários serviços de uma só vez, ou se um serviço depender de outros serviços antes de poder executar as tarefas, passou de um monólito para um monólito distribuído, com todos os problemas inerentes desta arquitetura, ao invés de uma arquitetura de microservices adequada.
Segundo Buijze, mudar para microservices é uma jornada. Não devemos passar de um modelo de negócios para os microservices em uma única etapa. Pelo contrário, devemos começar com um monolito bem estruturado e modular, para então, conforme a necessidade, com calma, separar os microservices, um por um. Buijze enfatiza que a necessidade de criar um microservice deve sempre vir de requisitos não funcionais.
O ingrediente mais importante necessário para transformar componentes em microservices é a transparência da localização. Um componente não deve estar ciente, nem fazer suposições sobre a localização de um componente com o qual interage. Isso significa que um componente pode ser extraído e pode se tornar um serviço sem a necessidade de reescrever a comunicação entre os demais existentes, inclusive este novo serviço.
Os eventos são uma maneira comum de resolver a transparência da localização. Ao invés de um serviço chamar diretamente os demais com os quais deseja interagir, pode publicar um evento e qualquer pessoa interessada pode ouvir. Buijze ressalta que um aspecto importante do uso de eventos é que invertemos a dependência, os componentes ou serviços que assinam eventos agora estão indiretamente ouvindo ao serviço emissor de eventos.
Um erro comum que Buijze experimentou ao usar apenas eventos, é que os eventos também são usados para solicitar indiretamente que algo aconteça em outro serviço. Isso aumenta o acoplamento entre eles, possivelmente com dependências bidirecionais, e isso pode criar uma coreografia muito complicada, como neste exemplo, em que nenhum serviço é responsável pelo processo de negócios:
Existem diferentes razões pelas quais os componentes desejam se comunicar. Além dos eventos, precisamos de dois outros tipos de mensagens, os comandos que representam a intenção de alterar algo e as consultas para atender à necessidade de informações. No exemplo anterior, os serviços de pedidos podem usar comandos para solicitar pagamentos e envio, e o serviço de remessas pode usar uma consulta para solicitar detalhes do pedido. Buijze recomenda que consideremos os comandos e as consultas tanto quanto consideramos os eventos.
Outro conceito relacionado a eventos é o event sourcing, no qual um componente não armazena o estado das entidades, mas todos os eventos que levaram ao estado para cada entidade. Para Buijze, event sourcing consiste em capturar a verdade, toda a verdade e nada além da verdade. Mas é necessário ressaltar que, a menos que façamos isso corretamente, não podemos garantir que possuímos toda a verdade. Um teste para verificar se estamos executando o event sourcing corretamente é jogar tudo fora, exceto o armazenamento de eventos. Se ainda conseguirmos reproduzir o estado da aplicação, estaremos realizando o event sourcing. Segundo Buijze para que isso funcione em um serviço, o serviço deve usar os eventos que publica para o próprio estado de maneira consistente.
O event sourcing tem alguns benefícios, tanto do ponto de vista comercial quanto técnico. A auditoria e a fonte única da verdade são dois exemplos. Também existem desafios, como o aumento do tamanho do armazenamento e o fato de poder ser complexo de implementar, embora Buijze acredite que esses desafios sejam algo do passado. O verdadeiro desafio é o pensamento de eventos, mas os eventos são uma maneira muito mais natural de pensar sobre o comportamento de uma aplicação, por isso, o palestrante recomenda que esqueçamos o estado e nos concentremos no comportamento. É muito mais fácil entender o que um aplicativo está fazendo ao utilizar os eventos e os comandos, porque descrevem o que o aplicativo faz de maneira funcional. Mas é recomendado que não utilizemos o event sourcing para todas as tarefas. Isto é uma ferramenta que, como outras, só deve ser usada onde faz sentido.
Buijze conclui enfatizando que toda comunicação é uma forma de contrato. Uma desvantagem dos eventos é que temos um contrato com muitos componentes desconhecidos. Portanto, devemos restringir o escopo dos eventos e dos contratos. Precisamos evitar o acoplamento em contextos limitados, pois todos os serviços falam a mesma língua e podem entender todos os eventos, mas muitos eventos, especialmente os event sourcings, são úteis apenas dentro do contexto e não devem ser publicados para o exterior. Eventos publicamente interessantes, talvez devam ser transformados em novos eventos para se adaptarem a uma API pública.
Em um post de 2015, Martin Fowler escreveu que havia notado um padrão em que quase todas as histórias de microservices bem sucedidas começaram com um monolito. Pouco tempo depois, Stefan Tilkov escreveu uma postagem num blog informando que está firmemente convencido de que, quando o objetivo é uma arquitetura de microservices, começar com um monolito, geralmente, é exatamente a coisa errada a se fazer.
Em uma apresentação no DDD Europe 2019, Eric Evans descreveu diferentes tipos de contextos limitados, alguns podem ser especialmente úteis em um sistema baseado em eventos.