Refactoring von Legacy-Code in JavaScript: Fortgeschrittenes Niveau

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Refactoring von Legacy-Code in JavaScript: Fortgeschrittenes Niveau



Die Arbeit mit Legacy-Code ist für jeden Entwickler, insbesondere im Bereich Node.js, eine unvermeidliche Realität. Oft gleicht solcher Code einem „Sumpf“ aus globalen Variablen, verschachtelten Callbacks, Funktionen mit Hunderten von Zeilen und dem völligen Fehlen einer modularen Struktur. Einfache Refactoring-Methoden funktionieren hier nicht: Es bedarf eines systematischen Ansatzes und der Kenntnis fortgeschrittener Techniken. In diesem Artikel analysieren wir Strategien, die helfen, Chaos in eine wartbare Architektur zu verwandeln, ohne die Produktion zu stoppen.



1. Analyse und Kartierung von Abhängigkeiten



Bevor man Code ändert, muss man ihn verstehen. In Legacy-Projekten fehlt oft die Dokumentation oder ist veraltet. Der erste Schritt ist die Erstellung einer Abhängigkeitskarte.



Werkzeuge:

  • Madge – ein Dienstprogramm zur Visualisierung von Abhängigkeiten zwischen Modulen. Es zeigt zyklische Abhängigkeiten und „tote“ Dateien an.
  • ESLint mit Plugins – hilft, ungenutzte Variablen, Funktionen und Importe zu identifizieren.
  • Deployment in eine isolierte Umgebung – führen Sie Tests aus (falls keine vorhanden sind, schreiben Sie zumindest Smoke-Tests) und protokollieren Sie, welche Module geladen werden.


Beispiel: Angenommen, wir haben eine Datei legacy.js, die 2000 Zeilen enthält und eine globale Variable config verwendet.



// legacy.js (vor dem Refactoring)var config = {    apiUrl: 'https://api.example.com',    timeout: 5000};

function fetchData(callback) { // 50 Zeilen Logik mit verschachtelten if und try/catch // verwendet die globale Variable config if (config.timeout > 0) { // ... } callback(null, data);}


Aktion: Mit Madge sehen wir, dass legacy.js in 15 anderen Dateien importiert wird. Es ist ein „göttliches Objekt“. Unsere Aufgabe ist es, es in atomare Module aufzuteilen.



2. Die „Strangler Fig“-Strategie (Feigenwürger)



Dieses Muster ist ideal für das Refactoring ohne Systemstillstand. Der Kern: Wir schreiben nicht alles auf einmal um, sondern ersetzen schrittweise Teile des alten Systems durch neue, bis das alte von selbst abstirbt.



Implementierung in Node.js:

  • Erstellen eines neuen Moduls mit sauberer Architektur.
  • Schreiben einer Proxy-Schicht (oder Fassade), die Aufrufe an das alte oder neue Modul weiterleitet.
  • Schrittweises Umschalten der Verbraucher auf das neue Modul.


Beispiel: Ersetzen des alten Callback-Stils durch Promise/async/await.



// Alte API (callback-basiert)function getUser(id, callback) {    // Legacy-Code    callback(null, { id: id, name: 'John' });}

// Neue API (Promise-basiert)async function getUserAsync(id) { // neue Implementierung mit async/await const user = await database.findUser(id); return user;}

// Proxy-Fassadeasync function getUserFacade(id) { if (USE_NEW_IMPLEMENTATION) { return getUserAsync(id); } else { return new Promise((resolve, reject) => { getUser(id, (err, user) => { if (err) reject(err); else resolve(user); }); }); }}


Das Flag USE_NEW_IMPLEMENTATION kann in die Konfiguration oder ein Feature Toggle ausgelagert werden. Dies ermöglicht es, den neuen Code für einen Teil der Benutzer zu aktivieren (Canary Release) oder Änderungen ohne Deployment zurückzusetzen.



3. Modularisierung und Isolierung von Seiteneffekten



Legacy-Code leidet oft unter versteckten Seiteneffekten: Eine Funktion ändert den globalen Zustand, schreibt in eine Datei oder ruft eine externe API auf, ohne ein Ergebnis zurückzugeben. Das Refactoring solcher Funktionen besteht darin, die reine Logik zu extrahieren.



Technik: „Funktion extrahieren“ (Extract Function) mit anschließender Abhängigkeitsinjektion (Dependency Injection).



Problematischer Code:



                

Blogs

Buchempfehlungen