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

Dieser Bericht beschreibt die Erfahrungen und Techniken bei der automatisierten Konvertierung einer 800.000 Zeilen großen C++-Monolith-Codebasis in eine Java EE-Anwendung für WildFly, einschließlich der Lösung typischer Sprachkonflikte und der Entwicklung eines clang-basierten Tools zur fortlaufenden Code-Generierung.

Andre Vehreschild, Lexi Pimenidis

Veröffentlicht Tue, 10 Ma
📖 5 Min. Lesezeit🧠 Tiefgang

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

Stellen Sie sich vor, Sie besitzen ein riesiges, altes Fabrikgebäude aus Ziegelsteinen (das ist der C++-Code). Es funktioniert seit Jahren perfekt, ist aber schwer zu reparieren, und die Architekten, die es gebaut haben, werden langsam rar. Die Firma beschließt nun, das gesamte Gebäude abzureißen und an derselben Stelle ein modernes, gläsernes Bürogebäude zu errichten (das ist Java).

Das Tückische: Während der Abriss und der Neubau stattfinden, läuft in der alten Fabrik noch die Produktion weiter. Neue Produkte müssen entwickelt werden, und Fehler müssen behoben werden. Das ist, als würde man versuchen, ein Flugzeug zu reparieren, während es noch fliegt.

Hier ist die Geschichte, wie ein Team versucht hat, diesen gewaltigen Umzug zu meistern, indem sie einen Roboter-Baumeister (einen automatischen Konverter) gebaut haben.

1. Das Problem: Der "Übersetzungs-Roboter"

Das Team wollte nicht jeden einzelnen Ziegelstein von Hand in Glas umwandeln (das wäre zu teuer und fehleranfällig). Stattdessen bauten sie ein Werkzeug, das den alten Code liest und automatisch in neuen Code umschreibt.

Aber Sprachen sind wie Dialekte:

  • C++ ist wie ein wilder, freier Künstler, der alles erlaubt (z. B. dass ein Objekt von zwei verschiedenen Eltern gleichzeitig abstammt).
  • Java ist wie ein strenger Bauinspektor, der klare Regeln hat (ein Objekt kann nur eine direkte Mutter haben).

Der Roboter musste also nicht nur Wörter übersetzen, sondern auch die Logik des Gebäudes umplanen.

2. Die größten Stolpersteine (und wie sie gelöst wurden)

A. Der "Vater-Problem" (Mehrfachvererbung)

In der alten Fabrik gab es Mitarbeiter, die von zwei verschiedenen Abteilungsleitern gleichzeitig befehligt wurden (z. B. ein "Datenbank-Manager" und ein "Befehlsketten-Manager"). Java erlaubt das nicht.

  • Die Lösung: Der Roboter hat diese Doppelrolle getrennt. Statt "Ich bin ein Kind von beiden" wurde daraus: "Ich bin ein Kind von Vater A, und ich habe Vater B als Mitarbeiter in meinem Büro angestellt."
  • Analogie: Statt dass ein Kind zwei Mütter hat, hat es eine Mutter und einen Pate, der ihm hilft.

B. Die "Befehlskette" (Chain of Command)

Einige Teile des Systems funktionierten wie eine militärische Befehlskette: Ein Befehl ging von Person A zu Person B zu Person C. In C++ lief das wie ein Zug, bei dem jeder den nächsten zieht. In Java funktioniert das nicht so einfach.

  • Die Lösung: Der Roboter hat den Zug in ein Rundspiel verwandelt. Ein "Spielleiter" (Chain Manager) ruft jeden Spieler nacheinander auf. Wenn Spieler A fertig ist, ruft er den Spielleiter zurück, der dann Spieler B ruft. Es ist weniger ein Zug, sondern mehr ein Ping-Pong-Spiel, das von einem Schiedsrichter gesteuert wird.

C. Die "Zahlen-Verkleidung" (Enums vs. Integers)

