- Arquitetura
- C#
- .NET
- React
- Manutenibilidade
Arquitetura clara antes de arquitetura sofisticada
Uma boa arquitetura não é a que acumula mais camadas e padrões. É a que torna evidente onde uma mudança deve acontecer, quais partes ela afeta e por que o sistema foi organizado daquela maneira.
Arquitetura é uma ferramenta para lidar com mudanças
Arquitetura costuma ser apresentada por meio de diagramas, nomes de padrões e regras de dependência. Tudo isso pode ser útil, mas existe uma pergunta mais prática: quando uma necessidade muda, o código indica com clareza onde essa mudança deve acontecer?
Se uma regra simples exige alterações espalhadas por controllers, services, repositories, componentes e utilitários genéricos, o sistema pode ter muitas camadas sem possuir limites claros.
- onde cada responsabilidade vive
- quem pode depender de quem
- quais decisões são locais
- quais mudanças atravessam módulos
- como verificar que o comportamento continua correto
O valor está menos na aparência da estrutura e mais na previsibilidade que ela oferece para a próxima mudança.
Organizar por capacidade pode revelar melhor o produto
Separar todo o backend em pastas como Controllers, Services, Repositories e Models parece organizado no início. Conforme o sistema cresce, porém, uma única funcionalidade passa a exigir navegação entre várias áreas distantes.
Uma alternativa é aproximar arquivos que mudam pelo mesmo motivo. Funcionalidades relacionadas a pedidos podem ficar próximas, mesmo que contenham tipos com responsabilidades técnicas diferentes. No frontend, componentes, chamadas de API e regras de apresentação de uma mesma área também podem formar um módulo de produto.
Features/
Orders/
Create/
GetById/
Cancel/
Customers/
Create/
Search/
Shared/src/
features/
orders/
api/
components/
hooks/
pages/
shared/Isso não significa que toda aplicação deva adotar exatamente essas pastas. A vantagem está em fazer a estrutura refletir as capacidades do produto, tornando mais fácil localizar o conjunto de código afetado por uma mudança.
Limites claros importam mais do que o número de camadas
Camadas são úteis quando representam limites reais. Uma regra de negócio não deveria precisar conhecer detalhes de banco, protocolo HTTP ou biblioteca de interface. Da mesma forma, um componente visual não deveria carregar sozinho todas as decisões de acesso a dados, tratamento de erro e navegação.
O problema começa quando cada camada existe apenas porque um modelo arquitetural diz que ela deve existir. Classes que apenas encaminham chamadas para outra classe aumentam a quantidade de código sem necessariamente proteger uma decisão.
- isola uma tecnologia externa
- concentra uma regra importante
- impede dependências indesejadas
- permite substituir uma implementação relevante
- reduz o contexto necessário para entender uma funcionalidade
- cria um ponto claro para testes e observação
Abstrações devem ser conquistadas pelo problema
Criar uma interface para cada classe ou um componente genérico para cada repetição pode dar uma sensação imediata de organização. O custo aparece depois, quando os nomes se tornam vagos e uma alteração simples precisa atravessar abstrações que não representam diferenças reais.
- Existem comportamentos realmente diferentes atrás desse contrato?
- A dependência externa precisa ser isolada?
- A repetição representa o mesmo conceito ou apenas código parecido?
- A abstração deixará a regra mais evidente?
- Conseguirei nomeá-la com precisão?
Duplicação pequena e explícita pode ser temporariamente mais segura do que uma generalização prematura. Quando o padrão real emerge, a extração passa a ser guiada por evidências do próprio código. O mesmo vale no React: um componente compartilhado deve representar uma linguagem visual ou um comportamento consistente, não apenas duas marcações semelhantes.
Testes e observabilidade revelam a qualidade dos limites
É difícil testar uma regra sem configurar banco, rede e interface? Pode haver responsabilidades misturadas. É difícil descobrir onde uma requisição falhou? Talvez o fluxo atravesse limites que não deixam rastros suficientes.
Testes não servem apenas para confirmar resultados. Eles também revelam o custo de usar uma parte do sistema isoladamente. Quando uma regra exige uma preparação enorme, a arquitetura está comunicando algo sobre seu acoplamento.
Observabilidade oferece outra perspectiva. Logs estruturados, identificadores de correlação e informações sobre falhas ajudam a acompanhar uma operação entre frontend, API e serviços internos. Eles mostram o sistema em funcionamento, algo que um diagrama estático não consegue fazer sozinho.
Registrar decisões torna a simplicidade sustentável
Uma solução simples pode parecer óbvia hoje e arbitrária alguns meses depois. Um registro curto explicando contexto, escolha e consequência protege a intenção sem exigir documentação extensa.
- qual problema concreto estamos resolvendo?
- quais restrições influenciaram a escolha?
- que alternativas foram consideradas?
- que custo estamos aceitando?
- qual sinal indicaria a necessidade de rever a decisão?
Esse hábito evita dois extremos: manter uma escolha para sempre apenas porque ela já existe ou substituí-la sem entender por que foi feita.
Arquitetura clara não significa ausência de sofisticação. Significa que a sofisticação aparece onde o problema exige.