Estrutura para evolução

Uma conceção evolutiva é a chave para a inovação contínua

Todas as aplicações bem sucedidas mudam ao longo do tempo, quer seja para corrigir erros, adicionar novas funcionalidades, incorporar novas tecnologias ou tornar os esquemas existentes mais dimensionáveis e resilientes. Se todas as partes de uma aplicação estiverem fortemente conjugadas, torna-se muito difícil introduzir as alterações no sistema. A alteração de uma parte da aplicação pode interromper outra parte ou fazer com que as alterações oscilem por toda a base de código.

Este problema não se limita às aplicações monolíticas. Uma aplicação pode estar decomposta em serviços, mas continuar a apresentar o tipo de acoplamento forte que faz com que o sistema fique rígido e frágil. Mas, quando os serviços são concebidos para evoluir, as equipas podem inovar e fornecer continuamente novas funcionalidades.

Os microsserviços estão a tornar-se uma forma popular de alcançar um design evolutivo, porque abordam muitas das considerações aqui listadas.

Recomendações

Imponha coesão elevada e acoplamento alargado. Um serviço é coeso se fornecer funcionalidades que estão interligadas logicamente. Os serviços são relativamente acoplados se for possível alterar um serviço sem alterar o outro. A elevada coesão geralmente significa que as alterações numa função exigirão alterações noutras funções relacionadas, em que todas as funções relacionadas residem num serviço. Se chegar à conclusão que atualizar um serviço requer atualizações coordenadas de outros serviços, poderá ser um sinal de que os serviços não são coesos. Um dos objetivos do design orientado pelo domínio (DDD) é identificar esses limites.

Encapsule o conhecimento do domínio. Quando um cliente consome um serviço, a responsabilidade de impor as regras de negócio do domínio não deve recair sobre o cliente. Em vez disso, o serviço deve encapsular todo o conhecimento do domínio que seja da respetiva responsabilidade. Caso contrário, todos os clientes têm de impor as regras de negócio e acaba por ficar com dados de conhecimento do domínio distribuídos por diferentes partes da aplicação.

Utilize mensagens assíncronas. As mensagens assíncronas são uma forma de separar o produtor de mensagens do consumidor. O produtor não depende do consumidor que responde à mensagem ou efetua qualquer ação específica. Com uma arquitetura de pub/sub, o produtor nem sequer sabe quem está a consumir a mensagem. Os novos serviços podem facilmente consumir mensagens sem modificações para o produtor.

Não incorpore dados de conhecimento do domínio num gateway. Os gateways podem ser úteis numa arquitetura de microsserviços, para ações como o encaminhamento de pedidos, tradução de protocolos, balanceamento de carga ou autenticação. No entanto, o gateway deve restringir-se a este tipo de funcionalidade de infraestrutura. Não deve implementar qualquer conhecimento de domínio, para evitar tornar-se uma dependência pesada.

Exponha interfaces abertas. Evite criar camadas de tradução personalizadas que ficam entre serviços. Em vez disso, um serviço deve expor uma API com um contrato de API bem definido. A API deve ter versão, para que possa evoluir a API, mantendo a retrocompatibilidade. Dessa forma, pode atualizar um serviço sem coordenar as atualizações para todos os serviços a montante que dependem dele. Os serviços destinados ao público devem expor uma API RESTful através de HTTP. Os serviços de back-end poderão utilizar um protocolo de mensagens de estilo RPC por motivos de desempenho.

Conceba e teste os contratos de serviço. Quando os serviços expõem APIs bem definidas, pode desenvolver e testar essas APIs. Dessa forma, pode desenvolver e testar um serviço individual sem lançar todos os serviços dependentes. (Obviamente, teria na mesma de efetuar testes de integração e de carga nos serviços reais.)

Abstraia a infraestrutura da lógica do domínio. Não permita que a lógica do domínio se misture com funcionalidades relacionadas com a infraestrutura, como as mensagens ou a persistência. Caso contrário, as alterações da lógica do domínio irão requerer atualizações das camadas de infraestrutura e vice-versa.

Passe as questões transversais para um serviço separado. Por exemplo, se vários serviços tiverem de autenticar pedidos, poderia mover esta funcionalidade para o seu próprio serviço. Em seguida, pode evoluir o serviço de autenticação ( por exemplo, ao adicionar um novo fluxo de autenticação - sem tocar em nenhum dos serviços que o utilizam.

Implemente os serviços de modo independente. Quando a equipa de DevOps consegue implementar um único serviço independentemente dos outros serviços na aplicação, as atualizações podem acontecer mais rapidamente e em segurança. As correções de erros e novas funcionalidades podem ser implementadas a uma cadência mais regular. Conceba a aplicação e o processo de lançamento para que suportem atualizações independentes.