Descomplicando a arquitetura de software: guia visual para novatos

Descomplicando a arquitetura de software: guia visual para novatos
Objetivo – Fornecer uma visão clara e prática dos principais conceitos de arquitetura de software, mostrando como aplicar estilos, camadas e padrões de projeto em um projeto real. O conteúdo é pensado para quem ainda está dando os primeiros passos como arquiteto ou desenvolvedor full‑stack.
Índice
Introdução
A arquitetura de software é a disciplina que define como os componentes de um sistema se relacionam e como as responsabilidades são distribuídas. Uma boa arquitetura traz:
- Manutenibilidade – alterações locais não afetam todo o código.
- Escalabilidade – o sistema cresce sem precisar de reescrita completa.
- Testabilidade – componentes isolados são mais fáceis de validar.
Camadas clássicas e sua responsabilidade
A divisão em camadas é o ponto de partida mais comum. Cada camada tem um objetivo claro e se comunica apenas com a camada imediatamente adjacente.
┌─────────────────────┐
│ Interface de Usuário│ ← camada de apresentação (UI)
└─────────▲───────────┘
│
┌─────────▼───────────┐
│ Controladores │ ← camada de aplicação
└─────────▲───────────┘
│
┌─────────▼───────────┐
│ Serviços de Domínio│ ← camada de domínio
└─────────▲───────────┘
│
┌─────────▼───────────┐
│ Repositórios │ ← camada de persistência
└─────────────────────┘
Regra de ouro: Cada camada conhece apenas a camada abaixo. Isso reduz o acoplamento e facilita a substituição de tecnologias (por exemplo, trocar um banco de dados relacional por um NoSQL).
1. Camada de apresentação (UI)
Responsável por coletar a entrada do usuário e exibir resultados. Em aplicações web, pode ser um conjunto de páginas HTML/JS ou um cliente móvel.
2. Camada de aplicação (Controladores)
Orquestra as chamadas entre UI e domínio. Não contém lógica de negócio, apenas delega tarefas.
3. Camada de domínio (Serviços)
Contém as regras de negócio. É o coração do sistema e deve permanecer livre de detalhes técnicos (como acesso a arquivos ou redes).
4. Camada de persistência (Repositórios)
Abstrai a forma como os dados são armazenados. Usa interfaces que podem ser implementadas por diferentes tecnologias.
Padrões de projeto essenciais
2.1. Repository
Isola a lógica de acesso a dados da camada de domínio. O domínio depende apenas de uma interface, facilitando testes unitários.
// Interface do repositório (Java)
public interface ProdutoRepository {
Produto encontrarPorId(Long id);
List<Produto> buscarTodos();
void salvar(Produto produto);
}
2.2. Service (ou Service Layer)
Agrupa operações de negócio que podem envolver múltiplos repositórios ou regras complexas.
# Service em Python
class CarrinhoService:
def __init__(self, produto_repo, carrinho_repo):
self.produto_repo = produto_repo
self.carrinho_repo = carrinho_repo
def adicionar_item(self, carrinho_id, produto_id, quantidade):
produto = self.produto_repo.obter(produto_id)
if produto.estoque < quantidade:
raise ValueError("Estoque insuficiente")
self.carrinho_repo.adicionar(carrinho_id, produto, quantidade)
2.3. Factory
Cria objetos complexos sem expor a lógica de construção ao cliente.
// Factory em TypeScript
export class PedidoFactory {
static criar(pedidoDto: PedidoDTO): Pedido {
const pedido = new Pedido();
pedido.clienteId = pedidoDto.clienteId;
pedido.itens = pedidoDto.itens.map(i => new Item(i.produtoId, i.quantidade));
return pedido;
}
}
2.4. Dependency Injection (DI)
Inverte o controle da criação de dependências, permitindo que o framework ou um contêiner forneça as instâncias necessárias.
// Registro de serviços no contêiner (C#)
services.AddScoped<IProdutoRepository, ProdutoRepository>();
services.AddScoped<CarrinhoService>();
Estilos arquiteturais: monólito vs. microserviços
| Característica | Monólito | Microserviços |
|---|---|---|
| Escopo | Um único artefato executável | Conjunto de serviços independentes |
| Deploy | Deploy único | Deploy independente por serviço |
| Complexidade | Simples de iniciar, mas pode crescer | Mais complexo inicialmente (orquestração) |
| Escalabilidade | Escala vertical (mais recursos na mesma máquina) | Escala horizontal por serviço |
| Comunicação | Chamadas internas (métodos) | Comunicação via rede (mensagens, RPC) |
Dica para iniciantes: Comece com um monólito modular (camadas bem definidas) e, ao ganhar experiência, extraia partes críticas como microserviços.
Diagrama de um monólito modular
flowchart LR
UI[Interface de Usuário]
Ctrl[Controladores]
Serv[Serviços de Domínio]
Repo[Repositórios]
UI --> Ctrl
Ctrl --> Serv
Serv --> Repo
Diagrama de um conjunto de microserviços
graph TD
API[Gateway HTTP]
Auth[Serviço de Autenticação]
Cat[Catálogo de Produtos]
Order[Gerenciamento de Pedidos]
Inv[Inventário]
API --> Auth
API --> Cat
API --> Order
Order --> Inv
Cat --> Inv
Exemplo prático: um mini‑e‑commerce
Vamos construir, passo a passo, um sistema de e‑commerce simplificado usando Node.js com Express (para a camada de aplicação) e TypeScript (para tipagem estática). O foco será demonstrar a estrutura de camadas e o uso de padrões, sem entrar em detalhes de infraestrutura.
1. Estrutura de diretórios
``` ecommerce/ │ ├─ src/ │ ├─ controllers/ # Camada de aplicação │ │ └─ ProdutoController.ts │ ├─ services/ # Camada de domínio │ │ └─ ProdutoService.ts │ ├─ repositories/ # Camada de persistência │ │ └─ ProdutoRepository.ts │ ├─ models/ # Entidades de domínio │ │ └─ Produto.ts │ ├─


