Por vezes, ainda me pego conversando sobre arquitetura de software com algumas pessoas. Apesar de já ter escrito umas ideias aqui e ali, senti que faltava colocar no papel uma visão que vai além das “badaladas” clean architecture, ports and adapters e DDD. Ou talvez, pensando bem, essa visão esteja exatamente entre essas abordagens, porque todas bebem de fontes parecidas.
No fim, pode até não ser nada novo. Mas talvez seja algo que o curso “zero to hero” nunca mencionou. Então, resolvi deixar aqui mais uma peça desse quebra-cabeça que é a arquitetura de software.
Domínio
No contexto de Domain-Driven Design (DDD), o domínio é, essencialmente, o coração do sistema. É a área de atuação ou o problema que o software foi criado para resolver. Pense no domínio como aquela parte do mundo real que o software tenta modelar e onde executa suas operações.
Parece simples, né? E é um conceito que você vai encontrar em muitos livros e artigos. Mas, na prática, a aplicação desse conceito é tudo menos… linear.
Entre livros e a realidade do dia a dia
Uma das imagens mais famosas do DDD é a divisão clara entre subdomínios, cada um com seus próprios times (ou time) e sistemas bem organizados. Por exemplo:
- Time A: cuida de Optimal Acquisition, Purchasing, Inventory e Resource Planning.
No mundo ideal, tudo estaria tão bem definido que o sistema rodaria como um relógio, com sinergia total entre os times e os domínios.
Agora, vamos temperar isso com um pouco de realidade. Imagine que, na segunda semana do projeto, a empresa percebe que o Time A está sobrecarregado. Então, dividem o trabalho assim:
- Time B: assume Purchasing.
- Time C: fica com Resource Planning.
Algumas semanas depois, alguém do Time C sai da equipe, e eles precisam se fundir com o Time B, formando o Time BC. Para complicar ainda mais, o Time A transfere parte de Inventory para o Time BC.
E aí fica a pergunta: seus sistemas aguentariam essas mudanças de time sem colapsar? A forma como você constrói software permite flexibilidade para reorganizar partes do sistema sem muito esforço?
O que vejo por aí
Embora a ideia de separar pastas em “models”, “views” e “controllers” esteja caindo em desuso, ainda vejo muitos projetos seguindo essa abordagem — só que com nomes diferentes. Uma unica pasta infrasctructure, com tudo dentro, por exempl.
Mesmo que as literaturas mais famosas sobre DDD e clean architecture não sejam muito prescritivas sobre organização de pastas, muitos desenvolvedores tentam copiar essas estruturas diretamente, sem considerar se elas realmente fazem sentido no contexto do projeto.
O sistema não é só seu (e nem do seu time)
Mudanças são inevitáveis. E, pensando nisso, gosto de construir sistemas baseados em módulos plug 'n play. Esses módulos devem ser coesos, com baixo acoplamento e fáceis de mover ou até mesmo deletar, se necessário.
Para alcançar essa flexibilidade, é essencial entender que boa parte do código de infraestrutura deve se alinhar às necessidades do domínio. Essa relação próxima faz com que infraestrutura e domínio funcionem juntos como uma unidade lógica.
Mas, além da infraestrutura e do domínio, há outro elemento importante no design dos meus sistemas: as bibliotecas (ou libs, cross cutting libs).
O papel das libs
As libs são componentes standalone, ou seja, não dependem do domínio. Isso significa que elas podem ser reutilizadas em qualquer projeto, tornando o sistema mais modular e sustentável a longo prazo.
No modelo básico, podemos visualizar assim:
https://miro.medium.com/v2/resize:fit:640/format:webp/1*2Yx38jXKm4wTRUqVCSE8ZQ.png
Porém, como frisei até aqui, gosto de mais uma camada separando as coias, camada de módulo.
Modulos
Os módulos desempenham um papel fundamental na estruturação de projetos, pois permitem agrupar funcionalidades relacionadas, promovendo coesão e encapsulamento. Eles facilitam a manutenção, tornam o código mais reutilizável e ajudam a manter a separação de responsabilidades clara e bem definida.
Em um sistema maior, onde existem vários módulos, o desenho evolui para algo assim:
Regra de ouro: nada é compartilhado diretamente entre módulos. Isso mantém o sistema modular e reduz a complexidade de dependências.
Por que essa abordagem?
Com essa organização, garantimos que:
- Flexibilidade: É fácil mover ou reaproveitar partes do sistema.
- Reutilização: Libs podem ser usadas em múltiplos projetos, economizando esforço.
- Isolamento: Problemas em um módulo não afetam outros diretamente.
Essa mentalidade ajuda a construir sistemas que acompanham as mudanças organizacionais e evoluem sem virar uma bola de neve técnica.
Conclusão
No fim, não mostrei muito código aqui, mas tentei compartilhar uma visão sobre como as abordagens que escolhemos para estruturar nossos sistemas não são apenas técnicas: elas impactam diretamente e são impactadas pelo nosso dia a dia de trabalho.
Cada decisão de design, desde a organização dos módulos até a reutilização de libs, reflete nas facilidades e nos desafios que enfrentamos em um projeto. Então, pensar na arquitetura como algo vivo e que deve acompanhar as mudanças da equipe e do negócio é o que nos ajuda a construir sistemas mais sustentáveis e adaptáveis.
Espero que essa reflexão te inspire a olhar para suas escolhas arquiteturais com uma perspectiva prática e estratégica. Afinal, arquitetura de software é menos sobre diagramas e mais sobre preparar o terreno para evoluir sem perder o controle. 🚀
Top comments (0)