Integração duplicação e mudanças
Nesta aula
- Linhas parecidas podem representar decisões distintas
- Duas funções concretas antes da decisão
- Depois reutilizar a regra já existente
- Uma contraprova que impede unificação excessiva
- Procedimento para integrar a mudança
- Erros que o contador de linhas não detecta
- Exercício com resolução
- Leitura técnica relacionada
Linhas parecidas podem representar decisões distintas
DRY é uma orientação para evitar a repetição de conhecimento que precisa permanecer coerente. Não é uma ordem para juntar toda sequência de linhas parecidas. Duas funções podem ter aparência diferente e esconder a mesma regra de publicação; duas expressões iguais podem atender necessidades que evoluem de forma independente. A decisão de unificar precisa identificar a regra compartilhada e o custo do acoplamento criado.
Na Oficina, somente casos ativos podem chegar aos consumidores públicos. Essa é uma regra de domínio: mudá-la altera o significado da aplicação. Já a forma de apresentar um título em uma lista e a estrutura de uma opção de seleção são decisões de apresentação. Convém compartilhar a regra pública e manter cada transformação com seu nome. Uma função genérica cheia de parâmetros booleanos pode economizar linhas e tornar a intenção mais difícil de ler.
Duas funções concretas antes da decisão
As funções a seguir são um exercício isolado, não novos exports ou uma nova tela do pacote. Recebem casos válidos com o mesmo contrato do projeto. A primeira produz títulos; a segunda produz opções de uma reserva. Observe onde o conhecimento realmente se repete.
function titulosDaLista(casos) {
return casos
.filter(caso => caso.ativo === true)
.map(caso => caso.titulo);
}
function opcoesDaReserva(casos) {
return casos
.filter(caso => caso.ativo === true)
.map(caso => ({ valor: caso.id, rotulo: caso.titulo }));
}As duas funções repetem a política de selecionar ativos. Se uma delas esquecer o filtro, o consumidor poderá divulgar um rascunho. Já os retornos são diferentes por uma razão: o título é texto, enquanto a opção precisa relacionar identificador e rótulo. Unificar esses retornos por um parâmetro “modo” esconderia a diferença sem eliminar a necessidade de compreendê-la.
Depois reutilizar a regra já existente
import { listarAtivos } from '../src/catalogo.mjs';
function titulosDaLista(casos) {
return listarAtivos(casos).map(caso => caso.titulo);
}
function opcoesDaReserva(casos) {
return listarAtivos(casos)
.map(caso => ({ valor: caso.id, rotulo: caso.titulo }));
}O módulo de catálogo já possui a política necessária e valida os dados. A extração não precisa criar outro pacote ou uma abstração universal. O ganho é ter um ponto claro para a regra de publicação, preservando nomes e formatos de cada consumidor. Antes de adaptar código real, localize os consumidores existentes e confirme se compartilham essa mesma promessa.
Uma contraprova que impede unificação excessiva
Imagine agora uma rotina de revisão interna cujo contrato é listar os identificadores de todos os registros, incluindo inativos. Seu código pode parecer semelhante ao da lista pública, mas reutilizar listarAtivos mudaria sua finalidade. Essa rotina não existe como funcionalidade da Oficina; é um contraponto fornecido para o exercício de projeto. O fato de dois lugares lerem os mesmos dados não torna suas regras iguais.
| Pergunta de decisão | Resposta no exemplo |
|---|---|
| A mudança da regra deve ocorrer nos dois consumidores? | Sim, ambos são públicos e seguem REQ-002. |
| Os formatos precisam se tornar iguais? | Não; títulos e opções mantêm contratos distintos. |
| A regra já tem um dono claro? | Sim, listarAtivos em src/catalogo.mjs. |
| A abstração preserva casos inválidos? | Sim, desde que o validador permaneça no caminho compartilhado. |
| O mesmo helper serve à revisão de todos os registros? | Não; seria outra necessidade, com autorização e contrato próprios. |
Procedimento para integrar a mudança
- Escreva qual conhecimento se repete e quais diferenças são intencionais. Não comece pela meta de reduzir linhas.
- Capture o comportamento atual com exemplos de ativo, inativo, vazio e inválido.
- Reutilize a regra existente ou extraia uma função pequena com nome de intenção. Preserve os formatos dos consumidores.
- Integre logo após a mudança e execute npm test e npm run validate dentro de pratica.
- Examine dependentes, documentação e diff. Registre por que a unificação foi feita e quais contextos ficaram de fora.
Erros que o contador de linhas não detecta
Uma branch longa acumula contratos incompatíveis antes de encontrá-los: integrar cedo reduz o intervalo entre causa e descoberta. DRY automático pode fazer uma tela pública e uma revisão interna compartilharem uma política errada: repare separando os contratos. Um changelog que só diz “refatoração” não mostra o impacto: registre a regra centralizada, as preservações e a verificação feita. Refatorar pretende preservar comportamento, mas essa intenção exige prova adequada; não é necessário inventar uma categoria nova de teste se os testes existentes já protegem o comportamento relevante.
O gate exige testes aplicáveis aprovados, formatos preservados e duplicações ou separações deliberadas com justificativa. Se a extração muda o resultado de um consumidor sem decisão de requisito, ela deixou de ser uma simples preservação de comportamento. Essa diferença precisa ser aceita explicitamente e coberta por prova.
Exercício com resolução
Entrada fornecida: [{id:"a",titulo:"Auditoria",descricao:"Exemplo A",ativo:true},{id:"b",titulo:"Rascunho",descricao:"Exemplo B",ativo:false}]. Calcule os resultados das duas funções e decida se a rotina hipotética que lista todos os IDs deve usar o mesmo filtro.
Ver solução comentada
Resolução: titulosDaLista devolve ["Auditoria"]; opcoesDaReserva devolve [{valor:"a",rotulo:"Auditoria"}]. A rotina interna de todos os IDs espera ["a","b"] e não deve aplicar a política pública. A rubrica exige preservar esses três resultados, justificar a centralização de REQ-002 sem unir formatos e manter inválidos explicitamente rejeitados. Escrever “unificar porque são parecidas” ou “nunca unificar” não demonstra a decisão.
Leitura técnica relacionada
S17: catálogo Refactoring, Extract Function, para nomear e isolar uma intenção. S09: Fowler, Continuous Integration, para integração frequente e verificável. Esses textos apoiam técnicas específicas; a decisão sobre a política pública vem do contrato da Oficina.
Fontes relacionadas
Consulte os limites e as seções de apoio de cada referência.
S17 S09Tente 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.