
Uma exportação de faturas inclui cobranças canceladas. A correção parece caber em uma condição, mas o método consulta o banco, lê a data atual e envia o arquivo a um provedor. Para observar o resultado, alguém precisa subir a aplicação inteira. O risco está no caminho até a condição e nos comportamentos que ninguém sabe enumerar.
Working Effectively with Legacy Code ajuda a enfrentar esse tipo de manutenção. Minha recomendação é lê-lo quando você precisa mudar software existente e ainda não consegue produzir evidência suficiente sobre a mudança. Seu valor aparece antes da refatoração elegante: encontrar uma entrada pequena para observar o que está acontecendo.
A referência aqui é a primeira edição, de Michael Feathers. A ficha da Pearson registra publicação em 22 de setembro de 2004 e copyright de 2005. Os exemplos usam Java, C++ e C#. Essa diferença entre publicação e copyright explica as duas datas encontradas em referências bibliográficas.
A organização favorece consulta por problema: dificuldade para testar uma classe, dependências de bibliotecas e métodos grandes aparecem no sumário. Você pode começar pela dificuldade da sua próxima tarefa, depois voltar aos conceitos que sustentam a técnica. Isso torna a leitura útil mesmo quando não há espaço para estudar o livro inteiro antes de uma entrega.
Feathers usa código sem testes como definição operacional de legado. A idade deixa de ser o critério decisivo. Um serviço criado recentemente pode exigir tanta confiança pessoal quanto um programa antigo se ninguém consegue verificar seu comportamento automaticamente.
Essa definição é produtiva para orientar uma intervenção, mas estreita como diagnóstico completo. Uma aplicação com testes ainda pode depender de um runtime sem suporte, ter vulnerabilidades ou concentrar conhecimento em uma pessoa. A leitura deve ampliar sua capacidade de mudar código, sem reduzir toda dívida técnica à falta de testes.
Para a rotina de faturas, a pergunta inicial passa a ser concreta: qual resultado precisamos observar para modificar a seleção de cobranças? Examinar o arquivo produzido oferece uma primeira fronteira. Testar todas as classes envolvidas seria um objetivo maior, com custo e escopo diferentes.
No texto Characterization Testing, Feathers distingue investigar o comportamento existente de verificar o comportamento desejado. Essa separação é a ideia mais importante para aproveitar o livro sem criar uma coleção de bugs congelados.
No nosso exemplo original e hipotético, a primeira observação mostra uma cobrança cancelada no CSV. Registrar esse resultado permite detectar quando ele muda. Ainda precisamos perguntar ao responsável pelo processo se isso representa defeito, compatibilidade necessária ou uma regra incompleta. O teste sozinho não fornece essa resposta.
Depois de confirmar o defeito, escreva uma expectativa nova para a exclusão da cobrança cancelada. A implementação antiga deve falhar nessa expectativa. Após a correção, atualize o teste que documentava o comportamento anterior e explique a decisão. Mantenha os casos de cobranças válidas protegidos. Misturar descoberta, julgamento e correção em uma expectativa única dificulta a revisão.
Uma seam, ou costura, permite substituir comportamento sem editar o ponto onde ele é usado. Seu ponto de habilitação escolhe a implementação. Feathers apresenta essas distinções em Seam Types. No caso abaixo, a montagem da rotina pode escolher uma consulta em memória e um destino que apenas captura o arquivo.
Encontrar essa possibilidade exige seguir dependências reais. Um construtor pode abrir conexão antes de executar a regra. Um import pode carregar configuração. Uma função aparentemente pura pode ler uma variável global. Trocar apenas o envio não resolve o problema se o acesso ao banco acontece antes.
Por isso considero a linguagem de costuras mais útil que a recomendação genérica de adicionar mocks. Ela obriga a perguntar onde a substituição acontece e como o teste a seleciona. Uma interface desenhada sem essa inspeção pode aumentar o número de arquivos sem tornar o fluxo executável isoladamente.
Produtos gratuitos e pagos para transformar ideias em uma base que você consegue executar.
13 produtos disponíveisContinue explorando tópicos similares

Aprenda com Kent Beck a transformar requisitos em passos pequenos de feedback, sem confundir testes verdes com produto correto.

