Software Architecture Lab
Voltar para conceitos
FundamentosIniciante12 min

Separação de Responsabilidades

Entenda como dividir o sistema em partes com funções claras para reduzir acoplamento, melhorar testabilidade e tornar a manutenção sustentável.

Resumo

Separação de responsabilidades é o princípio de dividir o sistema em partes com funções claras, onde cada parte sabe fazer uma coisa bem feita e ignora o resto.

Ele não é sobre criar muitas pastas — é sobre quem decide o quê dentro de uma aplicação. Quando esse contrato é quebrado, o código fica difícil de testar, frágil para mudar e doloroso para entender.

Problema que resolve

Sem separação, componentes acumulam papéis: renderizar, validar, chamar API, transformar dados, aplicar regra de negócio e tratar erros. Cada um desses papéis muda por motivos diferentes, em momentos diferentes — e quando estão juntos, qualquer alteração quebra alguma das outras.

A separação responde a uma pergunta poderosa: "se isso aqui mudar, o que mais precisa mudar junto?". Quanto menor a resposta, mais saudável o código.

Antes e depois

Tudo no componente
function PropostaForm() {
  const [docs, setDocs] = useState([]);
  const [erro, setErro] = useState("");
 
  async function enviar() {
    if (docs.length < 3) {
      setErro("Faltam documentos");
      return;
    }
    const res = await fetch("/api/propostas", {
      method: "POST",
      body: JSON.stringify({ docs }),
    });
    if (!res.ok) setErro("Falha ao enviar");
  }
 
  return <button onClick={enviar}>Enviar</button>;
}
Cada coisa no seu lugar
function PropostaForm() {
  const { enviar, erro } = useEnviarProposta();
  return <button onClick={enviar}>Enviar</button>;
}
 
// hook: orquestra o fluxo
function useEnviarProposta() { /* ... */ }
 
// use case: regra de negócio
function podeEnviar(proposta) { /* ... */ }
 
// service: comunicação externa
function postProposta(payload) { /* ... */ }

Quando aplicar

  • Sempre que uma função, componente ou módulo cresce além de uma frase para ser explicado.
  • Antes de duplicar lógica em outro lugar — extrair primeiro evita divergências.
  • Quando um teste exige montar muitos mocks só para testar uma coisa pequena.

Quando não exagerar

Não toda função pequena precisa virar uma camada. Em features triviais (uma tela de listagem simples, por exemplo), criar service + use case + mapper só por princípio gera mais ruído do que valor.

Erros comuns

  • Criar pastas chamadas services/, helpers/ e utils/ sem critério, e enfiar tudo dentro.
  • Separar arquivos sem separar responsabilidades reais: dois arquivos que sempre mudam juntos não estão separados de verdade.
  • Colocar regras de negócio dentro de componentes de UI ou handlers HTTP.
  • Misturar validação de formulário (entrada do usuário) com regra de domínio (regra do negócio).

Exercício

Leia este componente mentalmente e responda: quantos motivos para mudança ele tem hoje?

function CheckoutButton({ usuario, carrinho }) {
  async function pagar() {
    if (!usuario.email) return alert("Faça login");
    if (carrinho.total > usuario.limite) return alert("Limite excedido");
    const res = await fetch("/api/pagar", { method: "POST" });
    if (res.ok) window.location.href = "/obrigado";
  }
  return <button onClick={pagar}>Pagar</button>;
}

Sugestão: liste pelo menos quatro motivos diferentes pelos quais este código pode precisar mudar no futuro.

Conceitos relacionados

  • Acoplamento — métrica direta do quanto suas partes se conhecem.
  • Coesão — métrica do quanto cada parte é internamente consistente.
  • Camadas — a forma mais comum de organizar a separação em escala.

Conteúdos relacionados