Ir para o conteúdo
14 de ago. de 2026·6 min de leitura

Quando a aceitação de sistema legado significa algo?

A aceitação de sistema legado exige replay de tráfego, reconciliação até o centavo, rollback testado e transferência verificável.

Quando a aceitação de sistema legado significa algo?

Aceitação não é reunião, assinatura nem uma semana calma após o lançamento. Um sistema reescrito é aceitável quando o comprador prova que ele preserva o comportamento necessário, explica cada diferença financeira, sobrevive a uma reversão ensaiada e pode ser operado sem a equipe da reescrita presente.

Esse padrão parece severo até uma reescrita falhar. Então as provas ausentes aparecem juntas: ninguém sabe se um resultado diferente é correção ou regressão, totais divergem em centavos por milhares de registros, o procedimento de reversão contém comandos nunca executados e os engenheiros descobrem dependência não documentada dos autores. A aceitação deve revelar isso enquanto o projeto ainda pode agir.

A aceitação começa com um contrato de evidências

Defina a aceitação antes da implementação, pois a equipe precisa saber quais afirmações provará. “Funciona como o sistema antigo” não é testável. Troque por regras observáveis, dados nomeados, tolerâncias, aprovadores e evidências que permaneçam após a decisão.

Separe quatro decisões. Paridade funcional pergunta se a mesma solicitação válida produz o mesmo resultado de negócio. Reconciliação financeira verifica lançamentos, saldos, impostos, arredondamentos e alocações no nível contábil exigido. Aceitação operacional pergunta se a equipe consegue implantar, monitorar, restaurar e reverter. Aceitação de propriedade pergunta se ela consegue alterar o sistema depois da saída dos autores.

Cada decisão precisa de responsável. Produto ou operações aprovam mudanças intencionais. Finanças define tolerâncias e assina a reconciliação. O dono do serviço aceita procedimentos e riscos. Segurança revê limites de confiança. Um comitê pode receber decisões, mas não substituir responsáveis por uma média de opiniões.

Use uma matriz pequena. Para cada afirmação, registre fonte, regra de aprovação, exceção, aprovador e retenção. “99% coincide” não é regra sem explicar qual 1% pode divergir. Uma diferença num relatório regulatório pesa mais que dez mil diferenças de espaços.

Congele o contrato pelo controle de mudanças. Um caso novo pode justificar outra regra, mas a equipe não pode afrouxar tolerância porque a reescrita falhou. Registre autor, motivo e resultados invalidados, ou a meta se moverá diante de cada dificuldade.

Defina o ambiente: imagens do sistema, extensões do banco, locale, fusos, broker, flags e dados de referência. Resultado de ambiente sem nome não é reproduzível. “Parecido com produção” não basta. Dê um identificador e inclua o digest da configuração em cada pacote.

Desempenho entra no contrato quando tempo altera o negócio. Especifique carga, concorrência, volume, aquecimento e percentis na fronteira real. Um lote correto depois do corte matinal falhou. Uma resposta lenta que provoca repetição e duplicidade também. Desempenho não compensa paridade funcional.

A nova arquitetura não precisa parecer com a antiga. Paridade comportamental e de implementação são afirmações distintas. Copiar um lote COBOL num serviço Go preserva estrutura acidental e dificulta a propriedade. Aceite comportamento nas fronteiras e julgue o interior por práticas atuais.

O contrato também precisa dizer quem pode alterar uma exceção e por quanto tempo a prova vale. Relacione cada regra à versão exata do código, do esquema e dos dados de referência. Se uma flag, tabela cambial ou política contábil mudar, identifique quais execuções precisam ser refeitas. Uma assinatura antiga não aprova automaticamente uma versão futura com o mesmo nome.

Tráfego gravado é evidência, não uma suíte completa

Tráfego de produção gravado mostra melhor o que chamadores fazem, mas prova apenas a janela capturada. Use-o como corpus de caracterização e acrescente caminhos raros, destrutivos, sazonais e juridicamente sensíveis.

Em Working Effectively with Legacy Code, Michael Feathers descreve testes de caracterização como registros do comportamento atual. Isso serve para reescritas porque a implementação antiga costuma ser a última especificação precisa. A ressalva é simples: saída gravada prova comportamento atual, não comportamento correto.

Capture numa fronteira com significado: gateway HTTP, tópico, entrada em lote, terminal, arquivo, procedure ou job. Guarde roteamento, autorização, locale, data de negócio e estado funcional. Não colete segredos porque estão disponíveis. Tokenize contas, remova credenciais e guarde mapeamento apenas quando a identidade estável for necessária.