Resenha de Refactoring, segunda edição: passos pequenos, testes e contratos, com exemplo executável, críticas e um roteiro de aplicação.

Aplique Michael Nygard a timeouts, isolamento e recuperação com um exercício de falha controlada.
Checklist de 47 pontos para encontrar bugs, riscos de segurança e problemas de performance antes do lançamento.
Templates testados em produção, usados por desenvolvedores. Economize semanas de setup no seu próximo projeto.
Considere este exercício de projeto, criado para a resenha. A rotina recebe um identificador de cliente, busca cobranças, calcula totais, formata CSV e o envia. O objetivo é excluir cobranças canceladas, preservando a ordem das demais linhas e o arredondamento já utilizado. Não há dados nem resultados de produção neste caso.
Comece desenhando o fluxo e os efeitos. A consulta precisa devolver identificador, estado, valor e vencimento. O destino recebe o conteúdo gerado. Uma data de referência decide quais cobranças entraram no período. Esses são candidatos a entradas controláveis; a transformação entre eles é o trecho que queremos executar.
Se a rotina já recebe um objeto de consulta, use essa costura. Se instancia um cliente internamente, avalie introduzir um parâmetro opcional cujo padrão mantém o cliente atual. Preserve o caminho de produção durante essa alteração. Revise chamadas posicionais, inicialização e tratamento de erro antes de concluir que adicionar um parâmetro não mudou comportamento.
A substituição da consulta retorna um conjunto pequeno e explícito. O destino de teste captura o CSV e registra quantas vezes foi chamado. A data fica fixa. Assim você pode executar a transformação sem banco, rede ou credenciais. O teste continua usando a implementação real da seleção e da formatação; substituir também essas partes apagaria justamente a evidência procurada.
Monte os casos abaixo. Os resultados são expectativas desse exercício, sujeitas à validação do domínio em um projeto real.
| Entrada | Observação que interessa |
|---|---|
| Uma cobrança válida | Valor e identificador permanecem no arquivo |
| Válida seguida de cancelada | O caso corrigido contém apenas a válida |
| Duas válidas com centavos | Ordem e regra de arredondamento permanecem |
| Nenhuma cobrança elegível | Comportamento do arquivo vazio e do envio fica explícito |
| Falha na consulta | O destino não recebe um arquivo parcial |
Use comparações específicas para campos importantes. Se o contrato exige bytes exatos, compare também separador, codificação e quebra de linha. Evite normalizar o CSV até o teste ignorar uma diferença que o consumidor considera relevante. A remoção de um timestamp volátil precisa preservar um teste separado sobre seu formato, quando houver esse contrato.
Para tornar a comparação concreta, fixe a data em 2026-10-01 e use três cobranças vencidas em 2026-09-30, nesta ordem: F01, ativa, 1.099 centavos; F02, cancelada, 250 centavos; F03, ativa, 901 centavos. Suponha que a execução controlada anterior à correção produza o CSV abaixo, com separador ; e uma chamada ao destino. É uma baseline hipotética para o exercício; no projeto, ela deve ser obtida da implementação existente.
fatura_id;valor_centavos
F01;1099
F02;250
F03;901
Depois da correção, o resultado esperado mantém o cabeçalho e as linhas F01;1099 e F03;901, nessa ordem, com uma chamada ao destino. A baseline anterior contém F02; a nova expectativa a exclui por uma decisão explícita de negócio. Os valores inteiros evitam acrescentar uma convenção de arredondamento ao exemplo. Se o sistema calcula valores fracionários, outro caso precisa registrar sua regra real de arredondamento.
Agora faça a mudança funcional. O caso da cancelada falha antes e passa depois; os demais devem conservar suas expectativas. Uma revisão consegue distinguir a preparação para testar da alteração de negócio. Essa separação ajuda a localizar regressões e a reverter a correção sem desfazer toda a observabilidade criada.
Existe uma dificuldade circular: precisamos mudar código para conseguir testar código. O livro é especialmente útil por tratar desse ponto de partida imperfeito. A resposta prática exige contenção. Uma alteração mecânica pequena, acompanhada de inspeção, oferece uma superfície de revisão menor que reorganizar toda a classe antes do primeiro teste.
No exercício, extrair a criação do cliente e manter seu padrão é diferente de substituir o acesso inteiro por uma arquitetura de repositórios. A segunda opção pode ser desejável depois. Neste momento, acrescenta decisões sobre interfaces, erros e transações ao mesmo diff que tenta descobrir o comportamento antigo.
Não chame a preparação de comprovadamente segura se os testes ainda não existem. Registre o que foi inspecionado, execute as verificações disponíveis e peça revisão de alguém que conheça o caminho afetado. Havendo uma execução controlada do fluxo completo, compare sua saída antes e depois. Essa evidência continua limitada aos casos exercitados.
O teste com consulta em memória verifica o que a rotina faz com os registros recebidos. Ele não comprova que o SQL busca os registros certos, respeita isolamento ou converte valores corretamente. Preserve um teste de integração do adaptador com dados controlados e o banco compatível com o ambiente real.
O destino capturado também não demonstra que o provedor aceita o arquivo. Formato, autenticação e respostas de erro precisam de verificações próprias. Repetir um envio após timeout pode duplicar efeitos mesmo quando todos os testes locais passam. O risco pede contrato de idempotência ou conciliação, conforme o sistema.
Cobertura de linhas não mede essa distância. Prefiro um teste que acusa a inclusão indevida de uma cobrança a dezenas de expectativas sobre chamadas internas. Pergunte qual alteração errada faria a suíte falhar. Se trocar o estado de uma cobrança não altera resultado algum, investigue a utilidade da asserção antes de aumentar a cobertura.
Os exemplos e o trabalho manual refletem as linguagens e ferramentas da edição. Para quem escreve TypeScript ou Python, é necessário traduzir a intenção de técnicas baseadas em compilação, ligação ou herança. Copiar sua forma literalmente pode introduzir uma solução mais complicada que uma substituição explícita já disponível na linguagem.
Também existe o risco de manter costuras temporárias para sempre. Um parâmetro criado para um teste pode virar parte acidental da API; uma subclasse de teste pode depender demais da estrutura interna. Depois de estabelecer proteção, avalie consolidar a separação e remover mecanismos que deixaram de servir. Testabilidade precisa conviver com clareza do código de produção.
O livro oferece técnicas, não uma estimativa automática de risco. Poucos exemplos de entrada deixam muita coisa desconhecida. Quem procura um método completo de migração de dados, concorrência ou substituição de um sistema distribuído precisará complementar a leitura. Não há obrigação de preservar um desenho inviável apenas porque alguns testes passaram.
Recomendo para quem já conhece testes básicos e mantém uma base difícil de instanciar ou executar. Um desenvolvedor menos experiente pode aproveitar bastante com revisão de alguém que conheça o sistema. Sem noções de dependências e efeitos externos, vale praticar primeiro testes de funções e pequenos objetos.
Na sequência desta série, Refactoring ajuda a escolher movimentos estruturais depois de obter proteção. TDD by Example trabalha o desenvolvimento guiado por expectativas novas. Clean Code ajuda a discutir legibilidade; Feathers enfrenta a pergunta anterior: como executar este trecho sem carregar tudo ao redor?
Se você procura uma primeira introdução à programação, adie esta leitura. Se a dificuldade atual é uma regra nova em um módulo já bem testado, talvez TDD ou Refactoring tragam retorno mais imediato. O custo da leitura se justifica quando o bloqueio é chegar ao código com controle suficiente para mudá-lo.
Escolha uma correção pequena da sua fila. Leia os conceitos de costuras e procure o capítulo ligado ao obstáculo encontrado. Anote o comportamento que precisa mudar, o que deve permanecer e quem pode validar essa distinção. Separe a preparação estrutural da correção funcional na revisão.
O exercício terminou quando outra pessoa consegue executar os casos sem serviços externos, explicar cada expectativa e apontar quais contratos ainda dependem de integração. Depois da entrega, tente uma segunda mudança próxima. Ela deve conseguir reutilizar parte da proteção; se precisa reconstruir tudo, a entrada criada talvez esteja estreita ou acoplada demais.
Minha recomendação é forte para manutenção sob incerteza. O ganho esperado é aprender a produzir evidência onde antes havia apenas leitura e receio. Aplique as técnicas no trecho que precisa mudar, reconheça o alcance dos testes e use a confiança adquirida para melhorar o desenho em passos revisáveis.