Refactoring: Code sicher verbessern

Refactoring: Code sicher verbessern
Refactoring: Code sicher verbessern
Für Quiz, Lückentext, Lernkarten und Fortschritt ist JavaScript nötig. Alle Inhalte und Lösungen bleiben direkt lesbar.

Beim Refactoring ordnest du bestehenden, funktionierenden Code neu, ohne sein beobachtbares Verhalten zu verändern. Der Code soll danach leichter zu verstehen, zu testen, zu warten und zu erweitern sein.

Auf dieser Seite lernst du, Refactoring von Funktionsänderungen abzugrenzen, Code-Smells zu erkennen und eine Umstrukturierung mit kleinen Schritten und Tests abzusichern.

Deine Lernziele

Hake ab, was du schon kannst — und komm am Ende hierher zurück!

Was zählt als Refactoring?
Definition

Refactoring

Refactoring ist die manuelle oder automatisierte Verbesserung der internen Struktur vorhandener Software. Für die Nutzenden bleibt das beobachtbare Verhalten gleich.

Beobachtbares Verhalten umfasst zum Beispiel Ausgaben, Rückgabewerte und Reaktionen auf Eingaben. Wenn du eine neue Funktion ergänzt, ein fachliches Ergebnis änderst oder einen Fehler im sichtbaren Verhalten behebst, ist diese Änderung selbst kein Refactoring.

Typische Refactorings sind:

  • eine Variable oder Methode aussagekräftig umbenennen;
  • eine lange Methode in kleinere Methoden zerlegen;
  • duplizierten Code zusammenführen;
  • zusammengehörige Daten und Operationen in eine passende Klasse verschieben;
  • ungenutzten Code entfernen;
  • Verantwortlichkeiten zwischen Klassen neu verteilen.
Merke

Refactoring verändert, wie der Code aufgebaut ist – nicht, was das Programm nach außen tut.

Teste dich
Frage 1 von 1LeichtWelche Änderung ist ein Refactoring?
Lösung: x wird in gesamtpreis umbenannt, ohne Berechnung oder Ausgabe zu verändern. — Beim Refactoring bleibt das beobachtbare Verhalten erhalten. Eine neue Funktion oder eine sichtbare Fehlerkorrektur ist eine funktionale Änderung.
Woran erkennst du Refactoring-Bedarf?

Ein Code-Smell ist ein auffälliges Merkmal, das auf ein tiefer liegendes Strukturproblem hinweisen kann. Es beweist noch nicht, dass der Code falsch ist.

Definition

Code-Smell

Ein Code-Smell ist ein Warnzeichen für schwer verständlichen, schlecht gegliederten oder unnötig aufwendig änderbaren Code.

Häufige Warnzeichen sind:

  • unklare Namen wie x, data2 oder doIt;
  • lange Methoden mit mehreren Aufgaben;
  • verschachtelte Bedingungen und Schleifen;
  • Copy-and-Paste-Duplikate;
  • lange Parameterlisten;
  • Klassen mit unklaren oder zu vielen Verantwortlichkeiten;
  • ungenutzter Code;
  • veraltete Kommentare, die nicht mehr zum Code passen.

Auch Messwerte wie hohe Verschachtelungstiefe, geringe Testabdeckung oder sehr große Dateien können auf problematische Stellen hinweisen. Sie sind jedoch nur Hinweise: Erst die Analyse des konkreten Codes zeigt, ob und wie du ihn verbessern solltest.

Teste dich
Frage 1 von 1MittelEine Methode prüft eine Bestellung, berechnet den Preis, speichert Daten und versendet eine Nachricht. Welches Problem ist am deutlichsten?
Lösung: Die Methode übernimmt mehrere Verantwortlichkeiten. — Mehrere unabhängige Aufgaben erschweren Verständnis, Tests und Änderungen. Das Extrahieren klar benannter Methoden kann die Verantwortlichkeiten sichtbar trennen.
Wie sieht ein vollständiges Refactoring aus?

Eine Variable mit wechselnder Bedeutung erschwert das Lesen. Im folgenden Beispiel steht x zuerst für den Umfang und danach für die Fläche eines Rechtecks.

