Modul 34 · Migration Deep Dive · Stufe 1 Fundament

Patterns und Refactoring

Switch-basierte Preislogik wird nachvollziehbar in Strategy, Factory und Value Objects überführt. Die Akte zeigt nicht nur das Ziel, sondern die tatsächlichen Dateien, APIs, Dependencies, Codebelege, Tests, Risiken und Cutover-Schritte.

StrategyFactoryValue Object
1 → 4Produktionsdateien
11 → 38Java-Zeilen
1 → 1Testdateien
0 / 0Dependencies entfernt / neu
NIEDRIGRisiko · Score 0

Was sich konkret ändert

DimensionLegacyModernMigrationskonsequenz
Programmiermodellimperativ / ohne Framework-AnnotationenFunctionalInterfaceAnnotationen und Containerfunktionen werden nur dort eingesetzt, wo sie eine konkrete technische Verantwortung übernehmen.
Abhängigkeiten1 direkte Dependencies1 direkte Dependencies0 neu, 0 entfernt; Versionen und transitive Auswirkungen im erfolgreichen Online-Build prüfen.
Öffentliche API1 erkannte Methoden2 erkannte MethodenMethoden werden nach fachlicher Rolle gemappt; reine Bootstrap- und Framework-Methoden sind kein fachlicher Vertrag.
Datenmodellclass LegacyPriceCalculatorclass PriceService, class PricingStrategyFactory, enum CustomerType, interface PricingStrategyFeldnamen, IDs, Null-Semantik, Gleichheit und Serialisierungsform werden separat regressionstestet.
FehlerverhaltenLegacy-Exceptions und Rückgabewerteexplizitere Fach-/Framework-FehlerabbildungFehler dürfen nicht nur technisch übersetzt werden; Status, Ursache, Retrybarkeit und Client-Vertrag müssen erhalten oder versioniert werden.
TestsBestands- und Golden-Master-TestsUnit-, Slice-, Contract- und IntegrationstestsDer Modern-Pfad wird zuerst gegen denselben fachlichen Vektor geprüft und danach um neue technische Risiken ergänzt.
BetriebLegacy-Start/Lifecyclemodernes Packaging, Health und externe KonfigurationGolden Master und Vollständigkeitstests verhindern unbemerkte Branch-Lücken.
RollbackLegacy-Artefakt bleibt unverändertModern-Artefakt getrennt deploybarKein Rollback über Datenverlust: Schema, Nachrichten und verschlüsselte Daten müssen rückwärtslesbar oder durch Dual-Read abgesichert sein.

Fachlicher Vertrag: unverändert zu erhalten

  • Preisresultate bleiben für alle CustomerTypes identisch.
  • Neue Typen werden ohne wachsenden Switch im Service ergänzt.
  • Unsupported Types liefern definierten Fehler.

Hauptrisiko und Testfokus

branch growth and unsupported customer types

all strategies, factory completeness and unknown type tests

Die Modernisierung gilt erst als abgeschlossen, wenn der fachliche Vertrag automatisiert belegt ist.

Verbindliches Code- und Rollenmapping

Die Zuordnung ist semantisch: Eine Legacy-Klasse kann in mehrere moderne Rollen zerlegt werden.

Legacy-Rolle / DateiModern-Rolle / DateiBedeutung
LegacyPriceCalculator.javaPriceService.java + PricingStrategy.java + PricingStrategyFactory.javaSwitch wird Strategy/Factory-Komposition.
String/Branch Customer TypeCustomerType.javaKundentyp wird expliziter Value/Enum-Vertrag.

Legacy-Quellinventar

DateiTypAnnotationenöffentliche APIPatternZeilen
LegacyPriceCalculator.javaclass LegacyPriceCalculatordouble price(String customerType, double base)Conditional Strategy (Legacy-Antipattern) – wählt Preisalgorithmen über Bedingungen.11

Dependency- und Laufzeitmigration

StatusDependencyVersionScopePrüfung
BEIBEHALTENorg.junit.jupiter:junit-jupiterBOM/Parent → BOM/Parenttest → testGemeinsame Dependency; Version und Scope im effektiven POM prüfen.
Direkte POM-Daten ersetzen keinen erfolgreichen Online-Build mit transitiver SBOM- und CVE-Prüfung.

Vorher-/Nachher-Codebelege

Die folgenden Ausschnitte stammen direkt aus den enthaltenen Projekten. Dadurch ist sichtbar, welche Verantwortung tatsächlich verschoben wurde.

Legacy
LegacyPriceCalculator.java
Modern
PriceService.java + PricingStrategy.java + PricingStrategyFactory.java

Migrationsbedeutung: Switch wird Strategy/Factory-Komposition.

Legacy-Code

projects/34-patterns-refactoring/legacy/src/main/java/at/aydin/lab/patterns/legacy/LegacyPriceCalculator.java

package at.aydin.lab.patterns.legacy;

// Design Pattern: Conditional Strategy (Legacy-Antipattern) – wählt Preisalgorithmen über Bedingungen.
public final class LegacyPriceCalculator {
    public double price(String customerType, double base) {
        if ("STANDARD".equals(customerType)) return base;
        if ("PREMIUM".equals(customerType)) return base * 0.9;
        if ("EMPLOYEE".equals(customerType)) return base * 0.7;
        throw new IllegalArgumentException(customerType);
    }
}

Modern-Code

projects/34-patterns-refactoring/modern/src/main/java/at/aydin/lab/patterns/modern/PriceService.java

package at.aydin.lab.patterns.modern;

public final class PriceService {
    private final PricingStrategyFactory factory;
    public PriceService(PricingStrategyFactory factory) {
        this.factory = factory;
    }

