Papo de arquitetura: monólito ou microsserviços?

Osvaldo Zonetti
Geekie Educação
Published in
9 min readApr 23, 2024
Monólito vs Microsserviço

Quando estamos iniciando o desenvolvimento de uma aplicação backend, chega um momento em que nos perguntamos: e agora? como devo estruturar minha aplicação?

Também é neste momento que percebemos a importância do processo de arquitetura de software, pois de nada adianta termos todo o conhecimento, ferramentas e recursos necessários à nossa disposição, se não formos capazes de discernir, dentre todas as opções disponíveis, o que mais faz sentido para nosso projeto. Definitivamente, não é uma ciência exata, mas sim um trabalho que requer bastante ponderação e criatividade.

Atualmente, se tratando de arquitetura de software, temos duas grandes escolas de pensamento: a arquitetura monolítica e a arquitetura de microsserviços. Neste artigo, vamos entender a diferença entre essas abordagens e quem sabe, de uma vez por todas, sanar as dúvidas relacionadas ou pelo menos servir como um ponto de apoio e reflexão. Afinal, cada caso é um caso e nós, enquanto pessoas desenvolvedoras e arquitetas de software, somos responsáveis por determinar o que é mais adequado para nosso cenário.

Também vale ressaltar que, independente da arquitetura que escolhemos para nossas aplicações, sempre vão existir pontos fortes e fracos, pois quando fazemos uma escolha estamos por definição renunciando as outras opções, isso se chama custo de oportunidade. Além disso, a complexidade é uma constante, quando simplificamos algo, estamos na verdade meramente movendo a complexidade para outro lugar, mas ela não deixa de existir, por isso toda e qualquer arquitetura possuirá vantagens e desvantagens.

Arquitetura monolítica

Imagine um grande bloco de pedra, isso é um monólito. Porém, para fins didáticos, acho que seria interessante utilizarmos uma outra analogia, pois é um pouco difícil comparar software com um bloco de pedra 😅.

Imagine uma grande máquina com várias telas, botões e alavancas. Essa máquina satisfaz muito bem o propósito para o qual ela foi construída, no entanto, sempre que precisamos adicionar alguma funcionalidade ou fazer alguma manutenção, temos bastante trabalho: precisamos desmontá-la, entender perfeitamente onde precisamos implementar a modificação ou o ajuste necessário, montá-la novamente e torcer para que tudo continue funcionando em harmonia, pois uma característica inerente dessa “grande máquina” é que todas as peças em seu interior dependem fortemente umas das outras, de modo que falhas críticas podem comprometer todo o seu funcionamento.

A princípio, pode parecer problemático construir e dar manutenção em uma “grande máquina”, mas na verdade existem diversas vantagens:

  • Iniciar é mais simples: iniciar o desenvolvimento de um monólito dispensa configurações complexas, pois na maioria dos casos precisamos apenas de um banco de dados como recurso externo ao código. Portanto, nossas preocupações são basicamente definir as entidades e relacionamentos que serão persistidas e estruturar o nosso código, algo que muitas linguagens de programação e frameworks já orientam com base em exemplos, padrões mais comumente utilizados e boas práticas.
  • Facilidade de testar: ainda que a tendência de um monólito seja crescer e se tornar cada vez mais complexo à medida do tempo, isso não quer dizer que a base de código também precise se tornar mais complexa e difícil de compreender, é perfeitamente possível um monólito consideravelmente grande ser bem estruturado de modo que ainda seja fácil de manter e testar, isso porque como todas as partes do sistema estão fortemente conectadas, a criação de testes mais abrangentes como testes de integração se torna mais fácil.
  • Facilidade de documentar: por se tratar de apenas um projeto, na maioria dos casos, um monólito é mais fácil de ser documentado, seja com documentações dentro da própria base de código como anotações, comentários, arquivos de instruções ou mesmo formatos exportáveis como especificações de API. O fato do código estar centralizado em um ou poucos projetos reduz bastante a carga cognitiva necessária para que um time de desenvolvimento compreenda e documente a aplicação.
  • Facilidade de implantar: implantar um monólito costuma ser uma tarefa bastante simples quando comparada à uma implantação de microsserviços, especialmente se considerarmos a utilização de algum provedor de serviços cloud como Amazon Web Services, Google Cloud, Microsoft Azure ou Vercel por exemplo. Nesses casos, basta configurarmos o banco de dados e subir a aplicação através de um pipeline de CI/CD geralmente disponibilizado pelo próprio provedor.

