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.
- Mapeie as premissas do codigo originalQual 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
- Compare premissas com o novo contextoOs 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
- Avalie o custo de bugs vs custo de reescritaSe 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
- Cheque a cobertura de testes do modulo originalSe 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
- Decida: reuso direto, reuso com adaptacao ou reescritaReuso 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.