In C++ waren bestimmte Dinge (wie Farben: Rot, Blau) eigentlich nur Zahlen verkleidet. Man konnte eine Farbe einfach in eine beliebige Zahl verwandeln, auch in eine, die gar nicht existierte (z. B. "Farbe 42").

  • Das Problem: Java ist hier viel strenger. Eine Farbe ist eine echte Farbe, keine Zahl.
  • Die Lösung: Der Roboter hat aus den einfachen Zahlen-Listen echte Objekte gemacht. Er baute eine kleine Fabrik, die aus einer Zahl (z. B. 0) automatisch das richtige Farb-Objekt herstellt. Wenn jemand versucht, eine ungültige Zahl (42) zu verwenden, schreit der Roboter: "Das gibt es nicht!" und stoppt den Prozess, statt einen Fehler zu produzieren.

D. Der "Aufräumer" (Konstruktoren und Destruktoren)

In C++ gab es eine Regel: "Wenn du ein Werkzeug nimmst, musst du es auch wieder weglegen, sobald du fertig bist." Das passierte automatisch, wenn ein Objekt "stirbt" (Destruktor).

  • Das Problem: Java hat keine "Todes-Automatik". Es wartet einfach, bis der Müllmann (Garbage Collector) kommt, was zu spät sein kann, wenn wertvolle Ressourcen (wie Datenbank-Verbindungen) verstopft werden.
  • Die Lösung: Der Roboter hat eine Sicherheitsvorrichtung eingebaut. Er fügte einen "Versuch-und-Schutz"-Kasten (try-with-resources) hinzu. Das ist wie ein Timer: Sobald der Kasten geschlossen wird, wird das Werkzeug sofort und garantiert weggelegt, egal ob der Prozess normal endet oder abstürzt.

3. Der Bauprozess: Nicht perfekt, aber gut genug

Der Roboter war nicht fehlerfrei. Er übersetzte etwa 99% des Codes perfekt. Die restlichen 1% (ca. 10 Klassen) waren so speziell, dass der Roboter sie nur "halbwegs" übersetzen konnte.

  • Die Strategie: Das Team nutzte einen "Check-and-Replace"-Ansatz. Der Roboter lieferte den Entwurf, und ein Mensch prüfte nur die kritischen Stellen. Wenn der Roboter eine bekannte Fehlerstelle traf, wurde sie durch eine manuell korrigierte Version ersetzt.
  • Der Clou: Da die alte Fabrik weiterlief, wurde der Roboter bei jeder Änderung im alten Code automatisch neu gestartet. So wussten die Entwickler sofort: "Achtung, der Roboter hat an dieser Stelle wieder einen Fehler gemacht, weil sich der alte Code geändert hat."

4. Das Ergebnis

Am Ende war das alte Ziegelgebäude fast vollständig in ein modernes Glasgebäude umgewandelt.

  • Der Erfolg: Die Anzahl der Fehler beim ersten Starten des neuen Gebäudes sank drastisch.
  • Die Lektion: Am Anfang ging es schnell, aber gegen Ende wurde es schwieriger, die letzten 10 Fehler zu finden (wie bei einem Puzzle, wo die letzten Teile am schwersten zu finden sind).
  • Fazit: Es war kein magischer "Ein-Klick-Lösung", aber durch den Einsatz des Roboters und die klugen Umwege für die schwierigen Fälle gelang es, ein riesiges, laufendes System zu migrieren, ohne den Betrieb zu unterbrechen.

Zusammenfassend: Das Team hat nicht versucht, das alte Haus Stein für Stein zu tragen. Sie haben einen Kran gebaut, der die Wände hochgezogen und durch neue ersetzt hat, während im Inneren noch gearbeitet wurde. Am Ende stand ein funktionierendes, modernes Gebäude, das von neuen Architekten (Java-Entwicklern) leicht zu warten ist.