Como não poderia deixar de ser, a arquitetura monolítica também possui algumas desvantagens:

  • Menos resiliência: apesar da natureza centralizada do monólito ser vista como um ponto forte quando se trata de encontrar bugs, criar testes e documentar, ela também traz alguns pontos negativos se considerarmos que o funcionamento de todo o sistema depende de uma única aplicação, isto é, qualquer falha crítica em alguma estrutura global na aplicação pode comprometer todo o seu funcionamento, causando erros generalizados e, consequentemente, resultando na disrupção do serviço. E não estamos falando apenas de problemas no código, problemas de infraestrutura como falta de espaço de armazenamento, CPU, memória e oscilações na rede também podem comprometer todo o sistema da mesma forma.
  • Falta de modularidade: devido ao monólito ser fortemente acoplado, isto é, todos os seus módulos estarem interligados ao ponto de dependerem uns dos outros, existe uma certa dificuldade para se paralelizar o desenvolvimento da aplicação em uma equipe com várias pessoas ou entre várias equipes. Por mais que hoje tenhamos ferramentas que nos possibilitam versionar e manipular uma mesma base de código em paralelo como o Git por exemplo, quando precisamos adicionar um novo comportamento ou modificar um comportamento existente em um monólito, para termos a garantia de que não haverá impactos negativos nos demais módulos ou com outras implementações que também estão sendo desenvolvidas em paralelo, é importante que a mudança em questão já considere todas as adaptações necessárias em outros módulos impactados, ou que em algum momento seja feito um merge de todas as modificações para que tudo seja validado em conjunto.
  • Dificuldade de escalar: por se tratar um grande bloco de pedra, digo, uma “grande máquina”, é natural que para escalar uma aplicação monolítica geralmente seja necessário aumentar o "tamanho da máquina" ao invés de aumentar a quantidade de máquinas, isso porque a aplicação demanda recursos para funcionar (espaço de armazenamento, CPU ou memória) e, no caso de um monólito, muito recurso. Portanto, em uma arquitetura monolítica, a escalabilidade vertical costuma ser uma necessidade pois, como o sistema é composto por uma única aplicação que tende a continuar crescendo, a demanda por recursos acaba rapidamente se tornando um gargalo. A escalabilidade é relativa pois varia muito de aplicação para aplicação, mas assumindo um dado escopo, podemos dizer que, de modo geral, escalar um monólito tende a ser mais custoso do que escalar microsserviços, devido à quantidade de recurso demandada pelo sistema.

Arquitetura de microsserviços

Seguindo a mesma linha de raciocínio que utilizamos para descrever a arquitetura monolítica, vamos imaginar agora uma sala repleta de pequenas máquinas interligadas por uma rede de cabos e, logo na entrada da sala, uma dessas pequenas máquinas se encontra em evidência e possui as mesmas telas, botões e alavancas da máquina monolítica, vamos chamar esse conjunto de máquinas operando em sinergia de “máquina de microsserviços”.

Só para deixar claro nossa analogia: ambas as máquinas (monolítica e de microsserviços) possuem as mesmas telas, botões e alavancas, ou seja, fazem exatamente a mesma coisa, a diferença está em como elas são estruturadas.

Imaginando que acabamos de visualizar ambas as máquinas e estamos tentando definir quais são as maiores semelhanças e diferenças entre elas, a primeira coisa que nos vem à cabeça é que as máquinas ocupam praticamente o mesmo espaço, a diferença sendo que a máquina monolítica é um grande bloco, enquanto a máquina de microsserviços é um conjunto de pequenas máquinas mas que se sobrepostas também formariam um grande bloco. Consequentemente, também podemos concluir que a maior diferença entre as máquinas é a quantidade de componentes observados e a superfície de contato: enquanto na máquina monolítica só conseguimos ver e tocar um objeto, na máquina de microsserviços conseguimos ver e tocar vários objetos.

Olhando por essa perspectiva, conseguimos constatar as seguintes vantagens da arquitetura de microsserviços:

  • Desacoplamento: cada serviço é independente e pode ser desenvolvido, implantado e escalado separadamente, isso permite uma maior flexibilidade e facilita a manutenção e evolução do sistema, já que mudanças em um serviço não afetam necessariamente os outros.
  • Maior escalabilidade: uma característica inerente do desacoplamento é a capacidade de escalar serviços individualmente conforme a demanda, o que possibilita otimizar recursos e lidar com picos de tráfego em partes específicas do sistema evitando escalar outros serviços desnecessariamente, consequentemente tornando o uso de recursos mais eficiente.
  • Maior resiliência: arquitetura de microsserviços tende a ser mais resiliente devido à sua natureza distribuída. Na ocasião de um serviço falhar, o sistema não será necessariamente afetado como um todo, pois os outros serviços podem continuar operando normalmente. Além disso, é mais fácil implementar práticas como tolerância a falhas e recuperação de desastres em um ambiente de microsserviços justamente pela separação de contextos entre os serviços.
  • Desenvolvimento paralelo: com microsserviços, múltiplas equipes podem trabalhar de forma independente e paralela mais facilmente. Cada serviço pode ser desenvolvido por uma equipe separada, facilitando a colaboração e acelerando o processo de desenvolvimento. Isso também permite atualizações mais rápidas e frequentes, já que mudanças em um serviço não exigem necessariamente coordenação com outras partes do sistema.