Beispiel

Vorher:

  1. double x = 2 * (breite + hoehe);
  2. System.out.println("Umfang: " + x);
  3. x = breite * hoehe;
  4. System.out.println("Fläche: " + x);

Schritt 1: Bedeutungen erkennen. Die Variable speichert zwei verschiedene Größen.

Schritt 2: Sprechende Variablen einführen.

  1. double umfang = 2 * (breite + hoehe);
  2. System.out.println("Umfang: " + umfang);
  3. double flaeche = breite * hoehe;
  4. System.out.println("Fläche: " + flaeche);

Schritt 3: Verhalten vergleichen. Für breite = 4 und hoehe = 3 geben beide Fassungen Umfang: 14 und Fläche: 12 aus.

Das Verhalten bleibt gleich, aber die Namen zeigen nun unmittelbar, welche Bedeutung die Werte haben.

Man könnte die Variablen auch entfernen und beide Ausdrücke direkt ausgeben. Das wäre kürzer, aber nicht unbedingt verständlicher: Die Bedeutungen wären weniger deutlich benannt und die Zwischenwerte im Debugger schlechter zu beobachten. Refactoring bedeutet deshalb nicht automatisch „möglichst wenig Code“.

Bei einer größeren Weiterentwicklung könnten die Berechnungen in Methoden wie umfang() und flaeche() einer Klasse Rechteck verschoben werden. Dann liegt zusammengehörige Rechtecklogik an einem Ort.

Teste dich
Frage 1 von 1MittelWarum ist die zweite Fassung im Beispiel leichter verständlich?
Lösung: Die Namen umfang und flaeche machen die Bedeutung der Werte sichtbar. — Gute Namen verringern die gedankliche Übersetzungsarbeit. Sie verbessern hier die Lesbarkeit, ohne das beobachtbare Verhalten zu verändern.
Wie gehst du sicher vor?

Refactoring kann trotz guter Absicht neue Fehler verursachen. Deshalb arbeitest du in kleinen, überprüfbaren Schritten:

  1. Ausgangszustand prüfen: Stelle sicher, dass der vorhandene Code funktioniert und die Tests erfolgreich sind.
  2. Schutz bewerten: Prüfe, ob Tests gerade den betroffenen Bereich und sein wichtiges Verhalten abdecken.
  3. Ziel festlegen: Benenne das konkrete Strukturproblem, etwa einen unklaren Namen oder duplizierten Code.
  4. Kleine Änderung durchführen: Nimm nur eine überschaubare Umstrukturierung vor.
  5. Tests erneut ausführen: Bei einem Fehlschlag untersuchst du zuerst die letzte Änderung.
  6. Schritte wiederholen: Zerlege ein großes Refactoring in mehrere kleine Transformationen.
  7. Gesamtergebnis prüfen: Führe abschließend die relevanten Tests erneut aus und kontrolliere die Änderung im Zusammenhang.

Automatisierte IDE-Funktionen können beispielsweise Verwendungen eines Symbols finden und sicher umbenennen. Trotzdem musst du Vorbedingungen, Ergebnis und Tests prüfen. Auch automatisierte oder KI-erzeugte Vorschläge sind nicht ungeprüft verlässlich.

Gut zu wissen

Tests vergleichen nur die Fälle, die sie tatsächlich ausführen. Eine erfolgreiche Testsuite senkt deshalb das Regressionsrisiko, beweist aber nicht für alle möglichen Eingaben, dass das Verhalten vollständig erhalten blieb.

