Refactoring
Refactoring ist der systematische Prozess der Umstrukturierung von bestehendem Quellcode ohne Änderung seines externen Verhaltens, um Lesbarkeit, Wartbarkeit und Erweiterbarkeit zu verbessern.
Auf dieser Seite
Refactoring bezeichnet den systematischen Prozess der Umstrukturierung von bestehendem Quellcode, ohne dessen externes Verhalten zu verändern. Das Ziel ist die Verbesserung der internen Codequalität: bessere Lesbarkeit, einfachere Wartbarkeit und höhere Erweiterbarkeit. Der Begriff wurde maßgeblich durch Martin Fowlers gleichnamiges Buch von 1999 geprägt.
Refactoring ist wie das Aufräumen und Umorganisieren einer Werkstatt: Die Werkzeuge und Materialien bleiben dieselben, aber durch bessere Anordnung kann man effizienter arbeiten. In der Softwareentwicklung bedeutet das: Der Code macht weiterhin dasselbe, aber Entwickler können ihn leichter verstehen, warten und erweitern.
Warum ist Refactoring wichtig?
Software entwickelt sich ständig weiter. Mit jeder neuen Funktion, jedem Bugfix und jeder Änderung wächst die Codebasis. Ohne regelmäßiges Refactoring sammelt sich sogenannte technische Schuld an, der Code wird immer schwerer verständlich und wartbar. Refactoring ist die Lösung, um diese Schuld systematisch abzubauen.
Die wichtigsten Vorteile von Refactoring:
- Bessere Lesbarkeit: Klare Strukturen und aussagekräftige Namen machen den Code verständlicher
- Einfachere Wartung: Gut strukturierter Code lässt sich schneller ändern und debuggen
- Weniger Fehler: Reduzierte Komplexität führt zu weniger Bugs
- Höhere Entwicklungsgeschwindigkeit: Langfristig arbeitet das Team schneller mit sauberem Code
- Bessere Testbarkeit: Kleine, fokussierte Methoden sind leichter zu testen
Die wichtigsten Refactoring-Techniken
Martin Fowler hat in seinem Standardwerk einen Katalog von Refactoring-Techniken zusammengestellt. Diese Techniken sind kleine, bewährte Transformationen, die einzeln oder kombiniert angewendet werden können.
Extract Method
Extract Method ist eine der häufigsten Refactoring-Techniken. Sie wird angewendet, wenn eine Methode zu lang ist oder einen Codeblock enthält, der einen eigenständigen Zweck erfüllt. Der Block wird in eine neue Methode mit aussagekräftigem Namen ausgelagert.
// Vorher: Lange Methode mit gemischten Verantwortlichkeiten
public void processOrder(Order order) {
// Validierung
if (order.getItems().isEmpty()) {
throw new IllegalArgumentException("Bestellung ist leer");
}
if (order.getCustomer() == null) {
throw new IllegalArgumentException("Kein Kunde angegeben");
}
// Preisberechnung
double total = 0;
for (Item item : order.getItems()) {
total += item.getPrice() * item.getQuantity();
}
order.setTotal(total);
// Speichern
orderRepository.save(order);
}
// Nachher: Klare Struktur durch Extract Method
public void processOrder(Order order) {
validateOrder(order);
calculateTotal(order);
orderRepository.save(order);
}
private void validateOrder(Order order) {
if (order.getItems().isEmpty()) {
throw new IllegalArgumentException("Bestellung ist leer");
}
if (order.getCustomer() == null) {
throw new IllegalArgumentException("Kein Kunde angegeben");
}
}
private void calculateTotal(Order order) {
double total = 0;
for (Item item : order.getItems()) {
total += item.getPrice() * item.getQuantity();
}
order.setTotal(total);
}
Rename
Gute Namen sind entscheidend für verständlichen Code. Die Rename-Technik ändert Bezeichner (Variablen, Methoden, Klassen) in aussagekräftigere Namen. Moderne IDEs unterstützen sicheres Umbenennen im gesamten Projekt.
// Vorher: Unklare Bezeichner
function calc(a, b, c) {
return a * b * (1 - c);
}
// Nachher: Selbsterklärender Code
function calculateDiscountedPrice(price, quantity, discountRate) {
return price * quantity * (1 - discountRate);
}
Move Method / Move Field
Manchmal befindet sich eine Methode oder ein Feld in der falschen Klasse. Die Move-Technik verschiebt sie dorthin, wo sie konzeptuell hingehört. Ein typisches Anzeichen: Eine Methode verwendet mehr Daten einer anderen Klasse als der eigenen.
Weitere wichtige Techniken
| Technik | Beschreibung | Anwendungsfall |
|---|---|---|
| Inline Method | Ersetzt Methodenaufruf durch den Methodeninhalt | Wenn die Methode trivial ist und der Name nichts hinzufügt |
| Extract Class | Teilt eine große Klasse in mehrere kleinere | Klasse hat zu viele Verantwortlichkeiten |
| Replace Temp with Query | Ersetzt temporäre Variable durch Methodenaufruf | Berechnung soll wiederverwendbar sein |
| Introduce Parameter Object | Fasst mehrere Parameter zu einem Objekt zusammen | Methode hat zu viele Parameter |
| Encapsulate Field | Macht Feld privat und fügt Getter/Setter hinzu | Direkter Feldzugriff von außen |
Code Smells erkennen
Code Smells sind Hinweise darauf, dass Refactoring nötig sein könnte. Sie sind keine Fehler im eigentlichen Sinne, der Code funktioniert ja, aber sie deuten auf tieferliegende Designprobleme hin. Das Erkennen von Code Smells ist der erste Schritt zum gezielten Refactoring.
Häufige Code Smells:
- Long Method: Methoden mit mehr als 20-30 Zeilen sind oft zu lang
- Large Class: Klassen mit zu vielen Verantwortlichkeiten
- Duplicate Code: Derselbe oder ähnlicher Code an mehreren Stellen
- Feature Envy: Eine Methode nutzt mehr Daten einer anderen Klasse als der eigenen
- Primitive Obsession: Verwendung primitiver Typen statt kleiner Objekte (z.B. String für E-Mail-Adressen)
- Data Clumps: Datengruppen, die immer zusammen auftreten
- Comments: Übermäßige Kommentare können auf unklaren Code hindeuten
Refactoring vs. Rewriting
Refactoring wird oft mit Rewriting (Neuschreiben) verwechselt. Der entscheidende Unterschied: Beim Refactoring bleibt der existierende Code erhalten und wird schrittweise verbessert. Beim Rewriting wird der Code komplett neu geschrieben.
| Aspekt | Refactoring | Rewriting |
|---|---|---|
| Vorgehen | Kleine, inkrementelle Schritte | Kompletter Neubeginn |
| Risiko | Gering (schrittweise Validierung) | Hoch (Big-Bang-Ansatz) |
| Zeitaufwand | Kontinuierlich, verteilt | Großes Vorab-Investment |
| Funktionalität | Bleibt während des Prozesses erhalten | Erst am Ende wieder verfügbar |
| Anwendungsfall | Normale Codequalitätsprobleme | Fundamentale Architekturprobleme |
Die Faustregel: Refactoring ist fast immer die bessere Wahl. Rewriting sollte nur bei fundamentalen Architekturproblemen in Betracht gezogen werden, etwa wenn die verwendete Technologie veraltet ist oder die Grundstruktur nicht mehr zu den Anforderungen passt.
Best Practices für erfolgreiches Refactoring
Damit Refactoring sicher und effektiv ist, solltest du einige bewährte Praktiken beachten:
1. Tests sind Pflicht
Vor dem Refactoring muss eine ausreichende Testabdeckung vorhanden sein. Tests stellen sicher, dass das Verhalten des Codes nach dem Refactoring unverändert bleibt. Der Red-Green-Refactor-Zyklus aus dem Test-Driven Development (TDD) integriert Refactoring direkt in den Entwicklungsprozess.
2. Kleine Schritte machen
Refactoring sollte in kleinen, atomaren Schritten erfolgen. Nach jeder Änderung werden die Tests ausgeführt. So lassen sich Fehler sofort lokalisieren. Eine gute Faustregel: Zwischen zwei Testläufen sollten maximal fünf Minuten Arbeit liegen.
3. Versionskontrolle nutzen
Nutze Git oder ein anderes Versionskontrollsystem. Erstelle separate Branches für größere Refactorings und committe häufig. So kannst du jederzeit zu einem funktionierenden Zustand zurückkehren.
4. Das Boy-Scout-Prinzip
“Hinterlasse den Code besser, als du ihn vorgefunden hast.” Statt große Refactoring-Projekte zu planen, verbessere den Code kontinuierlich bei jeder Änderung. Wenn du einen Bugfix machst oder ein Feature hinzufügst, räume nebenbei ein wenig auf.
Tool-Unterstützung
Moderne Entwicklungsumgebungen bieten umfangreiche Unterstützung für automatisiertes Refactoring. Diese Tools führen die Transformationen sicher durch und aktualisieren alle betroffenen Stellen im Projekt.
IDE-Integration:
- IntelliJ IDEA: Umfangreiche Refactoring-Funktionen für Java, Kotlin und andere Sprachen
- Visual Studio: Refactoring-Support für C#, .NET und weitere
- Visual Studio Code: Erweiterungen für verschiedene Sprachen
- Eclipse: Klassische Java-IDE mit soliden Refactoring-Tools
Analyse-Tools:
- SonarQube: Erkennt Code Smells und schlägt Verbesserungen vor
- ESLint / TSLint: Regelbasierte Analyse für JavaScript/TypeScript
- PMD / Checkstyle: Statische Analyse für Java
Refactoring in der Ausbildung
Für angehende Fachinformatiker für Anwendungsentwicklung ist Refactoring eine zentrale Kompetenz. In der Praxis verbringst du oft mehr Zeit mit dem Lesen und Ändern von bestehendem Code als mit dem Schreiben von neuem Code. Refactoring-Fähigkeiten helfen dir dabei:
- Legacy-Code zu verstehen und zu verbessern
- Wartbare Software zu entwickeln, die auch nach Jahren noch erweiterbar ist
- Im Team effektiv zusammenzuarbeiten durch lesbaren Code
- Technische Schulden zu erkennen und abzubauen
- Professionelle Entwicklungspraktiken anzuwenden
Übe Refactoring regelmäßig, zum Beispiel mit Coding Katas wie FizzBuzz, wo du zunächst eine funktionierende Lösung schreibst und diese dann schrittweise verbesserst. So entwickelst du ein Gespür dafür, wann und wie Code verbessert werden kann.
Quellen und weiterführende Links
- Martin Fowler: Refactoring (2. Auflage) - Das Standardwerk zum Thema
- Refactoring.Guru - Interaktiver Katalog aller Refactoring-Techniken mit Beispielen
- Wikipedia: Refactoring - Grundlegende Übersicht
- Working Effectively with Legacy Code - Michael Feathers’ Buch zum Umgang mit Altcode
Prüfungsbezug
Passt zu deiner Prüfungsvorbereitung
Wenn dir dieser Begriff in Aufgaben, Projektdokumentation oder Fachgespräch begegnet, ordne ihn direkt in den Prüfungsstoff ein.