Extrahieren von Code
Ziel
- Ich verstehe, wie ich Variablen, Methoden und Klassen extrahieren kann.
- Ich verstehe, wie ich meinen Code verändern muss, damit diese Änderung funktioniert.
- Ich verstehe, wann es nützlich ist, diese Refaktorierungen durchzuführen.
Hintergrund
Code schreiben kann am Anfang sehr einfach sein. Etwas Datenstruktur hier, etwas Funktionalität da… und irgendwann hat man ein Produkt, das funktioniert. Die innere Struktur ist zu diesem Zeitpunkt aber oft nicht gut: Stellenweise zu wenig Abstraktion und Modularität, stellenweise gibt es Redundanz oder der Code ist einfach verworren.
Wenn man das nicht aufräumt, wird die künftige Fortentwicklung eines Programms sehr schnell sehr schwierig. Aber was heißt "Aufräumen"? Und wie geht das? Ein wichtiger Ansatz dafür ist die Bildung von Abstraktionen durch Extraktion von Teilen.
Das ist unser Thema hier.
Arbeitsschritte
Diese Aufgabe teilt sich in einen Theorieteil und einen Praxisteil.
Erstellen Sie zunächst ein Markdown-Dokument Extraction-Of-Code.md
und erstellen Sie darin
zwei Überschriften "Theorie" und "Praxis".
Teil 1: Die Theorie
- Erstellen Sie im Abschnitt "Theorie" die drei Überschriften "Extraktion von Variablen", "Extraktion von Methoden" und "Extraktion von Klassen".
- Lesen Sie anschließend die drei Artikel
Extract Variable,
Extract Method und
Extract Class,
und beantworten Sie anschließend zu jedem Artikel jeweils die folgenden Fragen:
- 1 Welches Problem löst diese Refaktorierung?
- 2 Wie wird diese Refaktorierung per Hand durchgeführt?
- 3 Auf welche Fallstricke soll man bei dieser Refaktorierung achten?
- 4 Recherchieren und beschreiben Sie, wie Ihre IDE Ihnen hilft diese Refaktorierung
durchzuführen.
Bietet Ihre IDE Ihnen hierfür eine Funktion an?
Wie löst man diese Funktion aus (per Menü-Klick, per Tastatur)?
Teil 2: Die Praxis
Folgend werden wir einen einfachen Python-Code nehmen und die drei Extraktionen nacheinander darauf anwenden. Es ist sinnvoll die beschriebenen Extraktionen von Hand durchzuführen.
- Erstellen Sie eine Datei
Extraction-Of-Code.py
und kopieren Sie den folgenden Python-Code hinein:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
- Machen Sie einen Commit mit der Datei
Extraction-Of-Code.py
. - 1
git -P show HEAD
- Der Code nimmt einen Monat als Eingabe und gibt zurück, welches Essen in diesem Monat Saison hat. Zwar ist der Code einfach gehalten, allerdings ist er schlecht testbar oder erweiterbar.
- 1 Extrahieren Sie die Ausdrücke
month.lower().endswith("r")
,month.lower().endswith("ary")
und8 > MONTHS.index(month) > 4
in eigene Variablen. Achten Sie darauf den Variablen ausdrucksstarke Namen zu geben! - Machen Sie einen Commit mit der Datei
Extraction-Of-Code.py
. - 2
git -P show HEAD
- Die Logik des Programms ist jetzt schon deutlich einfacher zu verstehen. Allerdings sind Erweiterung und Testbarkeit immer noch eher schwierig.
- 2 Extrahieren Sie die Boolschen Ausdrücke der if-Ausdrücke in eigene Funktionen. Benutzen Sie hierfür die in 1 eingeführten Variablen. Achten Sie darauf ausdrucksstarke Funktionsnamen zu vergeben!
- Machen Sie einen Commit mit der Datei
Extraction-Of-Code.py
. - 3
git -P show HEAD
- Aktuell wird beim Durchlauf des
if-elif-else
-Ausdrucks in jedem Schritt eine Funktion aufgerufen. Aus verschiedensten Gründen kann es aber nützlich sein diese Aufrufe schon vor Beginn des Ausdrucks erledigt zu haben, z. B. weil man das Ergebnis cachen möchte oder sich sehr viel Logik parallelisieren lässt. Es kann nützlich sein an dieser Stelle die Extraktionen von Variablen und Funktionen zu verbinden. - 3 Extrahieren Sie die Funktionsaufrufe im
if
- bzw.elif
-Ausdruck in eigene Variablen. Achten Sie darauf ausdrucksstarke Variablennamen zu vergeben! - Machen Sie einen Commit mit der Datei
Extraction-Of-Code.py
. - 4
git -P show HEAD
- Das Programm sieht jetzt aufgeräumt auf. Es existieren Funktionen, die die beiden Boolschen Werte für die Austern- und Tomatensaison berechnen und diese Ergebnisse sind mittels einer Variable erreichbar. Um eine gute Testbarkeit zu erreichen, wären aber Klassen sehr angenehm. (Für unser Miniprogramm ist der nächste Schritt übertrieben, aber für ein größeres Programm wäre er unter Umständen sinnvoll. Wir machen ihn zu Übungszwecken.)
- 4 Erstellen Sie die zwei Klassen
OystersGood
undTomatoesGood
. Bilden Sie die Funktionen aus 2 in diesen Klassen ab.
Implementieren Sie hierfür die Methode__init__(self, month)
, um die Logik der Funktionen abzubilden und__bool__(self, month)
, um den Rückgabewert der Funktionen abzubilden. Ersetzen Sie danach die Funktionsaufrufe aus 3 durchOystersGood(month)
bzw.TomatoesGood(month)
. - Machen Sie einen Commit mit der Datei
Extraction-Of-Code.py
. - 5
git -P show HEAD
- Das Programm hat nun einen ziemlichen Wandel hingelegt. Mithilfe dieser Klassen ist optimale Testbarkeit gegeben, mehr dazu in Testen.
- 5 Welche der Varianten des Programms gefällt Ihnen am besten? Begründen Sie kurz.
Abgabe
Geben Sie ein Markdown-Dokument ab mit knappen Antworten zu den oben gestellten Fragen
1, 2, … Geben Sie diese Marker mit an.
Geben Sie ggf. Beispiele oder benutzte Quellen an.
Geben Sie ein Kommandoprotokoll ab, das genau nur die Eingaben und Ausgaben der obigen Kommandos 1, 2, … enthält. Entfernen Sie vor Abgabe eventuelle Fehlversuche und sonstige zusätzliche Kommandos aus dem Protokoll.
Geben Sie den Quellcode ab, wie er am Ende der Aufgabe vorliegt.