Pular para o conteúdo
Boas Praticas

Reuso de Codigo: Quando Reaproveitar e Quando

Reuso de codigo e considerado boa pratica. Ate voce reutilizar o modulo errado no contexto errado e explodir um foguete. Esse artigo te da um framework pra decidir

Reuso sem auditoria e roleta russa

Reuso de codigo e considerado boa pratica. Ate voce reutilizar o modulo errado no contexto errado e explodir um foguete. Esse artigo te da um framework pra decidir quando reaproveitar e quando reescrever.

O caso Ariane 5: quando reuso vira desastre

O sistema de referencia inercial (SRI) do Ariane 5 era um modulo reutilizado diretamente do Ariane 4. Naquele foguete, funcionou por anos sem problema nenhum. O codigo era estavel, testado e confiavel. Por que nao reaproveitar?

O problema: o Ariane 5 tinha uma trajetoria de lancamento completamente diferente do Ariane 4. A velocidade horizontal do Ariane 5 era muito maior no inicio do voo. O modulo SRI convertia a velocidade horizontal de float 64 bits pra inteiro de 16 bits. No Ariane 4, o valor nunca passava de 32.767 (limite de int16). No Ariane 5, passava. Overflow. Boom.

O relatorio oficial do acidente foi claro: o erro nao era do codigo. O codigo fazia exatamente o que foi programado pra fazer. O erro era da decisao de reutilizar sem revalidar. A equipe assumiu que 'se funcionou antes, funciona agora' sem verificar se as condicoes mudaram.

E essa e a armadilha do reuso: codigo que funciona perfeitamente num contexto pode ser letal em outro. A qualidade do codigo e irrelevante se as premissas do ambiente mudaram. E premissas mudam o tempo todo — novos volumes de dados, novas regras de negocio, novas integrações, novos padroes de uso.

Framework de decisao: reaproveitar ou reescrever?

Nem todo reuso e ruim. E nem toda reescrita e justificada. O problema e que devs tendem a ir pra extremos: ou copiam tudo sem pensar, ou querem reescrever do zero 'porque o codigo antigo e feio'. Os dois extremos sao caros. Voce precisa de criterios objetivos.

  1. Mapeie as premissas do codigo original
    Qual era o volume de dados? Quais eram os ranges de input? Qual era o ambiente de execucao? Quais eram as dependencias externas? Se voce nao consegue responder essas perguntas, voce nao conhece o codigo bem o suficiente pra reutilizar.
    completed
  2. Compare premissas com o novo contexto
    Os ranges de input sao compativeis? O volume de dados e similar? O ambiente de execucao e o mesmo? Se qualquer premissa mudou significativamente, o modulo precisa ser auditado linha por linha antes de reutilizar.
    completed
  3. Avalie o custo de bugs vs custo de reescrita
    Se o modulo e de pagamento e um bug causa perda financeira direta, o custo de um bug e altissimo. Nesse caso, reescrever do zero com testes pode ser mais barato que arriscar um reuso mal auditado. Se o modulo e de UI e o pior cenario e um botao desalinhado, reuso faz mais sentido.
    in-progress
  4. Cheque a cobertura de testes do modulo original
    Se o modulo tem 90%+ de cobertura com testes relevantes (nao so de happy path), o risco de reuso diminui drasticamente. Se nao tem testes, voce ta reutilizando codigo que nunca foi provado que funciona — so deu sorte ate agora.
    in-progress
  5. Decida: reuso direto, reuso com adaptacao ou reescrita
    Reuso direto: premissas identicas, testes cobrindo edge cases. Reuso com adaptacao: premissas parcialmente compativeis, precisa ajustar ranges/validacoes. Reescrita: premissas incompativeis ou custo de bug supera custo de reescrita.
    upcoming

Esse framework nao e perfeito, mas e infinitamente melhor que 'acho que da pra copiar' ou 'acho que precisa reescrever'. Pelo menos forca voce a pensar nas premissas antes de tomar a decisao.

Auditando codigo legado antes de migrar

Voce decidiu que vale a pena reaproveitar o modulo, mas precisa auditar antes. Como fazer isso de forma sistematica, sem gastar 3 meses lendo cada linha?

Checklist de auditoria de codigo legado

  • Mapear todas as dependencias externas do modulo (APIs, bancos, filas, etc.)
  • Identificar todos os inputs do modulo e seus ranges esperados
  • Verificar se existem hardcoded values que dependem do contexto original
  • Checar se os tipos de dados sao compativeis (int32 vs int64, float vs decimal, etc.)
  • Rodar analise estatica (SonarQube, CodeClimate) pra encontrar code smells
  • Executar os testes existentes no novo ambiente e verificar se passam
  • Criar testes de limite especificos pro novo contexto (novos ranges, novos volumes)
  • Documentar premissas do codigo original e do novo contexto lado a lado

