Experience on Automatically Converting a C++ Monolith to Java EE

Este relatório descreve a experiência e as técnicas utilizadas para converter um grande código C++ monolítico (800 mil linhas) para Java EE, abordando desafios específicos como herança múltipla e a implementação de uma ferramenta baseada em clang-tool para regeneração contínua do código Java.

Andre Vehreschild, Lexi Pimenidis

Publicado Tue, 10 Ma
📖 5 min de leitura🧠 Leitura aprofundada

Each language version is independently generated for its own context, not a direct translation.

Imagine que você tem um castelo medieval gigante (o sistema antigo em C++) que funciona perfeitamente há anos. Ele é feito de pedra bruta, tem corredores secretos e mecanismos complexos. Agora, a empresa decidiu que precisa se mudar para um arranha-céu moderno de vidro e aço (o novo sistema em Java), que segue regras de construção muito diferentes e precisa ser habitado por pessoas que só sabem morar em prédios modernos.

O problema? O castelo tem 800.000 tijolos (linhas de código) e, enquanto a mudança acontece, o castelo continua sendo usado e até sendo reformado! Fazer isso manualmente, tijolo por tijolo, seria como tentar mover um castelo inteiro de pedra com uma colher de chá: demorado, cansativo e cheio de erros.

Aqui está a história de como eles fizeram essa mudança mágica, explicada de forma simples:

1. O Grande Desafio: A "Fábrica de Tradução"

Em vez de contratar uma equipe enorme para reescrever tudo à mão, eles criaram um robô tradutor (chamado de transpiler).

  • A Ferramenta: Eles usaram um "olho" muito esperto chamado Clang-Tool, que consegue ler o código C++ como se fosse um livro, entendendo cada palavra e gramática.
  • O Trabalho: O robô lia o código C++ e escrevia o código Java. Mas, como C++ e Java falam "idiomas" diferentes, o robô precisava de um manual de instruções muito detalhado para não cometer gafes.

2. Os Obstáculos (Os "Monstros" da Tradução)

A tradução não foi perfeita porque os dois idiomas têm regras muito diferentes. O robô teve que aprender a lidar com quatro "monstros" principais:

A. O Monstro das "Duas Mães" (Herança Múltipla)

  • O Problema: No C++, uma classe (um tipo de objeto) podia ter "dois pais" (herdar de duas classes ao mesmo tempo). No Java, isso é proibido; você só pode ter um pai biológico.
  • A Solução Criativa:
    • Se um dos pais fosse um "banco de dados" (DAO), o robô transformou a relação de "filho de" para "tem um". Em vez de herdar o banco de dados, o objeto agora carrega o banco de dados no bolso.
    • Se um dos pais fosse uma "corrente de comando" (Chain of Command), o robô reescreveu a lógica para que o objeto passasse a mensagem de um para o outro, como um jogo de "telefone sem fio", em vez de herdar diretamente.

B. O Monstro das "Listas de Compras" (Enums vs. Inteiros)

  • O Problema: No C++, você podia pegar um número qualquer (como 42) e jogá-lo dentro de uma "caixa de cores" (enum) sem pensar muito. O Java é mais rigoroso: se a caixa diz "Vermelho, Preto, Branco", você não pode colocar um "42" lá dentro.
  • A Solução Criativa: O robô transformou essas caixas simples em robôs inteligentes. Agora, em vez de apenas um número, o "Vermelho" é um pequeno objeto que sabe seu próprio número. Se alguém tentar colocar um número errado, o robô Java grita "Erro!" e para tudo, evitando que o sistema quebre silenciosamente.

C. O Monstro da "Morte" (Destrutores)

  • O Problema: No C++, quando um objeto morre (sai da memória), ele tem um "ritual de despedida" (destrutor) para limpar a bagunça (fechar arquivos, liberar memória). No Java, não existe funeral; o "Lixo" (Garbage Collector) vem e joga tudo fora quando quer.
  • A Solução Criativa: Eles usaram uma técnica chamada "Tentativa com Recursos" (Try with Resources). É como se, ao entrar em um quarto, você fosse obrigado a pegar uma chave de saída. Quando você sai do quarto (o bloco try), a porta se tranca automaticamente e limpa a bagunça, não importa se você saiu correndo ou calmamente.

D. O Monstro da "Escrita e Leitura" (Streams)

  • O Problema: O C++ escreve textos como se estivesse jogando peças de Lego em uma esteira (cout << "Olá" << 42). O Java prefere escrever tudo em um bloco de notas primeiro (StringBuilder) e só depois mostrar.
  • A Solução Criativa: O robô aprendeu a pegar as peças de Lego do C++ e montá-las em um bloco de notas eficiente do Java, garantindo que a mensagem final saísse exatamente igual, só que de forma mais organizada.

3. O Processo de Refinamento (O "Ajuste Fino")

O robô não foi perfeito de primeira. Ele deixou cerca de 10 classes com "arranhões" (erros).

  • A Estratégia: Em vez de tentar consertar o robô para sempre (o que seria caro e difícil), eles criaram um sistema de verificação automática. Toda vez que o código C++ era atualizado, o robô traduzia tudo de novo. Se o resultado fosse igual a um modelo de erro conhecido, o sistema avisava: "Ei, essa parte precisa de um ajuste manual!".
  • Isso permitiu que a empresa continuasse trabalhando no C++ antigo enquanto o novo sistema Java ia sendo polido.

4. O Resultado Final

Ao final do projeto:

  • O número de erros de compilação caiu drasticamente (como se o robô estivesse aprendendo a andar de bicicleta).
  • Restaram apenas cerca de 60 erros pequenos, que foram corrigidos manualmente por humanos.
  • O sistema novo rodou no servidor (WildFly) e funcionou perfeitamente.

Em resumo: Foi como transformar um castelo medieval em um arranha-céu moderno usando um robô que lia os planos antigos e desenhava os novos. O robô não foi perfeito, mas foi rápido o suficiente para que a empresa não parasse de trabalhar, e com um pouco de ajuda humana no final, o prédio novo ficou pronto, seguro e moderno.