Cada caso precisa de ID imutável e origem: versão, hora, solicitação, snapshot, saídas e transformação de limpeza. Calcule hashes da captura e do fixture. Assim o revisor sabe se teste ou sistema mudou.

Um envelope útil:

{
  "case_id": "close-004812",
  "captured_at": "2026-03-31T23:58:14Z",
  "business_date": "2026-03-31",
  "request": {"operation": "post_invoice", "invoice_ref": "TKN-8821"},
  "state_snapshot": "sha256:7d3f...",
  "expected": {
    "status": "posted",
    "ledger_delta_minor": 18425,
    "events": ["invoice.posted"]
  }
}

Dinheiro fica em unidades menores porque ponto flutuante é uma fronteira ruim. ID de mensagem e horário podem variar conforme a política.

A amostra pode omitir fechamentos, falhas escondidas por repetição e correções administrativas. Acrescente ano bissexto, arquivo vazio, tamanho máximo, duplicata, estorno, timeout após commit e lote parcial. Use procedimentos, incidentes, suporte e esquema. Pergunte a quem fecha os livros onde o código mente.

Reprodução não pode repetir efeitos externos. Direcione emails, pagamentos, arquivos e mensagens a dublês isolados. Se a solicitação não puder ser inofensiva, use caminho sombra sem commit. Um harness capaz de cobrar cliente não é ferramenta de aceitação.

Rotule a amostra por operação, classe de cliente, canal, moeda, autorização, data e tipo de falha. Contar casos sem essas dimensões engana: milhares de consultas simples não cobrem um único estorno ou fechamento. Registre ainda versão da origem, snapshot e transformação de limpeza, pois o revisor precisa distinguir uma mudança de fixture de uma mudança real no programa.

Paridade exige uma política explícita

Saídas raramente merecem comparação byte a byte. Defina antes quais diferenças importam. Normalize campos voláteis, compare campos significativos exatamente e classifique o restante.

Compare resposta, banco, mensagens, arquivos, logs de auditoria e tempo observável. JSON igual pode esconder lançamento ausente; linhas corretas podem vir com eventos em ordem incompatível. Comparar só a superfície fácil cria confiança falsa.

Normalize pouco. Substitua IDs apenas se identidade não importa. Reduza precisão temporal apenas se a ordem não importa. Ordene coleções apenas se o contrato permitir. Nunca remova campo porque varia; primeiro descubra seus consumidores.

O resultado deve ser legível sem o código:

{
  "case_id": "close-004812",
  "result": "FAIL",
  "comparisons": [
    {"path": "$.status", "expected": "posted", "actual": "posted", "rule": "exact"},
    {"path": "$.ledger_delta_minor", "expected": 18425, "actual": 18424, "rule": "exact"},
    {"path": "$.processed_at", "expected": "<timestamp>", "actual": "<timestamp>", "rule": "normalized"}
  ]
}

Use quatro resultados: passou, mudança esperada, defeito conhecido e diferença inexplicada. “Quase igual” não existe. Mudança aponta para decisão; defeito tem dono; diferença inexplicada bloqueia.

Meça cobertura por operação, classe de conta, canal, autorização, moeda, data, erro e efeito. Informe cruzamentos vazios. Dez mil consultas não compensam nenhum estorno.

Execute ambos contra estado inicial controlado. Restaure snapshots ou isole cópias. Congele relógios, sementes, câmbio e configuração. Capture respostas externas mutáveis.

Não gere o esperado com a implementação nova. Aprovar sua saída e salvá-la prova repetibilidade, não paridade. O oráculo vem do sistema antigo, regra independente ou livros reconciliados.

Mantenha quatro estados visíveis no relatório. Um caso aprovado coincide segundo a regra. Uma mudança esperada aponta para decisão e novo teste. Um defeito conhecido aponta para dono e tratamento. Uma diferença inexplicada bloqueia a afirmação. Não transforme o último estado em “aceitável” apenas para melhorar um percentual agregado.

Reconcilie dinheiro na fronteira contábil

Aceitação financeira exige igualdade exata e explicação de cada diferença intencional. Totais agregados escondem erros compensados, duplicatas, datas erradas e valores na conta errada.

Compare na representação da regra: centavos inteiros ou decimal fixo por moeda. Não use planilhas que convertem tipos ou exibem arredondamento diferente do valor armazenado.

Compare contagens e IDs, depois cada linha por entidade, conta, moeda, data, débito ou crédito e valor. Em seguida compare totais de controle, saldos e relatórios. Cada camada reduz a busca.

Anti-join mostra lançamentos ausentes; agrupamento mostra valores diferentes. Adapte a consulta Postgres à identidade real:

WITH old_totals AS (
  SELECT entity_id, account_code, currency, effective_date,
         SUM(amount_minor) AS amount_minor, COUNT(*) AS line_count
  FROM old_postings
  GROUP BY entity_id, account_code, currency, effective_date
),
new_totals AS (
  SELECT entity_id, account_code, currency, effective_date,
         SUM(amount_minor) AS amount_minor, COUNT(*) AS line_count
  FROM new_postings
  GROUP BY entity_id, account_code, currency, effective_date
)
SELECT COALESCE(o.entity_id, n.entity_id) AS entity_id,
       COALESCE(o.account_code, n.account_code) AS account_code,
       COALESCE(o.currency, n.currency) AS currency,
       COALESCE(o.effective_date, n.effective_date) AS effective_date,
       o.amount_minor AS old_amount, n.amount_minor AS new_amount,
       o.line_count AS old_lines, n.line_count AS new_lines
FROM old_totals o
FULL OUTER JOIN new_totals n USING (entity_id, account_code, currency, effective_date)
WHERE o.amount_minor IS DISTINCT FROM n.amount_minor
   OR o.line_count IS DISTINCT FROM n.line_count;

Dimensões exatas devem retornar zero linhas. Tolerância precisa ser específica por regra e conta. Um centavo em um milhão de lançamentos não é pequeno; saldo líquido zero pode esconder contas trocadas.

Teste arredondamento: meio para cima, par, truncamento, regra da moeda e etapa. round(sum(x), 2) difere de sum(round(x, 2)). Preserve a distribuição de restos, salvo política nova aprovada.

Guarde snapshot, versão da consulta, contagens, linhas sem par, diferenças, totais, executor e aprovação. Guarde exceções, não uma tela verde. Finanças deve rastrear o total até os lançamentos.

Faça a reconciliação em camadas e conserve a saída de cada uma. Primeiro identidades e contagens, depois linhas, totais de controle e saldos finais. Investigue diferenças que se compensam, datas efetivas erradas e valores corretos na conta errada. Uma tolerância permitida para determinada alocação não autoriza diferença igual em impostos, caixa ou contas de controle.

Paridade não preserva todo defeito antigo

Preserve
comportamento,

Resultado surpreendente precisa de classificação: obrigatório, tolerado, acidental ou proibido. Cada desvio recebe decisão.

Obrigatório inclui cálculos contratuais, formatos consumidos, fluxos e controles. Tolerado pode ser estranho mas usado. Acidental não tem consumidor e contradiz a regra. Proibido viola política ou cria risco.

“Limpar tudo” durante a reescrita é popular porque defeitos aparecem e o código parece fácil. É má estratégia. Misturar mudança funcional e plataforma torna diferenças ambíguas e amplia reversão. Preserve o necessário, isole correções aprovadas e adie o resto.

Para cada mudança, mantenha caso e saída antiga, aprovador e saída nova. O relatório marca “mudança esperada”. Sistemas consumidores precisam aceitar o contrato alterado.

Correções de segurança podem ser imediatas. Não reproduza exposição ou entrada perigosa para deixar o relatório verde. Registre o controle, teste negação e permissão e trate o risco de rollback.

Essa classificação evita transliteração. Pode-se preservar comportamento e trocar tabelas por filas, dividir monólito ou mover cálculo para Rust. Aceitação observa contratos, não estrutura morta.

Mantenha o log legível: IDs, comportamentos, motivo, aprovador, impacto, rollback e data. Centenas de diferenças sem explicação não viram aceitas por serem chamadas de conhecidas.

O ensaio de reversão deve mudar estado real

Leia
toda

Rollback só é crível após operação em ambiente semelhante, restauração do estado e retomada sem perda ou duplicidade. Ler runbook não testa acesso, artefato, fila ou coordenação.

Escolha unidade e último ponto seguro. Após escritas novas, o antigo consegue ler ou reproduzir, ou o rollout deve parar? Essa decisão precede o lançamento.

Escrita dupla adiciona outro comportamento: quando uma gravação falha. Sem ordem, repetição e idempotência, ela aumenta ambiguidade. Um diário durável com replay testado pode ser melhor.

Use identidades de produção e o engenheiro de plantão. Não conceda acesso amplo temporário. Busque artefato fixado, altere rota, restaure estado e execute transações.

Registre cinco fatos:

  1. Gatilho e autoridade.
  2. IDs dos artefatos.
  3. Última e primeira transações.
  4. Reconciliação do intervalo.
  5. Tempo e intervenção.