    public double price(CustomerType type, double base) {
        return factory.forType(type).apply(base);
    }
}

Modern-Code

projects/34-patterns-refactoring/modern/src/main/java/at/aydin/lab/patterns/modern/PricingStrategy.java

package at.aydin.lab.patterns.modern;

// Design Pattern: Strategy
// Zweck: Rabattalgorithmus ist austauschbar und ohne zentrale Switch-Anweisung erweiterbar.
@FunctionalInterface
public interface PricingStrategy {
    double apply(double basePrice);
}
Legacy
String/Branch Customer Type
Modern
CustomerType.java

Migrationsbedeutung: Kundentyp wird expliziter Value/Enum-Vertrag.

Legacy-Code

projects/34-patterns-refactoring/legacy/src/main/java/at/aydin/lab/patterns/legacy/LegacyPriceCalculator.java

package at.aydin.lab.patterns.legacy;

// Design Pattern: Conditional Strategy (Legacy-Antipattern) – wählt Preisalgorithmen über Bedingungen.
public final class LegacyPriceCalculator {
    public double price(String customerType, double base) {
        if ("STANDARD".equals(customerType)) return base;
        if ("PREMIUM".equals(customerType)) return base * 0.9;
        if ("EMPLOYEE".equals(customerType)) return base * 0.7;
        throw new IllegalArgumentException(customerType);
    }
}

Modern-Code

projects/34-patterns-refactoring/modern/src/main/java/at/aydin/lab/patterns/modern/CustomerType.java

package at.aydin.lab.patterns.modern;

public enum CustomerType {
    STANDARD, PREMIUM, EMPLOYEE
}
Technischen Unified Diff öffnen
--- LegacyPriceCalculator.java
+++ CustomerType.java
@@ -1,11 +1,5 @@
-package at.aydin.lab.patterns.legacy;
+package at.aydin.lab.patterns.modern;
 
-// Design Pattern: Conditional Strategy (Legacy-Antipattern) – wählt Preisalgorithmen über Bedingungen.
-public final class LegacyPriceCalculator {
-    public double price(String customerType, double base) {
-        if ("STANDARD".equals(customerType)) return base;
-        if ("PREMIUM".equals(customerType)) return base * 0.9;
-        if ("EMPLOYEE".equals(customerType)) return base * 0.7;
-        throw new IllegalArgumentException(customerType);
-    }
+public enum CustomerType {
+    STANDARD, PREMIUM, EMPLOYEE
 }

Umsetzungsplan mit Qualitäts-Gates

  1. Arbeitspaket 1
    Switch-Zweige und Testfälle als Entscheidungstabelle erfassen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  2. Arbeitspaket 2
    PricingStrategy als kleinen fachlichen Vertrag definieren. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  3. Arbeitspaket 3
    Je CustomerType eine Strategie implementieren oder als Lambda registrieren. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  4. Arbeitspaket 4
    PricingStrategyFactory mit Vollständigkeitsprüfung einführen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  5. Arbeitspaket 5
    PriceService nur von Factory/Strategie abhängig machen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  6. Arbeitspaket 6
    Legacy Switch nach Golden-Master- und Mutations-/Grenztests entfernen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.

Konkreter Test- und Abnahmekatalog

IDEbenePrüfungerforderlicher Nachweis
34-PATTERNS-REFACTORING-A01Integration/ContractAlle bisherigen Preisfälle sind identisch.Automatisierter Test und CI-Protokoll
34-PATTERNS-REFACTORING-A02Integration/ContractJeder Enum-Wert hat genau eine Strategie.Automatisierter Test und CI-Protokoll
34-PATTERNS-REFACTORING-A03Integration/ContractUnbekannter/null Typ scheitert verständlich.Automatisierter Test und CI-Protokoll
34-PATTERNS-REFACTORING-A04Integration/ContractNeue Strategie erfordert keine Änderung bestehender Strategien.Automatisierter Test und CI-Protokoll
34-PATTERNS-REFACTORING-A05Integration/ContractFactory-Konfiguration ist unit-getestet.Automatisierter Test und CI-Protokoll
34-PATTERNS-REFACTORING-T01UnitFachlogik ohne Container oder externen Dienst testen.Unit-Test
34-PATTERNS-REFACTORING-T02RegressionLegacy- und Modern-Ergebnis für denselben Golden-Master-Vektor vergleichen.Vergleichsreport
34-PATTERNS-REFACTORING-T03NegativeFehlerhafte, leere und grenzwertige Eingaben prüfen.Negativtest
34-PATTERNS-REFACTORING-T04OperationsStart, Health, Shutdown und Konfigurationsfehler prüfen.Deployment-/Startprotokoll
34-PATTERNS-REFACTORING-F01Fokusall strategies, factory completeness and unknown type testsModulspezifischer Testreport

Risikoregister des Moduls

RisikoAuswirkungGegenmaßnahmeGate
branch growth and unsupported customer typesNIEDRIGall strategies, factory completeness and unknown type testsvor Cutover

Konfiguration und Ressourcen

Keine zusätzlichen Ressourcen.

Rollback und Koexistenz

PriceService kann vorübergehend eine LegacyStrategy verwenden; der äußere Servicevertrag bleibt stabil.

Abbruchkriterien

  • Fachlicher Golden-Master weicht ab.
  • Daten-, Nachrichten- oder API-Kompatibilität ist ungeklärt.
  • Fehlerquote, Latenz oder Ressourcenverbrauch überschreiten das vereinbarte Limit.
  • Monitoring oder Rückfallpfad ist nicht funktionsfähig.

Definition of Done

Direkte Arbeitslinks

⌂ Cockpit