Problemas comuns de código em microsserviços

Olá pessoal!

Recentemente, em uma conferência da PGConf em Moscou, um dos palestrantes demonstrou uma arquitetura de "microsserviço", mencionando de passagem que todos os microsserviços herdam de uma classe base comum. Embora não houvesse explicações para a implementação, parecia que nesta empresa o termo “microsserviços” não era entendido da mesma maneira que os clássicos pareciam nos ensinar. Hoje, lidaremos com um dos problemas interessantes - qual pode ser o código comum em microsserviços e se é que pode ser?

O que é um microsserviço? Este é um aplicativo independente. Não é um módulo, não é um processo, não é algo que é simplesmente implementado separadamente, mas um aplicativo completo, real e separado. Ele tem sua própria função principal, seu próprio repositório no git, seus próprios testes, sua própria API, seu próprio servidor da web, seu próprio arquivo README, seu próprio banco de dados, sua própria versão, seus próprios desenvolvedores.

Assim como os contêineres, os microsserviços começaram a ser usados ​​quando o poder de computação do HW e a confiabilidade das redes atingiram um nível tal que você pode pagar uma chamada de função que dura 100 vezes mais do que antes, o consumo de memória é 100 vezes maior, o luxo instalar cada "avó" não apenas em um "apartamento" separado, mas em uma "casa" separada. Como qualquer solução arquitetural, a arquitetura dos microsserviços mais uma vez sacrifica o desempenho, ganhando a capacidade de manutenção do código para os desenvolvedores. Mas como a pessoa e a velocidade de sua reação continuaram as mesmas, os sistemas continuam a satisfazer os requisitos.

Por que dividir em aplicativos separados? Porque distribuímos parte da complexidade do sistema já no nível da arquitetura do sistema. Geralmente, o processo de programação é um "passo inicial" da grande "parte da complexidade" inicial, e a decomposição (em classes, módulos, funções e, no nosso caso, aplicativos inteiros) é a implementação de parte dessa complexidade na forma de uma estrutura. Quando dividimos o sistema em microsserviços, tomamos uma decisão arquitetural (bem-sucedida ou não), que os desenvolvedores não precisam mais tomar no futuro ao implementar partes específicas da funcionalidade. Sabe-se que esse microsserviço específico é responsável pelo envio de e-mails, e este - para autorização, já foi estabelecido; portanto, todos os meus novos recursos "caem" nesse padrão sem discussão.

Um aspecto importante dos microsserviços é a falta de conectividade. Os microsserviços devem ser independentes da palavra "completamente". Eles não possuem estruturas de dados comuns e cada microsserviço pode / deve ter sua própria arquitetura, tecnologia, método de montagem (e assim por diante). Por definição. Porque é uma aplicação independente. Alterações no código de um microsserviço não devem afetar os outros de nenhuma maneira, a menos que a API seja afetada. Se eu tiver N microsserviços escritos em Java, não deve haver nenhum fator constrangedor para não gravar o microsserviço N + 1 em Python, se for subitamente lucrativo por algum motivo. Eles são fracamente acoplados e, portanto, um desenvolvedor que começa a trabalhar com um microsserviço específico:

a) Monitora com muita sensibilidade sua API, porque é o único componente visível do lado de fora;
b) sente-se completamente livre na refatoração;
c) Entenda o propósito do microsserviço (lembramos aqui sobre SRP) e implemente uma nova função de acordo;
d) Seleciona o método de persistência mais adequado;
etc.

Tudo isso é bom e soa lógico e harmonioso, como muitas ideologias e teorias (e aqui o teórico ideológico põe fim e vai jantar), mas estamos praticando. O código não precisa ser escrito em martinfowler.com . E mais cedo ou mais tarde nos deparamos com o fato de que todos os microsserviços:

  • informações de log;
  • conter autorização;
  • Acessar agentes de mensagens
  • retorne as mensagens de erro corretas;
  • deve, de alguma maneira, entender as entidades gerais do sistema, se houver;
  • deve trabalhar com um formato de mensagem comum (e protocolo);

e faça de forma idêntica.

E, em algum momento, o arquiteto ideológico começa a trabalhar de manhã e descobre que uma “biblioteca” apareceu no sistema à noite - um novo repositório com um código comum usado em muitos microsserviços. Um arquiteto deveria estar horrorizado?

Isso depende

Para avaliar corretamente a situação, devemos retornar à idéia principal: microsserviços são uma coleção de aplicativos independentes que interagem entre si por meio de uma API (de rede). Nisto, vemos a principal vantagem e simplicidade da arquitetura. E não queremos perder essa vantagem sob nenhuma circunstância. O código geral que foi colocado na "biblioteca" interfere nisso? Vejamos alguns exemplos.