Como também não poderia deixar de ser, os microsserviços também possuem desvantagens:

  • Camada de comunicação mais complexa: uma das principais desvantagens dos microsserviços é a complexidade adicional na camada de comunicação entre os serviços. Como os serviços são independentes, é necessário que sejam implementados mecanismos de comunicação como o uso de protocolos específicos como GraphQL, gRPC, APIs REST, SOAP, AMQP dentre outros, além de também ser necessário lidar com possíveis inconsistências nos dados trafegados e problemas de infraestrutura como latência de rede.
  • Dificuldade de simular cenários: simular cenários e executar testes integrados em um ambiente de microsserviços tende a ser mais complexo do que em um monólito, pois como existem mais serviços envolvidos e eles podem estar distribuídos em diferentes ambientes, se torna necessário implementar testes mais sofisticados com o uso de mocks de serviços externos e configurar uma integração contínua mais robusta para lidar com múltiplos serviços e consolidar contextos como ambientes de homologação, sandbox e produção por exemplo.
  • Dificuldade de implantar: implantar e gerenciar um ambiente de microsserviços também tende a ser mais complexo do que um monólito, especialmente nos quesitos de automação e monitoramento. É necessário lidar com desafios como versionamento de serviços, roteamento de tráfego e monitoramento distribuído para garantir o desempenho e a confiabilidade do sistema como um todo.

Qual arquitetura é a melhor para minha organização?

Até agora nos preocupamos em entender cada uma das arquiteturas sob um olhar mais técnico, mas você já parou pra pensar que a arquitetura de software pode impactar e também ser impactada pela forma como sua organização está estruturada?

Em 1967, um programador chamado Melvin Conway fez uma constatação que hoje ficou conhecida como “Lei de Conway”:

Organizações que projetam sistemas estão fadadas a produzir sistemas que tenham a mesma estrutura de comunicação de suas organizações.

Apesar de não ser nenhuma ciência exata ou lei da física, a Lei de Conway tem sido bastante utilizada por empresas para organizarem suas equipes de modo a reduzir as camadas entre pessoas e sistemas, acreditando que dessa forma haverá menos atrito e mais fluidez nas atividades do cotidiano e na comunicação entre as equipes.

Supondo então que exista de fato uma forte correlação da estrutura de comunicação de uma organização com a estrutura dos sistemas que ela projeta, podemos fazer algumas observações sobre como a arquitetura monolítica e de microsserviços impactam e são impactadas pelo formato da organização.

A começar pela arquitetura monolítica, devido ao seu forte acoplamento, onde todos os módulos estão intimamente interligados, espera-se observar uma comunicação mais direta entre as equipes envolvidas na estrutura organizacional. Esse tipo de comunicação simplifica o início do desenvolvimento, os testes e a documentação, mas pode resultar em menor resiliência e dificuldade de escalabilidade ao longo do tempo, tanto do sistema quanto das equipes.

Por outro lado, na arquitetura de microsserviços, como temos uma separação mais clara de responsabilidades e uma comunicação mais complexa entre os serviços, espera-se que a organização possua equipes altamente especializadas e autônomas. Essa estrutura de comunicação proporciona maior flexibilidade, escalabilidade e resiliência, porém introduz desafios adicionais na comunicação entre serviços e equipes e na implantação do sistema.

Considerações finais

À medida que o campo de desenvolvimento de software continua a evoluir, é esperado que surjam novas abordagens e ferramentas que ajudem a mitigar as desvantagens de ambas as arquiteturas. Além disso, também é natural que as organizações continuem buscando maneiras de otimizar suas estruturas de comunicação e processos de desenvolvimento, o que muito provavelmente acabará resultando em novas descobertas e inovações neste meio.

Como exemplo, algumas organizações já estão investindo em ferramentas e práticas que facilitam a comunicação entre microsserviços, como malhas de serviços e APIs baseadas em eventos. De forma semelhante, na arquitetura monolítica, práticas de desenvolvimento orientadas a domínio também tem se tornado mais populares pois podem ajudar a manter o código mais modular e gerenciável, mesmo à medida que a base de código cresce.

Além disso, conforme as organizações se tornam mais complexas e seus sistemas se tornam mais interconectados, a escolha da arquitetura pode se tornar menos binária e mais híbrida, dependendo das exigências específicas de cada parte do sistema.

No fim das contas, a escolha da arquitetura de software deve ser uma decisão estratégica que leve em consideração não apenas as necessidades técnicas do projeto, mas também a estrutura da equipe, os processos de desenvolvimento e as metas de longo prazo da organização.

Enfim, espero que o artigo tenha sido útil. Para aqueles que desejam se aprofundar mais sobre o assunto, fica a recomendação de leitura dos livros Arquitetura Limpa e Microsserviços Prontos Para a Produção, ambos os autores fazem investigações detalhadas e reflexões profundas que podem gerar muitos insights e colaborar para o desenvolvimento de aplicações bem sucedidas.

--

--