O que é um Modelo Arquitetural e qual a sua importância?
Basicamente, um modelo arquitetural é a estrutura abstrata sobre a qual sua aplicação será implementada.
"A arquitetura de software de um programa ou sistema computacional é a estrutura ou estruturas do sistema que abrange os componentes de software, as propriedades externamente visíveis desses componentes e as relações entre eles.” (Bass, Clements, & Kasman, Software Architecture in Practice)
Para definir o modelo que mais irá se adequar ao seu projeto, precisamos conhecer bem as estratégias de curto, médio e longo prazo da empresa, os requisitos não funcionais e arquiteturais do software, assim como a curva de crescimento de usuários ao longo do tempo e a volumetria de requisições.
Bem como os pontos citados ao longo deste artigo, existem ainda outros a levar em conta na decisão de qual modelo arquitetural aplicar. Como exemplo, podemos listar:
Preocupações de segurança;
Armazenamento de dados;
Lockins;
Volume total de usuários;
Volume de usuários simultâneos;
TPS (transações por segundo);
Plano de disponibilidade/SLA;
Requisitos legais;
Disponibilidade em um ou mais tipos de plataformas;
Integrações.
O levantamento de arquitetura, RAs (requisitos arquiteturais), VAs (variáveis arquiteturais), RFs (requisitos funcionais), RNFs (requisitos não funcionais) e os critérios que definem cada um desses itens influenciam diretamente na escolha do modelo correto.
A escolha do modelo arquitetural pode impactar todo o life cycle da aplicação. Por isso, esse é um assunto que devemos tratar com grande atenção. O uso de MVPs (principalmente aqueles que não vão para produção), podem auxiliar muito nessa tarefa. Eles dão uma oportunidade única de errar, ajustar, errar novamente, provar conceitos, ajustar e errar quantas vezes forem necessárias para que no final o software possua a arquitetura na versão mais acertada, trazendo assim os verdadeiros ganhos dessa escolha.
Como estão divididos os modelos arquiteturais
É ideal deixar claro que como muitas definições no mundo do software, o que é, e quais são os modelos arquiteturais podem variar. Por isso, neste artigo procurei dividi-los em quatro grandes grupos: monolítico, semimonolítico (ou monolito modular), monolito distribuído (ou microlito) e microcomponentizado.
Monolítico
Modelo em que todos os componentes formam um único aplicativo ou executável integrados em um único código-fonte. Neste caso, todo ele é desenvolvido, implantado e escalado como unidade única.
Figura 1 – Exemplo de Modelo Monolítico.
Prós
Simplicidade: como o aplicativo é tratado como uma unidade única e coesa, ele se torna mais simples, já que todas as partes estão contidas em um único código-fonte.
Maior aderência a Padrões de Projeto: levando em conta que temos um único código-fonte, outro fator que facilita é que os próprios padrões de projetos (Design Patterns, 01/2000) foram escritos em épocas de dominância dos monolitos, tornando a aplicação dos mesmos mais aderente.
Maior desempenho: devido à baixa latência na comunicação, os monolitos costumam ter um bom desempenho, mesmo utilizando tecnologias mais defasadas.
Menor consumo de recursos: a baixa complexidade, a simplicidade e a menor sobrecarga de comunicação entre camadas favorecem o menor consumo de recursos.
Troubleshooting facilitado: Criação dos ambientes de desenvolvimento e debugs são feitos de forma facilitada em monolitos, pois neles os componentes partilham dos mesmos processos. Outro fator que podemos levar em conta é que monolitos possuem menos pontos de falha externos, simplificando a busca por erros.
Contras
Tamanho de times limitados: quebras relacionadas a Continuous Integration e conflitos de merge acontecem com maior regularidade em monolitos, gerando dificuldades de trabalho paralelo para grandes times.
Escalabilidade: a escalabilidade pode ser limitada em certos aspectos. Mesmo com facilidade na escalabilidade vertical, muitas vezes a escalabilidade horizontal pode se tornar um problema que poderá afetar o crescimento da aplicação.
Disponibilidade de janelas: normalmente, para um monolito ocorrem trocas de executáveis, o que necessita de uma janela de disponibilidade sem que usuários acessem o aplicativo, o que não acontece com outros modelos arquiteturais que podem utilizar outras técnicas de deploy como o Blue-Green ou até mesmo trabalhar com imagens ou pods.
Tecnologia única: a baixa diversidade tecnológica muitas vezes pode se tornar um impedimento para o crescimento da aplicação por atender somente um tipo de sistema operacional, por exemplo, ou não atender de forma integral novas features solicitadas pelos clientes por não possuir atualizações que tenham capacidade de solucionar problemas complexos.
Maior gasto com compilação e execução: grandes monolitos geralmente têm um tempo elevado para compilar e fazer a execução local, gerando um maior comprometimento de tempo de desenvolvimento.
Quando Usar
Escalabilidade e Disponibilidade Baixas: se a aplicação possui uma escala limitada em que, por exemplo, o número de usuários é baixo ou a alta disponibilidade não é mandatória, o modelo monolítico é uma boa solução.
Aplicações Desktop: o modelo monolítico é altamente indicado para aplicações desktop.
Times de baixa senioridade: modelos monolíticos, devido à sua simplicidade e localização dos componentes, possibilitam que times de baixa senioridade possam trabalhar com uma melhor performance.
Recursos limitados: para uma infraestrutura limitada com recursos escassos.
Semimonolítico (ou Monolito Modular)
Modelo em que as aplicações são compostas por partes de estruturas monolíticas. Neste caso, a combinação tenta equilibrar a simplicidade do modelo monolítico e a flexibilidade do microcomponentizado. Atualmente, esse modelo arquitetural costuma ser bastante confundido com microsserviços.
Figura 2 – Exemplo de Modelo Semimonolítico.
Prós
Traz benefícios dos modelos monolítico e microcomponentizado: com isso, é possível manter partes como estruturas monolíticas e microcomponentizar somente componentes que têm a real necessidade.
Diversidade tecnológica: possibilidade de usar diversas abordagens tecnológicas.
Infraestrutura diversificada: este modelo pode ser desenvolvido para utilizar tanto infra On-Premise quanto Cloud, favorecendo a migração entre ambas.
Suporta times maiores: a segmentação dos componentes favorece que vários times trabalhem paralelamente, cada qual em seu escopo.
Especialidades Técnicas: devido à segmentação, aproveita-se melhor as hard skills do time, tais como frontend, UX, backend, QA, arquitetos, etc.
Contras
Padronização: devido ao grande número de componentes que podem surgir em um modelo semimonolítico, a padronização (ou falta dela) pode se tornar um grande problema.
Complexidade: a complexidade inerente a esse tipo de modelo também tende a aumentar com novas features. Logo, novos recursos como mensageria, cache, integrações, controle de transações, testes, entre outros, podem adicionar ainda mais complexidade ao modelo.
Budget: em modelos que amparam o uso de diversas tecnologias com times grandes, são necessários mais profissionais especialistas e com nível maior de senioridade, ocasionando muitas vezes um gasto maior com despesas de pessoal.
Troubleshooting complexo: a própria complexidade do modelo e a diversidade de tecnologias tornam cada vez mais difícil o troubleshooting da aplicação. Isso se dá devido à grande quantidade de pontos de falhas (inclusive externos à aplicação) que passam a existir e à comunicação entre eles.
Quando Usar
Aceito em Vários Cenários: é um modelo flexível que pode atender vários cenários, porém nem sempre da melhor forma.
Pouca Definição: em projetos que possuem incertezas ou até mesmo que não possuem a total definição de seus requisitos, este modelo é o mais indicado.
Em médias e grandes equipes: como dito, a divisão dos componentes em vários grupos facilita o trabalho paralelo de médias e grandes equipes. Normalmente, os grupos possuem seus próprios repositórios de código, o que torna o trabalho paralelo mais ágil.
Senioridade Diversa: este modelo se beneficia de times com essa formatação, pois softwares semimonolíticos apresentam desafios variados, tanto nas camadas de frontend e backend quanto em questões de infraestrutura (IaC – Infrastructure as a Code).
Infraestrutura: para uma infraestrutura Cloud-based ou híbrida, este modelo é mais aplicável. É um modelo que permite, por exemplo, uma adoção gradual entre On-Premise e Cloud, facilitando a adaptação e minimizando impactos operacionais.
Monolito Distribuído
Essa modelagem é uma modelagem "moderna" que também vem sendo implementada e confundida com o modelo microcomponentizado/microsserviços.
"You shouldn't start a new project with microservices, even if you're sure your application will be big enough to make it worthwhile." (Fowler, Martin. 2015)
Em resumo, neste modelo arquitetural o software é construído com bases do modelo monolítico, mas implantando conforme o modelo microcomponentizado. Atualmente, muitos o consideram um antipattern.
Figura 3 – Exemplo de Modelo Monolíto Distribuído.
Não valeria à pena listarmos as características de prós (não sei se tem), mas ainda vale citar características que vão contra: este modelo arquitetural reúne pontos negativos dos outros dois estilos com o qual é confundido.
Nele, os serviços são altamente acoplados e também possuem vários tipos de complexidade, tais como: operacional, testabilidade, deployment, comunicação e infraestrutura.
O alto acoplamento, principalmente entre os serviços de backend, traz sérias dificuldades no deployment, sem contar com o aumento expressivo de pontos de falha no software.
Microcomponentizado
Modelo de software em que todos os componentes são segmentados em pequenas partes totalmente desacopladas. Dentro de microcomponente, podemos citar:
Microfrontends
Microdatabases
Microvirtualizações
Microsserviços
Microbatches
BFFs
APIs
Figura 4 – Exemplo de Modelo Microcomponentizado.
"A microservice is a service-oriented application component that is tightly scoped, strongly encapsulated, loosely coupled, independently deployable, and independently scalable" (Gartner, n.d.).
As opiniões se convergem a dizer que, todo o microsserviço que deu certo, primeiro foi um monolito que ficou grande demais para ser mantido e chegou a um ponto comum de ter que ser separado.
Prós
Escalabilidade: a escalabilidade neste modelo torna-se bastante flexível. Conforme a necessidade, escala-se os componentes de maneira específica.
Desenvolvimento Ágil: as equipes podem trabalhar de forma independente em cada componente, facilitando a implantação contínua e acelerando o ciclo de desenvolvimento.
Resiliência: caso um componente falhe, não afeta necessariamente toda a aplicação. Isso melhora a resiliência geral do sistema. É importante salientar que existem abordagens de pontos únicos de falha a fim de evitar esse tipo de problema.
Tecnologia Diversificada: cada componente pode ser desenvolvido utilizando tecnologias diferentes, permitindo a escolha da melhor ferramenta para cada tarefa específica. Além disso, também favorece as skills existentes em cada time.
Facilidade de Manutenção: mudanças em um componente não afetam automaticamente outros, facilitando a manutenção e atualização contínua.
Desacoplamento: os componentes são independentes uns dos outros, o que significa que as mudanças em um serviço não afetam automaticamente outros, facilitando a manutenção.
Contras
Custo: custo elevado de todos os componentes deste modelo (input, output, requisições, armazenamento, ferramentas, segurança, disponibilidade, entre outros).
Tamanho: softwares microcomponentizados costumam ser maiores em sua essência. Não somente o tamanho da aplicação, mas todo o ecossistema que a permeia desde o commit até o ambiente produtivo.
Complexidade Operacional: existe um aumento exponencial da complexidade nesse modelo. Projetar bons componentes arquiteturais para que essa complexidade seja gerida é de grande relevância. É importante escolher e gerir bem ferramentas de logging, APM e Continuous Monitoring, por exemplo. Gerenciar muitos microsserviços pode ser complexo. É necessário um esforço adicional para monitorar, orquestrar e manter os serviços em execução.
Latência: a comunicação entre microsserviços pode se tornar complexa, especialmente em sistemas distribuídos, exigindo estratégias adequadas de comunicação e gerenciamento de API.
Overhead de Rede: o tráfego de rede entre microsserviços pode aumentar, especialmente em comparação com arquiteturas monolíticas, o que pode afetar o desempenho.
Consistência entre Transações: garantir consistência em operações que envolvem vários microsserviços pode ser desafiador, especialmente quando se trata de transações distribuídas.
Testabilidade: testar interações entre microsserviços pode ser mais complexo do que testar uma aplicação monolítica, exigindo estratégias de teste eficientes.
Infraestrutura: pode ser necessário investir em uma infraestrutura robusta para suportar a execução de vários microsserviços, incluindo ferramentas de orquestração de contêineres e sistemas de monitoramento.
Dispersão Técnica: neste ponto, podemos dizer que existe uma ação da Lei de Conway "Reversa", pois os times, assim como tecnologias e ferramentas, tendem a seguir a dispersão e segregação. Nos times, cada um passa a ter conhecimento de uma pequena parte de um grande todo. Dessa forma, para tecnologias e ferramentas, cada desenvolvedor usa o framework ou ferramentas que mais lhe convém.
Domain-Driven Design: para aumentar as chances de sucesso desse modelo é necessário que os times tenham conhecimento de DDD.
Quando Usar
Volumetria: a arquitetura de microsserviços/microcomponentes tem se mostrado eficaz em sistemas de alta volumetria, ou seja, aqueles que precisam lidar com grandes quantidades de transações, dados e usuários.
Disponibilidade: uma das principais razões para se adotar esse tipo de arquitetura é a disponibilidade. Quando bem construído, um software que adota microcomponentização não tende a falhar como um todo quando pequenas partes apresentam problema. Sendo assim, outros componentes continuam em operação enquanto o componente problemático se recupera.
Escalabilidade: se diferentes partes de sua aplicação têm requisitos de escalabilidade distintos, os microsserviços podem ser úteis. Você pode dimensionar apenas os serviços que precisam de mais recursos, em vez de escalar toda a aplicação.
Tamanho dos Times: times pequenos podem ser problemas. Configurações, boilerplates, ambientes, testes, integrações, processos de input e output.
Resiliência > Desempenho": em casos de incerteza, por exemplo, do volume de requisições e até onde ele pode chegar como grandes e-commerces em períodos de alto acesso (black friday) onde é necessário que o software seja mais resiliente e tenha um desempenho mediano.
Checklist Comparativo
Figura 5 – Checklist Comparativo entre modelos.
Conclusão
Em síntese, a escolha do modelo arquitetural é crucial para o sucesso do projeto, exigindo uma análise criteriosa das necessidades e metas. Cada modelo arquitetural tem suas vantagens e desvantagens e devemos guiar a decisão pelo alinhamento com os requisitos específicos do projeto. Ao considerar as estratégias da empresa, requisitos e levantamentos arquiteturais, é possível tomar uma decisão que impactará positivamente o ciclo de vida da aplicação.
O trabalho (e apoio) do time de arquitetura é de extrema importância. Sendo também de grande importância que a gestão e áreas correlatas apoiem disponibilizando tempo para o levantamento de toda essa gama de informações.
Ficou em dúvida ainda? A princípio, comece pelo semimonolítco/monolito modular. Da mesma forma, dê muita atenção a modelagem do banco de dados.
Referências
Gartner. (s.d.). Microservice. Recuperado de https://www.gartner.com/en/information-technology/glossary/microservice
Gamma, E., Helm, R., Johnson, R., & Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley.
Bass, L., Clements, P., Kazman, R. (2013). Software Architecture in Practice (3rd ed.). Addison-Wesley.
Microservices Architecture (12/2023). Recuperado de https://microservices.io/
Fowler, S. J. (2017). Microsserviços Prontos para a Produção. Novatec.
Treinamento ArchExpert. (s.d.). Conteúdo Premium. Recuperado de https://one.archoffice.tech/
Monolith First (06/2015). Recuperado de https://martinfowler.com/bliki/MonolithFirst.html
Microservices. Acessado em 01/2024. Recuperado de https://martinfowler.com/tags/microservices.html