1. A classe de usuário (ou alguma outra entidade comercial) mora na biblioteca.

  • isto é uma entidade comercial não está encapsulada em um microsserviço, mas se espalha de maneira diferente (caso contrário, por que colocá-la em uma biblioteca de códigos compartilhada?);
  • isto é os microsserviços se conectam através dessa entidade comercial, alterando a lógica de trabalhar com uma entidade afetará vários microsserviços;
  • é ruim, muito ruim, não são microsserviços, embora não seja "grande bola de lama", mas muito rapidamente a visão de mundo da equipe levará a "grande bola de lama distribuída";
  • mas os microsserviços no sistema trabalham com os mesmos conceitos, e os conceitos geralmente são entidades ou apenas estruturas com campos, o que devo fazer? Leia DDD, é exatamente como encapsular entidades dentro de microsserviços para que eles não "voem" pela API.

Infelizmente, qualquer lógica comercial colocada em uma biblioteca compartilhada terá esse efeito. As bibliotecas de códigos gerais tendem a crescer, resultando no meio do sistema formando um "tumor" lógico que não pertence a nenhum microsserviço específico, e a arquitetura falha. O "centro de gravidade lógica" do sistema começa a se transformar em um repositório com um código comum, e temos uma mistura infernal de monólito e microsserviços, e não precisamos ir até lá.

2. O código de análise para o formato da mensagem é colocado na biblioteca.

  • O código é mais provável em Java se todos os microsserviços forem gravados em Java;
  • Se amanhã eu escrever um serviço em Python, não poderei usar o analisador, mas parece que não há nenhum problema, escreverei uma versão em Python;
  • Ponto-chave: se estou escrevendo um novo microsserviço em Java, preciso usar esse analisador? Sim, provavelmente não. Talvez eu não seja obrigado, embora, como desenvolvedor de microsserviços, possa ser muito útil. Bem, como se eu tivesse encontrado algo útil no Repositório Maven.

Um analisador de mensagens, um logger aprimorado ou um cliente agrupado para enviar dados para o RabbitMQ - é como auxiliares, componentes auxiliares. Eles estão a par das bibliotecas padrão do NuGet, Maven ou NPM. O desenvolvedor do microsserviço é sempre o rei; ele decide se deve usar a biblioteca padrão ou criar seu próprio código novo ou usar o código da biblioteca auxiliar compartilhada. Como será mais conveniente para ele, porque ele escreve um APP SEPARADO E INDEPENDENTE. Um ajudante em particular pode evoluir? Talvez ele provavelmente tenha versões. Deixe o desenvolvedor se referir a uma versão específica em seu serviço, ninguém o obriga a atualizar o serviço; ao atualizar os auxiliares, essa é uma pergunta para quem suporta o serviço.

3. Interface Java, classe base abstrata, característica.

  • Ou outra peça da categoria de "código rasgado";
  • I.e. Estou aqui, independente e independente, e um pedaço do meu fígado está em outro lugar;
  • Aqui a coerência dos microsserviços no nível do código é exibida, portanto não a recomendamos;
  • Nos estágios iniciais, isso provavelmente não trará problemas tangíveis, mas a essência do projeto arquitetônico é a garantia de conforto (ou desconforto) nos próximos anos.

A equipe que começa a trabalhar em um novo produto estabelece as bases da arquitetura e exerce a maior influência sobre as tendências que o produto terá. Se os princípios de SRP, decomposição bem-sucedida, baixa conectividade etc. forem inicialmente incorporados ao sistema, ele poderá continuar a se desenvolver corretamente. Caso contrário, a aceleração centrífuga dos "fatores do tempo" (outra equipe, pouco tempo, correções urgentes, falta de documentação) lançará esse sistema mais à margem, mais rápido do que parece.

A questão de um código comum em microsserviços permanece difícil porque está associada a algum tipo de compensação: ponderamos o que será mais lucrativo no futuro - o grau de independência dos microsserviços, menos repetições no código, as qualificações dos engenheiros, a simplicidade do sistema etc. Cada vez, essas são reflexões e discussões, que podem levar a diferentes decisões arquitetônicas específicas. No entanto, vamos resumir algumas das recomendações:

Recomendação 0: Não chame microsserviços de nada que esteja dividido em partes existentes independentemente. Nem toda tabela com colunas é uma matriz, vamos usar os termos corretamente.

Recomendação 1: É altamente desejável que os microsserviços não possuam código comum.

Recomendação 2: Se ainda houver um código comum, seja uma coleção (biblioteca) de "auxiliares" opcionais. O desenvolvedor do serviço decide se deve usá-los ou escrever seu próprio código.

Recomendação 3: Sob nenhuma circunstância deve haver lógica comercial no código comum. Toda a lógica de negócios é encapsulada em microsserviços.

Recomendação 4: Deixe a biblioteca de códigos comum ser projetada como um pacote padrão (NuGet, Maven, NPM, etc), com a opção de versionamento (ou, melhor ainda, vários pacotes separados).

Recomendação 5: O "centro de gravidade lógica" do sistema deve sempre permanecer nos próprios microsserviços, e não no código comum.

Recomendação 6: se você planeja escrever no formato de microsserviços, reconcilie antecipadamente que o código entre eles às vezes será duplicado. Até certo ponto, nosso "instinto SECO" natural deve ser suprimido.

Agradecemos sua atenção e microsserviços bem-sucedidos.

Source: https://habr.com/ru/post/pt454100/


All Articles