Teste dich
Frage 1 von 1SchwerNach einem Refactoring sind alle vorhandenen Tests erfolgreich. Welche Schlussfolgerung ist gerechtfertigt?
Lösung: In den geprüften Fällen wurde keine Verhaltensänderung entdeckt; ein vollständiger Beweis ist das nicht. — Erfolgreiche Tests sind wichtige Kontrollen. Ihre Aussagekraft hängt jedoch davon ab, welche Bereiche, Eingaben und Grenzfälle sie abdecken.
Welche Technik passt zu welchem Problem?
BeobachtungPassendes RefactoringBeabsichtigte Wirkung
Ein Name verrät seine Bedeutung nichtUmbenennenAbsicht sichtbar machen
Eine Methode erledigt mehrere AufgabenMethode extrahierenAufgaben trennen und benennen
Mehrere Stellen enthalten gleiche LogikGemeinsame Logik extrahierenDuplikation verringern
Gemeinsamer Code liegt in mehreren UnterklassenPull-upGemeinsamkeit in einer Oberklasse bündeln
Spezielle Logik liegt in einer allgemeinen OberklassePush-downLogik der passenden Unterklasse zuordnen
Eine sehr kurze Methode verdeckt mehr, als sie erklärtMethode inline setzenunnötige Umleitung entfernen
Code wird nicht mehr verwendetToten Code entfernenAblenkung und Pflegeaufwand verringern

Die Tabelle ist eine Entscheidungshilfe, kein Automatismus. Du musst zuerst verstehen, welche Aufgabe der Code erfüllt und welche Abhängigkeiten betroffen sind.

Vertiefung: Große Änderungen schrittweise umsetzen

Bei einem umfangreichen Refactoring kann Branch by Abstraction helfen. Eine Abstraktionsschicht erlaubt vorübergehend zwei Implementierungen. Teile des Systems werden schrittweise auf die neue Struktur umgestellt, während die übrigen Teile weiter funktionieren.

Refactoring hat außerdem Grenzen. Wenn ein System grundlegende Sicherheits-, Skalierungs- oder Technologieprobleme besitzt, kann eine umfassendere Softwaremodernisierung nötig sein. Gezielte Leistungsoptimierung ist ebenfalls ein anderes Ziel, weil sie beobachtbare Laufzeiteigenschaften verändern soll.

Teste dich
Frage 1 von 1SchwerZwei Klassen enthalten fast dieselbe Preisberechnung. Was ist der sinnvollste erste Gedanke?
Lösung: Prüfen, ob sich die gemeinsame Logik in eine benannte gemeinsame Einheit extrahieren lässt. — Analysiere zuerst Gemeinsamkeiten und Unterschiede. Eine gemeinsame Abstraktion ist nur passend, wenn sie das fachlich gleiche Verhalten ausdrückt.
Karteikasten
Karteikasten

Überlege zuerst selbst und drehe die Karte anschließend zum Prüfen um.

Alles auf einen Blick
Mindmap
  • Refactoring
    • Ziel: verständliche und wartbare Struktur
    • Grenze: beobachtbares Verhalten bleibt gleich
    • Hinweise: Code-Smells und auffällige Metriken
    • Techniken: umbenennen, extrahieren, verschieben, Duplikate entfernen
    • Absicherung: Tests, kleine Schritte und Ergebnisprüfung
    • Risiko: Tests und Werkzeuge geben keine vollständige Garantie
Abschluss-Check
Teste dich
Frage 1 von 3LeichtWelche Aussage beschreibt Refactoring korrekt?
Lösung: Die interne Struktur wird verbessert, während das beobachtbare Verhalten erhalten bleibt. — Entscheidend ist nicht die Länge des Codes, sondern die Strukturverbesserung bei erhaltenem Verhalten.
Frage 2 von 3MittelEine lange Methode enthält drei klar trennbare Aufgaben. Welche Maßnahme passt am besten?
Lösung: Die Aufgaben in aussagekräftig benannte Methoden extrahieren. — Durch das Extrahieren werden die Aufgaben getrennt, einzeln benannt und leichter überprüfbar.
Frage 3 von 3SchwerEin Team möchte duplizierte Logik zusammenführen. Welche Reihenfolge ist am sichersten?
Lösung: Verhalten mit passenden Tests absichern, Gemeinsamkeiten prüfen, eine kleine Extraktion durchführen und erneut testen. — Tests schützen relevantes Verhalten, ersetzen aber nicht die fachliche Analyse. Kleine Transformationen und erneute Prüfungen begrenzen das Risiko.

Refactoring ist gelungen, wenn der Code nachvollziehbarer strukturiert ist, sein beobachtbares Verhalten erhalten blieb und du diese Erhaltung mit passenden Prüfungen begründet beurteilen kannst.

Passend dazu