Injete complicação: mensagem em voo, dependência lenta, troca de turno ou escrita reversível. Isso testa onde runbooks falham.

Depois compare filas, jobs, totais, autorização e confirmações. Verifique duplicatas e caches. Guarde horários dos sistemas, não narrativa posterior.

Se rollback é impossível, chame de recuperação para frente. Teste desativação, reparo e correção. Não assine capacidade falsa.

Depois da mudança de rota, valide mais que a saúde do endpoint. Compare profundidade das filas, jobs agendados, autorizações, totais e confirmações dos consumidores. Marque a última transação antes da troca e a primeira depois da recuperação. Reconcilie o intervalo para provar que repetição não duplicou trabalho e que nenhuma mensagem ficou perdida entre os dois lados.

A transferência prova propriedade por ação

Engenheiros são donos quando explicam, operam, diagnosticam, alteram, implantam e recuperam sem ajuda privilegiada. Documentos são insumo, não prova.

A equipe receptora deve rastrear solicitação, diagnosticar falha, mudar regra e teste, compilar, implantar, reverter, ensaiar recuperação e reconciliar transações.

Se não explica normalização, não possui a política. Se só o fornecedor gera cliente ou gira segredo, não possui build. Conta ausente do inventário significa operação sem dono.

O pacote inclui:

  • Repositórios, builds, locks, geração e regras de propriedade.
  • Decisões, contratos, modelos, ameaças e diferenças.
  • Runbooks de implantação, rollback, backup, restauração, migração, reconciliação e incidente.
  • Painéis, alertas, objetivos, campos e consultas.
  • Acessos, segredos, licenças, suporte e riscos.

Fixe versões e faça build limpo no ambiente do receptor. Arquive ferramentas quando permitido. Build preso ao computador do autor está incompleto. Documente artefatos gerados e comandos.

CodeHero prende o comportamento ao original com harness de paridade sobre tráfego gravado enquanto moderniza a arquitetura; o harness deve ficar como regressão do cliente. Em ambiente regulado, instalação isolada exige donos para modelos, hardware, atualizações, acessos e exportação.

Liste dependências comerciais e técnicas: build hospedado, pacote, licença, credencial, alerta, modelo ou aprovação. Remova, transfira ou aceite. Suporte não substitui propriedade.

Termine com explicação reversa pelos receptores: arquitetura, riscos, limite, exceções e incidente. Registre lacunas com donos e datas.

A equipe receptora deve demonstrar uma mudança pequena de ponta a ponta: editar regra, atualizar teste, executar build limpo, implantar num ambiente controlado e desfazer. Ela também precisa diagnosticar uma falha sem chamar os autores. Esse exercício encontra dependências escondidas em contas, pacotes privados, geradores, licenças e destinos de alerta que uma lista de documentos não revela.

A assinatura deve ser reproduzível

Mantenha
código

A assinatura identifica versão, evidências, exceções, riscos e pessoas. Um ausente deve reconstruir a decisão e repetir verificações.

Crie índice imutável com commits, digests, corpus, política, paridade, reconciliação, segurança, desempenho, rollback, transferência, decisões e riscos. Assine ou faça hash e retenha.

Não decida por percentual. Informe por afirmação e dimensão, com casos reais. Finanças precisa de linhas e valores; operações, ensaio; propriedade, tarefas e lacunas.

Risco residual fica no registro: condição, impacto, detecção, contenção, dono e revisão. Ressalva sem dono é trabalho pendente.

Defina expiração. Release, normalização, esquema, canal ou política nova invalida evidência. O índice diz o que repetir. Aceitação vale para sistema e condições identificados.

O gate deve ser estreito: nenhuma diferença inexplicada no obrigatório, reconciliação aprovada, recuperação executada e exercícios concluídos. Exceção precisa de autoridade.

O índice final liga commits, digests dos artefatos, versão do corpus, política de comparação, relatório de paridade, pacote financeiro, revisão de segurança, desempenho, ensaio de recuperação, transferência, decisões e riscos. Assine ou calcule o hash desse índice. Alguém ausente da reunião deve conseguir reconstruir a decisão e repetir a verificação material sem depender da memória do projeto.

Eu rejeitaria código bonito com evidência fraca. Aceitaria uma lista curta de defeitos se comportamento coincide, contas fecham, recuperação funciona e plantonistas conseguem alterar o sistema. A assinatura apenas registra o que máquinas, contas e pessoas já provaram.

Perguntas frequentes

O

que

Tráfego

gravado

Quanta

paridade

Devemos

preservar

Como

reconciliar

Paridade

exige

Como

testar

E

se

Quais

artefatos

Quem

aprova