====== LU07.L10 - Refactoring-Review ======
^ Paar ^ Urteil ^ Was passiert ^
| 1 | **Verhaltensänderung** | ''namen.sort()'' gibt ''None'' zurück und sortiert die übergebene Liste an Ort und Stelle. Der Aufrufer bekommt ''None'' statt einer Liste - und seine Originalliste ist verändert |
| 2 | **Verhaltensänderung** | Der Generator ist nach ''sum'' aufgebraucht. ''max'' bekommt eine leere Folge und wirft ''ValueError'' |
| 3 | **Verhaltensänderung** | Der mutable Standardwert wird einmal beim Definieren erzeugt. Der zweite Aufruf sieht die Werte des ersten |
| 4 | **Echtes Refactoring** | Gleiche Liste, gleiche Reihenfolge, gleiche Objekte |
| 5 | **Kommt darauf an** | Siehe unten |
| 6 | **Echtes Refactoring** mit Nebengewinn | Gleiches Ergebnis. ''any'' hört beim ersten Treffer auf und baut keine Zwischenliste |
===== Die Tests, die es aufgedeckt hätten =====
def test_paar1_original_bleibt():
namen = ["Zoe", "Ali"]
assert sortierte_namen(namen) == ["Ali", "Zoe"]
assert namen == ["Zoe", "Ali"] # scheitert nachher
def test_paar2_zweimal_lesbar():
werte = quadrate(1000)
assert sum(werte) > 0
assert max(werte) > 0 # scheitert nachher mit ValueError
def test_paar3_frischer_start():
assert sammeln(1) == [1]
assert sammeln(2) == [2] # scheitert nachher: [1, 2]
Alle drei Tests haben dieselbe Bauart: Sie prüfen nicht nur den Rückgabewert, sondern auch **was daneben passiert** - der Zustand der Eingabe, die zweite Verwendung, der zweite Aufruf. Genau dort verstecken sich unerwünschte Nebeneffekte.
===== Zu Paar 5 =====
Die Index-Fassung ist ein echtes Refactoring **nur unter zwei Bedingungen**:
- **''kunde_id'' existiert immer.** Die Vorher-Version lässt Bestellungen ohne passenden Kunden still weg, die Nachher-Version wirft ''KeyError''.
- **''id'' ist eindeutig.** Bei doppelten IDs liefert die Vorher-Version mehrere Zeilen pro Bestellung, die Nachher-Version nur eine.
bestellungen = [{"kunde_id": 1, "betrag": 10}, {"kunde_id": 9, "betrag": 20}]
kunden = [{"id": 1, "name": "A"}, {"id": 1, "name": "A2"}]
# vorher -> [('A', 10), ('A2', 10)] Bestellung 9 fällt still weg
# nachher -> KeyError: 9
Beide Fassungen sind vertretbar - aber es sind **verschiedene** Fachregeln. Wer den Umbau macht, muss entscheiden, welche gelten soll, und das dokumentieren:
def zuordnen(bestellungen, kunden):
index = {k["id"]: k for k in kunden}
# bewusst: Bestellungen ohne passenden Kunden werden übersprungen (wie bisher)
return [(index[b["kunde_id"]]["name"], b["betrag"])
for b in bestellungen if b["kunde_id"] in index]
**Das ist der Kern von D1A.** Ein Refactoring wird nicht dadurch richtig, dass die Tests grün sind - sondern dadurch, dass Sie wissen, welche Fälle die Tests //nicht// abdecken. Fehlende Schlüssel, Duplikate, leere Eingaben und mehrfache Verwendung sind die vier Stellen, an denen es fast immer passiert.
----
{{tag>M323-LU07 M323-D1A}}
[[https://creativecommons.org/licenses/by-nc-sa/4.0/ch/|{{https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png}}]] (c) Kevin Maurizi