| Nr. | Einordnung | Begründung |
|---|---|---|
| 1 | Refactoring | Verhalten identisch, nur der Name ändert. Mit dem Rename-Werkzeug der IDE risikoarm |
| 2 | Bugfix | Das Verhalten ändert sich absichtlich: Bestellungen über genau 100 bekommen neu Rabatt |
| 3 | Optimierung | Ergebnis bleibt gleich, nur die Laufzeit ändert. Achtung: Reihenfolge und Duplikate ändern sich - falls davon etwas abhängt, ist es doch eine Verhaltensänderung |
| 4 | Refactoring | Dieselbe Response, andere Struktur. Der klassische Fall für D1I |
| 5 | Neues Feature | Die Ausgabe enthält etwas, das vorher nicht da war |
| 6 | Refactoring | Gleiche Liste als Ergebnis, deklarativer geschrieben |
| 7 | Rewrite | Die Implementierung wird ersetzt. Verhalten meist ähnlich, aber nicht garantiert gleich - hier braucht es Characterization Tests vorher |
| 8 | Grenzfall | Für den Aufrufer, der den Rückgabewert nutzt, ändert sich nichts. Für den Aufrufer, der sich auf die mutierte Eingabeliste verlassen hat, ändert sich alles |
Die Umstellung von mutable auf immutable ist genau dann ein reines Refactoring, wenn keine Aufrufstelle die Nebenwirkung genutzt hat. Prüfen lässt sich das nur, indem man alle Aufrufstellen anschaut - oder indem Tests existieren, die die Nebenwirkung abdecken.
# vorher: der Aufrufer sieht die Änderung, ohne den Rückgabewert zu verwenden def preise_erhoehen(produkte, prozent): for p in produkte: p["preis"] = round(p["preis"] * (1 + prozent / 100), 2) return produkte # nachher: wer den Rückgabewert ignoriert, bekommt jetzt gar nichts mehr def preise_erhoehen(produkte, prozent): return [{**p, "preis": round(p["preis"] * (1 + prozent / 100), 2)} for p in produkte]
Der Umbau ist trotzdem richtig - er muss nur als Verhaltensänderung behandelt werden: Aufrufstellen suchen, anpassen, testen, in einem eigenen Commit.
assert auf gleiches Ergebnis plus Messung vorher/nachher