Zurück zur Startseite

Koexistenz von Legacy-Code in High-Load-Systemen

Der Artikel untersucht die Risiken des Entfernens von Legacy-Code in großen Projekten und Koexistenzstrategien durch Feature Toggles und Fassaden. Beispiele zu Spring Boot, Traffic-Migrationsschemata und Fälle zwingender Löschung werden bereitgestellt. Der Ansatz minimiert Regressionen und erhält die Verfügbarkeit.

Legacy nicht löschen: Feature Toggles für Stabilität
Advertisement 728x90

Stabilität statt Löschung: Strategien für die Koexistenz von Legacy-Code in großen Projekten

In langlaufenden, hochbelasteten Systemen birgt das Löschen von Legacy-Code das Risiko von Regressionen und Instabilitäten. Statt umfassender Refaktorisierung ist es klüger, alten und neuen Code mithilfe von Feature-Toggles und Fassaden nebeneinander laufen zu lassen. Dieser Ansatz ermöglicht kontinuierliche Entwicklung ohne Ausfallzeiten und hält bewährte Komponenten als Sicherheitsnetz.

Risiken aggressiver Code-Entfernung

Sogar das Löschen toten Codes kann zu Fehlern führen – durch versteckte Abhängigkeiten wie Reflection, dynamisches Laden oder RPC-Aufrufe. Tests in Legacy-Systemen decken selten Randfälle ab, und Produktivdaten aktivieren oft seltene Ausführungspfade. Der Verlust institutionellen Wissens verschärft das Problem: Verabschiedete Teams hinterlassen kritischen Code für Nischen-Szenarien wie Migrationen oder Compliance.

In Unternehmensumgebungen werden vendor-spezifische Custom-Module besonders anfällig – Änderungen können die Vendor-Unterstützung gefährden.

Google AdInline article slot

Das Prinzip "Lass gut sein" in der Praxis

Ein klassisches Beispiel ist der Deep Space 1-Probe von NASA: Code aus den 1970er-Jahren blieb unberührt und wurde durch Adapter umschlossen. Stabile Komponenten bleiben unverändert, wenn sie zuverlässig funktionieren. Diese reife Strategie eignet sich für Systeme, die älter als fünf Jahre sind.

Architektur der Koexistenz: Der Strangler Fig im Umkehrschluss

Zerstören Sie nicht den Legacy-Code – bauen Sie das neue System parallel auf und leiten Schritt für Schritt den Datenverkehr um. Zwei Strategien:

| Strategie | Maßnahmen | Einsatzzeitpunkt |

Google AdInline article slot

|----------|---------|----------------|

| Entfernung | Neuentwicklung auf neuem Stack | Einfache Logik, 100 % Testabdeckung, keine Abhängigkeiten |

| Koexistenz | Neuer Code läuft neben dem Alten, schrittweise Umleitung | Kritische Funktionalität, schwache Tests, hohe Risiken |

Google AdInline article slot

Feature-Toggles gewährleisten Sicherheit:

  • Entwickeln Sie die neue Implementierung.
  • Umschließen Sie sie mit einem Flag-Check.
  • Führen Sie sie auf 1 % des Datenverkehrs aus.
  • Skalieren Sie hoch, falls erfolgreich.
  • Rollback per Flag bei Problemen.

Legacy-Code bleibt mindestens 2–3 Jahre im Repository für Zuverlässigkeitsanalysen.

Umsetzung in Spring Boot

Umgeben Sie Legacy-Code mit einer Schnittstelle, ohne den Originalcode zu verändern.

// Legacy-Service (unverändert)
@Service
public class LegacyDiscountService {
    public double calculateDiscount(Order order) {
        // Logik aus dem Jahr 2019
        return order.getTotal() * 0.1;
    }
}

// Neuer Service
@Service
public class NewDiscountService {
    public double calculateDiscount(Order order) {
        return applyComplexRules(order);
    }
}

Fassade mit Toggle:

@Component
public class DiscountServiceFacade {
    private final LegacyDiscountService legacyService;
    private final NewDiscountService newService;
    
    @Value("${feature.discount.new.enabled:false}")
    private boolean useNewService;
    
    public DiscountServiceFacade(LegacyDiscountService legacyService, 
                                 NewDiscountService newService) {
        this.legacyService = legacyService;
        this.newService = newService;
    }
    
    public double calculateDiscount(Order order) {
        if (useNewService) {
            return newService.calculateDiscount(order);
        }
        return legacyService.calculateDiscount(order);
    }
}

Isolation via Profiles:

@Configuration
public class DiscountConfiguration {
    
    @Bean
    @ConditionalOnProperty(name = "feature.discount.new", havingValue = "false", matchIfMissing = true)
    public DiscountService legacyDiscountService() {
        return new LegacyDiscountService();
    }
    
    @Bean
    @ConditionalOnProperty(name = "feature.discount.new", havingValue = "true")
    public DiscountService newDiscountService() {
        return new NewDiscountService();
    }
}

Tests ignorieren Legacy:

@Test
@DisabledIf("!${feature.discount.new.enabled}")
void testNewDiscountLogic() {
    // Nur neue Logik
}

Workflow zum Datenverkehrsumschalten

API-Gateway leitet basierend auf Flags weiter: Monolith als Fallback, Microservice skaliert schrittweise. Der Feature-Toggle-Service verwaltet Echtzeit-Prozentsätze. Legacy bleibt mindestens 2–3 Jahre in Produktion.

Wenn eine Entfernung unvermeidbar ist

  • Sicherheit: CVEs in veralteten Bibliotheken.
  • Compliance: GDPR-Verstöße.
  • EOL-Technologie: Java-Versionen ohne Patches.
  • Keine Expertise: Keine Spezialisten verfügbar.

Auch dann: Graduelle Bereitstellung mit Rollback-Möglichkeit nutzen.

Schlüssel-Erkenntnisse

  • Systemstabilität hat Vorrang vor Code-Ästhetik: Uptime zählt mehr als gelöschte Legacy-Zeilen.
  • Versteckte Abhängigkeiten erfordern die Überwachung tatsächlicher Produktivaufrufe vor der Löschung.
  • Feature-Toggles reduzieren Migrierungsrisiken.
  • Technische Schulden zahlen sich aus, wenn Wartungskosten geringer sind als Refaktorisierung.
  • Institutionelles Wissen im Code: Löschen nur mit 100 %iger Sicherheit.

— Editorial Team

Advertisement 728x90

Weiterlesen