O ponto 3 e o mais subestimado. Valores hardcoded sao premissas escondidas. Um timeout de 5000ms que funcionava quando o servico ficava na mesma rede pode ser insuficiente quando o servico migra pra outra regiao. Uma constante de MAX_ITEMS = 1000 que fazia sentido quando o sistema tinha 50 usuarios pode virar gargalo com 50 mil.

Dica pratica: faz um grep por numeros magicos (constantes numericas sem nome) e por valores de configuracao hardcoded. Cada um e uma premissa implicita que precisa ser validada no novo contexto.

Migracoes seguras com Strangler Fig

Quando a auditoria mostra que o modulo precisa de mudancas significativas, mas voce nao pode parar tudo pra reescrever, o padrao Strangler Fig e a melhor abordagem. O nome vem da figueira estranguladora — uma planta que cresce em volta de uma arvore existente ate substitui-la completamente.

A ideia e simples: em vez de substituir o sistema legado de uma vez (big bang rewrite), voce cria o sistema novo ao lado do antigo e migra funcionalidade por funcionalidade. O sistema antigo continua rodando enquanto o novo vai assumindo. Quando todo o trafego ja usa o novo, voce desliga o antigo.

Big Bang Rewrite

+ Prós

  • • Codigo novo limpo sem compromissos
  • • Sem complexidade de manter dois sistemas
  • • Mais satisfatorio pro dev (sensacao de progresso)

− Contras

  • • Risco altissimo — tudo muda de uma vez
  • • Meses ou anos ate o novo sistema estar pronto
  • • Bugs novos substituem bugs conhecidos
  • • Historia mostra que falha mais do que funciona (Netscape 6)

Strangler Fig (gradual)

+ Prós

  • • Risco baixo — cada migracao e pequena e reversivel
  • • Sistema antigo continua funcionando durante a transicao
  • • Valor entregue incrementalmente, nao so no final
  • • Facil de pausar ou cancelar se prioridades mudarem

− Contras

  • • Complexidade de manter dois sistemas em paralelo
  • • Precisa de proxy/router pra direcionar trafego
  • • Pode demorar mais no total
  • • Precisa de disciplina pra nao abandonar a migracao no meio

Na pratica, o Strangler Fig funciona assim: voce coloca um proxy na frente do sistema legado. Quando constroi uma feature nova, o proxy redireciona o trafego daquela rota pro novo servico. Rotas que ainda nao foram migradas continuam indo pro legado. Com o tempo, todas as rotas apontam pro novo sistema e o legado e desativado.

Netflix usou esse padrao pra migrar do datacenter proprio pra AWS ao longo de 7 anos. Shopify usou pra migrar do monolito Rails pra microsservicos. As duas migracoes foram bem-sucedidas justamente porque nao tentaram fazer tudo de uma vez.

Casos reais: Netflix e Shopify

Netflix: 7 anos de migracao incremental

Em 2008, a Netflix sofreu uma corrupcao de banco de dados que derrubou o servico de entrega de DVDs por 3 dias. Esse incidente convenceu a lideranca de que precisavam migrar pra cloud. Mas em vez de tentar reescrever tudo, eles adotaram uma estrategia incremental.

Primeiro migraram os sistemas que nao tocavam no video streaming — billing, metadata, recomendacoes. Depois foram migrando os servicos mais criticos um por um. O streaming em si foi o ultimo a migrar. A Netflix so desligou o ultimo servidor de datacenter em janeiro de 2016 — quase 8 anos depois do inicio.

O resultado? Zero downtime durante a migracao. E o sistema novo era dramaticamente mais resiliente. Se tivessem tentado um big bang rewrite, a chance de o Netflix ficar fora do ar por dias durante a transicao seria alta.

Shopify: do monolito aos componentes

O Shopify roda em um dos maiores monolitos Rails do mundo. Em vez de migrar pra microsservicos (o hype da epoca), eles adotaram uma abordagem diferente: modularizaram o monolito. Extrairam dominios de negocio em componentes isolados dentro do mesmo codebase, com fronteiras bem definidas.

Quando um componente ficava maduro o suficiente e precisava de escala independente, ai sim era extraido pra um servico separado. Nao todos de uma vez. Nao porque 'microsservicos sao o futuro'. So quando havia necessidade concreta.

A licao dos dois casos e a mesma: migracoes bem-sucedidas sao incrementais. Voce nao precisa reescrever tudo. Precisa reescrever o que importa, quando importa, e manter o resto funcionando enquanto isso.

Migre com seguranca, construa com confianca

No CrazyStack voce aprende arquitetura de software na pratica. Como estruturar codigo pra facilitar migracoes futuras, como auditar legado e como fazer deploys incrementais sem quebrar producao.

Acesse crazystack.com.br e aprenda do jeito certo.