Responsabilidade única e coesão
Nesta aula
Separar pelo motivo de mudança
Um arquivo curto pode misturar responsabilidades; um arquivo maior pode concentrar tarefas que pertencem ao mesmo propósito. Responsabilidade única significa organizar uma unidade em torno de uma razão principal de mudança. Coesão é a relação entre seus elementos: eles trabalham juntos para uma finalidade reconhecível. Contar linhas não responde a nenhuma dessas perguntas.
Na Oficina Caracol, a regra de quais casos são públicos pertence ao catálogo. O protocolo de receber uma solicitação HTTP pertence ao servidor. A apresentação do estado de carregamento pertence à interface. Se mudar a cor do botão obriga a editar a seleção de ativos, provavelmente criamos uma ligação que não corresponde ao problema.
Acoplamento é a dependência entre unidades. Alguma dependência é inevitável: a interface precisa conhecer o formato da resposta. O objetivo é tornar esse acordo explícito e limitado, para que uma alteração local não exija reconstruir o projeto inteiro.
Fronteiras justificadas do projeto
| Unidade oficial | Responsabilidade | Mudança que justifica editá-la |
|---|---|---|
| data/casos.json | Guardar registros fictícios. | Alterar o conteúdo de um caso. |
| src/catalogo.mjs | Validar casos e produzir seleção pública. | Mudar o contrato ou a regra de seleção. |
| src/operacoes.mjs | Registrar a reserva simulada por chave. | Mudar a regra de repetição com efeito único. |
| src/servidor.mjs | Receber solicitações e ligar protocolo às operações. | Mudar o tratamento HTTP de uma resposta. |
| public/app.js | Ligar ações da página às respostas da API. | Mudar a interação e o feedback apresentado. |
| public/styles.css | Definir apresentação visual. | Ajustar contraste, espaçamento ou aparência do foco. |
Validar registros e selecionar ativos podem permanecer no mesmo módulo de catálogo porque compartilham um contrato de dados e uma finalidade. Não precisamos criar um arquivo para cada campo. A separação também não permite repetir a regra de ativo no servidor e na interface: duplicar a decisão cria futuras divergências.
Uma verificação localizada da fronteira
O trecho abaixo é um ensaio isolado, apresentado para leitura como módulo executado a partir da pasta pratica. Ele usa a API acordada do pacote e dados inventados; não representa uma saída já obtida. A mesma intenção de verificação pertence à suíte do catálogo. Observe que a regra pode ser examinada sem abrir porta ou montar a página.
import assert from 'node:assert/strict';
import { listarAtivos } from './src/catalogo.mjs';
const entrada = [
{ id: 'c01', titulo: 'Revisão', descricao: 'Caso fictício ativo', ativo: true },
{ id: 'c02', titulo: 'Arquivo', descricao: 'Caso fictício inativo', ativo: false }
];
const anterior = structuredClone(entrada);
const saida = listarAtivos(entrada);
assert.deepEqual(saida, [
{ id: 'c01', titulo: 'Revisão', descricao: 'Caso fictício ativo' }
]);
assert.deepEqual(entrada, anterior);A primeira comparação verifica a representação pública. A segunda verifica que a seleção não alterou a entrada. Esse ensaio não comprova que a API ou a página usam a função corretamente; essas relações precisam de verificações de integração. Uma boa fronteira torna a regra examinável, mas não elimina a prova do conjunto.
Procedimento para melhorar a organização
- Descreva a finalidade de cada unidade em uma frase sem usar e para reunir tarefas independentes.
- Liste três mudanças plausíveis e indique onde cada uma deveria ocorrer.
- Examine se regras iguais foram copiadas em lugares diferentes. Escolha o módulo responsável e faça os consumidores usarem seu contrato.
- Conserve juntos elementos que mudam pela mesma razão; reúna microarquivos que apenas obrigam o leitor a saltar entre pastas.
- Depois de reorganizar, verifique comportamento local e integração. Uma refatoração não deve alterar o contrato sem que isso seja decidido e registrado.
Erros e condição de avanço
| Erro | Mecanismo do problema | Reparo |
|---|---|---|
| Tudo em um arquivo de utilidades | Finalidades diferentes não têm endereço reconhecível. | Mover funções para o domínio cuja regra representam. |
| Um arquivo por propriedade | Uma mudança de contrato exige muitos saltos artificiais. | Agrupar validações relacionadas ao registro. |
| Interface filtra inativos por conta própria | Servidor pode continuar revelando informação indevida. | Centralizar a seleção antes da fronteira pública. |
A organização é suficiente para avançar quando podemos localizar a regra, modificá-la e verificar seus consumidores sem alterações sem relação com o objetivo. Não exigimos o menor arquivo possível; exigimos uma divisão que favoreça compreensão, teste e mudança responsável.
Exercício com fronteiras resolvidas
Um único arquivo lê dados, escolhe serviços ativos, abre a porta HTTP, desenha mensagens e define cores. Proponha uma separação usando os caminhos oficiais. Depois diga onde alterar somente o título de c01 e onde tratar um conflito de chave de reserva.
Ver solução comentada
Solução: manter dados em data/casos.json; regras de catálogo em src/catalogo.mjs; regras de reserva em src/operacoes.mjs; protocolo em src/servidor.mjs; interação em public/app.js; apresentação em public/styles.css. O título muda na origem de dados, com validação posterior. O conflito nasce na regra de reservas e recebe tradução HTTP no servidor. Uma boa resposta reconhece essa colaboração sem duplicar a regra nos dois módulos.
Referências para aprofundamento
Apoio: S01, Software Design, para organização de responsabilidades; S17, definição de refatoração; e S19, documentação de ECMAScript modules e node:assert. O exemplo verifica uma fronteira do pacote, sem representar aprovação da aplicação inteira.
Fontes relacionadas
Consulte os limites e as seções de apoio de cada referência.
S01 S17 S19Tente o exercício antes de consultar a solução. Marque a aula para organizar sua leitura.
A conclusão desta leitura não equivale a certificação ou aceite de um projeto real. Teste os exemplos no escopo indicado e registre as limitações.