In unserer vorherigen Lektion haben wir einen neuen Weg zum Verständnis und zur Verbesserung von Code durch Extrahieren bis zum Umfallen gelernt. Dieses Tutorial war zwar ein guter Weg, um die Techniken zu erlernen, aber es war kein ideales Beispiel, um die Vorteile davon zu verstehen. In dieser Lektion extrahieren wir, bis wir alle unseren Trivia-Spiele-bezogenen Code aufgegeben haben, und wir analysieren das Endergebnis.
Diese Lektion wird auch unsere Serie über das Refactoring abschließen. Wenn Sie der Meinung sind, dass wir etwas verpasst haben, können Sie das vorgeschlagene Thema kommentieren. Wenn sich gute Ideen sammeln, werde ich mit zusätzlichen Tutorials fortfahren, die auf Ihren Wünschen basieren.
Gibt es einen besseren Weg, um unseren Artikel zu beginnen, als indem wir unsere längste Methode in kleine Stücke extrahieren. Erst durch das Testen wird dieses Verfahren wie üblich nicht nur effizient, sondern macht auch Spaß.
Wie üblich haben Sie den Code, wie er war, als ich dieses Tutorial in der php_start
Ordner, während das Endergebnis in der php
Mappe.
function wasCorrectlyAnswered () if ($ this-> inPenaltyBox [$ this-> currentPlayer]) if ($ this-> isGettingOutOfPenaltyBox) $ this-> display-> correctAnswer (); $ this-> geld [$ this-> currentPlayer] ++; $ this-> display-> playerCoins ($ this-> players [$ this-> currentPlayer], $ this-> Geldbörsen [$ this-> currentPlayer]); $ winner = $ this-> didPlayerNotWin (); $ this-> currentPlayer ++; if ($ this-> sollteResetCurrentPlayer ()) $ this-> currentPlayer = 0; return $ winner; else $ this-> currentPlayer ++; if ($ this-> sollteResetCurrentPlayer ()) $ this-> currentPlayer = 0; return true; else $ this-> display-> correctAnswerWithTypo (); $ this-> geld [$ this-> currentPlayer] ++; $ this-> display-> playerCoins ($ this-> players [$ this-> currentPlayer], $ this-> Geldbörsen [$ this-> currentPlayer]); $ winner = $ this-> didPlayerNotWin (); $ this-> currentPlayer ++; if ($ this-> sollteResetCurrentPlayer ()) $ this-> currentPlayer = 0; return $ winner;
Diese Methode, wasCorrectlyAnswered ()
, ist unser erstes Opfer.
Wie wir bereits aus früheren Lektionen gelernt haben, besteht der erste Schritt beim Ändern von Legacy-Code darin, ihn unter die Lupe zu nehmen. Dies kann ein schwieriger Prozess sein. Zum Glück für uns die wasCorrectlyAnswered ()
Methode ist ziemlich einfach. Es besteht aus mehreren ansonsten
Aussagen. Jeder Zweig des Codes gibt einen Wert zurück. Wenn wir einen Rückgabewert haben, können wir immer spekulieren, dass Tests machbar sind. Nicht unbedingt einfach, aber zumindest möglich.
Funktion testWasKorrekturAnsweredAndGettingOutOfPenaltyBoxWhileBeingAWinner () $ this-> setAPlayerThatIsInThePenaltyBox (); $ this-> game-> isGettingOutOfPenaltyBox = true; $ this-> game-> geldbörsen [$ this-> game-> currentPlayer] = Spiel :: $ numberOfCoinsToWin; $ this-> assertTrue ($ this-> game-> wasCorrectlyAnswered ());
Es gibt keine eindeutige Regel, welcher Test zuerst geschrieben werden soll. Wir haben hier gerade den ersten Hinrichtungsweg gewählt. Wir hatten tatsächlich eine schöne Überraschung und verwendeten eine der privaten Methoden, die wir zuvor mit vielen Tutorials extrahiert hatten. Aber wir sind noch nicht fertig. Alles grün, also ist es Zeit zum Refactoring.
Funktion testWasKorrekturAnsweredAndGettingOutOfPenaltyBoxWhileBeingAWinner () $ this-> setAPlayerThatIsInThePenaltyBox (); $ this-> currentPlayerWillLeavePenaltyBox (); $ this-> setCurrentPlayerAWinner (); $ this-> assertTrue ($ this-> game-> wasCorrectlyAnswered ());
Dies ist einfacher zu lesen und deutlich beschreibender. Sie finden die extrahierten Methoden im angefügten Code.
FunktionstestWasKorrekturAnsweredAndGettingOutOfPenaltyBoxWährend NICHTBeingAWinner () $ this-> setAPlayerThatIsInThePenaltyBox (); $ this-> currentPlayerWillLeavePenaltyBox (); $ this-> setCurrentPlayerNotAWinner (); $ this-> assertFalse ($ this-> game-> wasCorrectlyAnswered ()); private Funktion setCurrentPlayerNotAWinner () $ this-> game-> geldbörsen [$ this-> game-> currentPlayer] = 0;
Wir haben erwartet, dass dies vorüber ist, aber es schlägt fehl. Die Gründe sind überhaupt nicht klar. Ein genauerer Blick auf didPlayerNotWin ()
kann hilfreich sein.
function didPlayerNotWin () return! ($ this-> folgt [$ this-> currentPlayer] == self :: $ numberOfCoinsToWin);
Die Methode gibt tatsächlich true zurück, wenn ein Spieler nicht gewonnen hat. Vielleicht könnten wir unsere Variable umbenennen, aber erst müssen Tests bestehen.
private Funktion setCurrentPlayerAWinner () $ this-> game-> geldbörsen [$ this-> game-> currentPlayer] = Spiel :: $ numberOfCoinsToWin; private Funktion setCurrentPlayerNotAWinner () $ this-> game-> geldbörsen [$ this-> game-> currentPlayer] = 0;
Bei näherer Betrachtung sehen wir, dass wir hier die Werte gemischt haben. Unsere Verwirrung zwischen dem Methodennamen und dem Variablennamen brachte uns dazu, die Bedingungen umzukehren.
private Funktion setCurrentPlayerAWinner () $ this-> game-> geldbörsen [$ this-> game-> currentPlayer] = 0; private Funktion setCurrentPlayerNotAWinner () $ this-> game-> geldbörsen [$ this-> game-> currentPlayer] = Spiel :: $ numberOfCoinsToWin - 1;
Das funktioniert. Während der Analyse didPlayerNotWin ()
Wir haben auch beobachtet, dass es die Gleichheit verwendet, um den Gewinner zu ermitteln. Wir müssen unseren Wert auf einen niedrigeren Wert setzen, da der Wert im von uns getesteten Produktionscode erhöht wird.
Die restlichen drei Tests sind einfach zu schreiben. Sie sind nur Variationen der ersten beiden. Sie finden sie im beigefügten Code.
Das verwirrendste Problem ist die Irreführung $ Gewinner
Variablennamen. Das sollte sein $ notAWinner
.
$ notAWinner = $ this-> didPlayerNotWin (); $ this-> currentPlayer ++; if ($ this-> sollteResetCurrentPlayer ()) $ this-> currentPlayer = 0; return $ notAWinner;
Wir können das beobachten $ notAWinner
Variable wird nur verwendet, um einen Wert zurückzugeben. Könnten wir das nennen? didPlayerNotWin ()
Methode direkt in der return-Anweisung?
$ this-> currentPlayer ++; if ($ this-> sollteResetCurrentPlayer ()) $ this-> currentPlayer = 0; return $ this-> didPlayerNotWin ();
Dies besteht immer noch unseren Unit-Test, aber wenn wir unsere Golden Master-Tests ausführen, schlagen sie mit einem Fehler "Nicht genügend Speicher" fehl. Tatsächlich macht die Änderung das Spiel nie zu Ende.
Was passiert ist, dass der aktuelle Spieler auf den nächsten Spieler aktualisiert wird. Da wir einen Einzelspieler hatten, verwendeten wir immer denselben Spieler. So ist Testen. Sie wissen nie, wann Sie eine versteckte Logik in schwierigem Code entdecken.
Funktion testWasKorrekturAnsweredAndGettingOutOfPenaltyBoxWhileBeingAWinner () $ this-> setAPlayerThatIsInThePenaltyBox (); $ this-> game-> add ('Another Player'); $ this-> currentPlayerWillLeavePenaltyBox (); $ this-> setCurrentPlayerAWinner (); $ this-> assertTrue ($ this-> game-> wasCorrectlyAnswered ());
Durch Hinzufügen eines weiteren Spielers zu jedem unserer Tests im Zusammenhang mit dieser Methode können wir sicherstellen, dass die Logik abgedeckt ist. Bei diesem Test schlägt die geänderte return-Anweisung fehl.
private Funktion selectNextPlayer () $ this-> currentPlayer ++; if ($ this-> sollteResetCurrentPlayer ()) $ this-> currentPlayer = 0;
Wir können sofort erkennen, dass die Auswahl des nächsten Spielers auf beiden Wegen der Bedingung identisch ist. Wir können es in eine eigene Methode umsetzen. Der Name, den wir für diese Methode gewählt haben, ist selectNextPlayer ()
. Dieser Name hilft dabei, die Tatsache hervorzuheben, dass der Wert des aktuellen Spielers geändert wird. Das deutet auch darauf hin didPlayerNotWin ()
könnte in etwas umbenannt werden, das die Beziehung zum aktuellen Spieler widerspiegelt.
function wasCorrectlyAnswered () if ($ this-> inPenaltyBox [$ this-> currentPlayer]) if ($ this-> isGettingOutOfPenaltyBox) $ this-> display-> correctAnswer (); $ this-> geld [$ this-> currentPlayer] ++; $ this-> display-> playerCoins ($ this-> players [$ this-> currentPlayer], $ this-> Geldbörsen [$ this-> currentPlayer]); $ notAWinner = $ this-> didCurrentPlayerNotWin (); $ this-> selectNextPlayer (); $ notAWinner zurückgeben; else $ this-> selectNextPlayer (); wahr zurückgeben; else $ this-> display-> correctAnswerWithTypo (); $ this-> geld [$ this-> currentPlayer] ++; $ this-> display-> playerCoins ($ this-> players [$ this-> currentPlayer], $ this-> Geldbörsen [$ this-> currentPlayer]); $ notAWinner = $ this-> didCurrentPlayerNotWin (); $ this-> selectNextPlayer (); $ notAWinner zurückgeben;
Unser Code wird kürzer und ausdrucksvoller. Was könnten wir als nächstes tun? Wir könnten den seltsamen Namen der "nicht Gewinner" -Logik ändern und die Methode in eine positive Logik umwandeln, anstatt in eine negative. Oder wir könnten später mit der negativen Logik der Verwirrung fortfahren. Ich glaube nicht, dass es einen bestimmten Weg gibt. Also lasse ich das Problem der negativen Logik als Übung und wir werden mit der Extraktion fortfahren.
function wasCorrectlyAnswered () if ($ this-> inPenaltyBox [$ this-> currentPlayer]) return $ this-> getCorrectlyAnsweredForPlayersInPenaltyBox (); else return $ this-> getCorrectlyAnsweredForPlayersNotInPenaltyBox ();
Versuchen Sie als Faustregel, auf jedem Pfad einer Entscheidungslogik eine einzige Codezeile zu haben.
Wir haben den gesamten Codeblock in jedem Teil unseres Codes extrahiert ob
Aussage. Dies ist ein wichtiger Schritt, über den Sie immer nachdenken sollten. Wenn Sie einen Entscheidungspfad oder eine Schleife in Ihrem Code haben, sollte sich darin nur eine einzige Anweisung befinden. Die Person, die diese Methode liest, ist höchstwahrscheinlich nicht an den Implementierungsdetails interessiert. Er oder sie wird sich um die Entscheidungslogik kümmern ob
Aussage.
function wasCorrectlyAnswered () if ($ this-> inPenaltyBox [$ this-> currentPlayer]) return $ this-> getCorrectlyAnsweredForPlayersInPenaltyBox (); return $ this-> getCorrectlyAnsweredForPlayersNotInPenaltyBox ();
Und wenn wir zusätzlichen Code loswerden können, sollten wir dies tun. Entferne den sonst
und die Logik immer noch gleich geblieben, haben wir ein bisschen Wirtschaft gemacht. Diese Lösung gefällt mir besser, weil sie das "Standardverhalten" der Funktion hervorhebt. Der Code, der sich direkt im Inneren der Funktion befindet (hier die letzte Codezeile). Das ob
Anweisung ist die außergewöhnliche Funktionalität, die der Standardfunktion hinzugefügt wird.
Ich habe Gründe gehört, dass das Schreiben der Bedingungen auf diese Weise die Tatsache verdecken könnte, dass der Standardwert nicht ausgeführt wird, wenn die ob
Anweisung aktiviert. Ich kann dem nur zustimmen, und wenn Sie es vorziehen, das zu behalten sonst
Teil dort für Klarheit, bitte tun Sie es.
private Funktion getCorrectlyAnsweredForPlayersInPenaltyBox () if ($ this-> isGettingOutOfPenaltyBox) return $ this-> getCorrectlyAnsweredForPlayerGettingOutOfPenaltyBox (); else return $ this-> getCorrectlyAnsweredForPlayerStayingInPenaltyBox ();
Wir können weiterhin innerhalb unserer neu erstellten privaten Methoden extrahieren. Die Anwendung des gleichen Prinzips auf unsere nächste Bedingungsanweisung führt zum obigen Code.
private Funktion giveCurrentUserACoin () $ this-> folgt [$ this-> currentPlayer] ++;
Schauen Sie sich unsere privaten Methoden an getCorrectlyAnsweredForPlayersNotInPenaltyBox ()
und getCorrectlyAnsweredForPlayerGettingOutOfPenaltyBox ()
Wir können sofort feststellen, dass eine einfache Zuordnung doppelt vorhanden ist. Diese Aufgabe kann für jemanden wie uns, der bereits weiß, was mit den Geldbörsen und Münzen ist, offensichtlich sein, nicht aber für einen Neuankömmling. Diese einzelne Zeile in eine Methode extrahieren giveCurrentUserACoin ()
ist eine gute Idee.
Es hilft auch bei der Vervielfältigung. Wenn wir in Zukunft die Art und Weise ändern, in der wir den Spielern Münzen geben, müssen wir den Code nur innerhalb dieser privaten Methode ändern.
private Funktion getCorrectlyAnsweredForPlayersNotInPenaltyBox () $ this-> display-> correctAnswerWithTypo (); return $ this-> getCorrectlyAnsweredForAPlayer (); private Funktion getCorrectlyAnsweredForPlayerGettingOutOfPenaltyBox () $ this-> display-> correctAnswer (); return $ this-> getCorrectlyAnsweredForAPlayer (); private Funktion getCorrectlyAnsweredForAPlayer () $ this-> giveCurrentUserACoin (); $ this-> display-> playerCoins ($ this-> players [$ this-> currentPlayer], $ this-> Geldbörsen [$ this-> currentPlayer]); $ notAWinner = $ this-> didCurrentPlayerNotWin (); $ this-> selectNextPlayer (); $ notAWinner zurückgeben;
Dann sind die zwei richtig beantworteten Methoden identisch, außer dass eine etwas etwas mit einem Tippfehler ausgibt. Wir haben den doppelten Code extrahiert und die Unterschiede bei jeder Methode beibehalten. Sie denken vielleicht, wir hätten die extrahierte Methode mit einem Parameter im Aufrufercode verwenden und einmal normal und einmal mit einem Tippfehler ausgeben können. Die oben vorgeschlagene Lösung hat jedoch einen Vorteil: Sie hält die beiden Konzepte "Nicht in Strafbox" und "Herausnehmen von Strafbox" getrennt.
Damit ist die Arbeit abgeschlossen wasCorrectlyAnswered ()
.
function wrongAnswer () $ this-> display-> wrongAnswer (); $ currentPlayer = $ this-> players [$ this-> currentPlayer]; $ this-> display-> playerSentToPenaltyBox ($ currentPlayer); $ this-> inPenaltyBox [$ this-> currentPlayer] = true; $ this-> currentPlayer ++; if ($ this-> sollteResetCurrentPlayer ()) $ this-> currentPlayer = 0; return true;
Bei 11 Zeilen ist diese Methode nicht riesig, aber sicherlich groß. Erinnerst du dich an die magische Zahl sieben plus minus zwei Nachforschungen? Es heißt, dass unser Gehirn gleichzeitig über 7 + -2 Dinge denken kann. Das heißt, wir haben eine begrenzte Kapazität. Um eine Methode leicht und vollständig zu verstehen, möchten wir, dass die Logik innerhalb dieses Bereichs in diesen Bereich passt. Mit insgesamt 11 Zeilen und einem Inhalt von 9 Zeilen ist diese Methode am Limit. Sie können argumentieren, dass es tatsächlich eine leere Zeile und eine andere mit nur einer geschweiften Klammer gibt. Das würde nur 7 Logikzeilen ergeben.
Während Klammern und Räume im Raum kurz sind, haben sie für uns eine Bedeutung. Sie trennen Teile der Logik, sie haben eine Bedeutung, daher muss unser Gehirn sie verarbeiten. Ja, es ist im Vergleich zu einer vollständigen Zeile oder Vergleichslogik einfacher, aber immer noch.
Deshalb ist unser Ziel für Logikzeilen innerhalb einer Methode 4 Zeilen. Dies liegt unter dem Minimum der obigen Theorie, so dass sowohl ein genialer als auch ein mittelmäßiger Programmierer in der Lage sein sollte, die Methode zu verstehen.
$ this-> currentPlayer ++; if ($ this-> sollteResetCurrentPlayer ()) $ this-> currentPlayer = 0;
Wir haben bereits eine Methode für diesen Code, also sollten wir sie verwenden.
function wrongAnswer () $ this-> display-> wrongAnswer (); $ currentPlayer = $ this-> players [$ this-> currentPlayer]; $ this-> display-> playerSentToPenaltyBox ($ currentPlayer); $ this-> inPenaltyBox [$ this-> currentPlayer] = true; $ this-> selectNextPlayer (); wahr zurückgeben;
Besser, aber sollten wir fallen oder weitermachen?
$ currentPlayer = $ this-> players [$ this-> currentPlayer]; $ this-> display-> playerSentToPenaltyBox ($ currentPlayer);
Wir könnten die Variable aus diesen beiden Zeilen einreihen. $ this-> currentPlayer
Es ist offensichtlich, dass der aktuelle Spieler zurückgegeben wird, sodass die Logik nicht wiederholt werden muss. Wir lernen nichts Neues oder abstrahieren nichts Neues, indem wir die lokale Variable verwenden.
function wrongAnswer () $ this-> display-> wrongAnswer (); $ this-> display-> playerSentToPenaltyBox ($ this-> players [$ this-> currentPlayer]); $ this-> inPenaltyBox [$ this-> currentPlayer] = true; $ this-> selectNextPlayer (); wahr zurückgeben;
Wir haben nur 5 Zeilen. Sonst noch was drin?
$ this-> inPenaltyBox [$ this-> currentPlayer] = true;
Wir können die Zeile oben in eine eigene Methode extrahieren. Es wird helfen, zu erklären, was passiert, und die Logik darüber zu isolieren, wie der aktuelle Spieler an seiner eigenen Stelle in die Strafbox geschickt wird.
function wrongAnswer () $ this-> display-> wrongAnswer (); $ this-> display-> playerSentToPenaltyBox ($ this-> players [$ this-> currentPlayer]); $ this-> sendCurrentPlayerToPenaltyBox (); $ this-> selectNextPlayer (); wahr zurückgeben;
Immer noch 5 Zeilen, aber alle Methodenaufrufe. Die ersten beiden zeigen Dinge. Die nächsten beiden beziehen sich auf unsere Logik. Die letzte Zeile gibt nur wahr zurück. Ich sehe keine Möglichkeit, diese Methode verständlicher zu machen, ohne durch die Extraktionen, die wir vornehmen könnten, Komplexität einzuführen, z. B. durch Extrahieren der beiden Anzeigemethoden in eine private. Wenn wir das tun würden, wohin sollte diese Methode gehen? Das sehr gut finden Spiel
Klasse oder in Anzeige
? Ich denke, dass dies bereits eine zu komplexe Frage ist, die es verdient, in Bezug auf die Einfachheit unserer Methode in Betracht gezogen zu werden.
Lassen Sie uns ein paar Statistiken erstellen, indem Sie dieses großartige Tool vom Verfasser von PHPUnit https://github.com/sebastianbergmann/phploc.git ausprobieren
./ phploc… / Refactoring \ Legacy \ Code \ - \ Part \ 1 \: \ The \ Golden \ Master / Source / Trivia / php / phploc 2.1-gca70e70 von Sebastian Bergmann. Code-Codezeilen (LOC) 232 Kommentarcodezeilen (CLOC) 0 (0,00%) Nichtkommentare Codezeilen (NCLOC) 232 (100,00%) Logische Codezeilen (LLOC) 99 (42,67%) Klassen 88 (88,89) %) Durchschnittliche Klassenlänge 88 minimale Klassenlänge 88 maximale Klassenlänge 88 durchschnittliche Methodenlänge 7 minimale Methodenlänge 1 maximale Methodenlänge 17 Funktionen 1 (1,01%) durchschnittliche Funktionslänge 1 Nicht in Klassen oder Funktionen 10 (10,10%) Cyclomatic Complexity Durchschnittliche Komplexität pro LLOC 0,26 Durchschnittliche Komplexität pro Klasse 25,00 Minimale Klasse Komplexität 25,00 Maximale Klasse Komplexität 25,00 Durchschnittliche Komplexität pro Methode 3.18 Minimale Methodenkomplexität 1.00 Maximale Methodenkomplexität 10.00 Abhängigkeiten Globale Zugriffe 0 Globale Konstanten 0 (0,00%) Globale Variablen 0 (0,00%) Super-Global Variablen 0 (0,00%) Attributzugriffe 115 Nicht statisch 115 (100.00%) statisch 0 (0,00%) Methodenaufrufe 21 nicht statisch 21 (100.00%) statisch 0 (0,00%) Struktur Namespaces 0 Schnittstellen 0 Eigenschaften 0 Klassen 1 Zusammenfassung Klassen 0 (0,00%) Beton Klassen 1 ( 100.00%) Methoden 11 Geltungsbereich Nichtstatische Methoden 11 (100.00%) Statische Methoden 0 (0.00%) Sichtbarkeit Öffentliche Methoden 11 (100.00%) Nicht öffentliche Methoden 0 (0.00%) Funktionen 1 Benannte Funktionen 1 (100.00%) Anonyme Funktionen 0 (0,00%) Konstanten 0 Globale Konstanten 0 (0,00%) Klassenkonstanten 0 (0,00%)
./ phploc… / Refactoring \ Legacy \ Code \ - \ Part \ 11 \: \ The \ End \? / Source / trivia / php phploc 2.1-gca70e70 von Sebastian Bergmann. Codezeilen (LOC) 371 Kommentarcodezeilen (CLOC) 0 (0,00%) Codezeilen ohne Kommentar (NCLOC) 371 (100,00%) Logische Codezeilen (LLOC) 151 (40,70%) Klassen 145 (96.03 %) Durchschnittliche Klassenlänge 36 minimale Klassenlänge 8 maximale Klassenlänge 89 durchschnittliche Methodenlänge 2 minimale Methodenlänge 1 maximale Methodenlänge 14 Funktionen 0 (0,00%) durchschnittliche Funktionslänge 0 Nicht in Klassen oder Funktionen 6 (3,97%) Cyclomatic Complexity Durchschnittliche Komplexität pro LLOC 0,15 Durchschnittliche Komplexität pro Klasse 6,50 Minimale Klassenkomplexität 1,00 Maximale Klassenkomplexität 17,00 Durchschnittliche Komplexität pro Methode 1,46 Minimale Methodenkomplexität 1,00 Maximale Methodenkomplexität 10,00 Abhängigkeiten Globale Zugriffe 0 Globale Konstanten 0 (0,00%) Globale Variablen 0 (0,00%) Super-Global Variablen 0 (0,00%) Attributzugriffe 96 nicht statisch 94 (97,92%) statisch 2 (2,08%) Methodenaufrufe 74 nicht statisch 74 (100.00%) statisch 0 (0,00%) Struktur Namespaces 0 Schnittstellen 1 Eigenschaften 0 Klassen 3 Zusammenfassung Klassen 0 (0,00%), Betonklassen 3 (100,00) %) Methoden 59 Geltungsbereich Nichtstatische Methoden 59 (100.00%) Statische Methoden 0 (0,00%) Sichtbarkeit Öffentliche Methoden 35 (59.32%) Nicht öffentliche Methoden 24 (40.68%) Funktionen 0 Benannte Funktionen 0 (0,00%) Anonyme Funktionen 0 (0,00%) Konstanten 3 Globale Konstanten 0 (0,00%) Klassenkonstanten 3 (100,00%)
Brute-Daten sind so gut, wie wir sie verstehen und analysieren können.
Die Anzahl der logischen Codezeilen ist von 99 auf 151 deutlich gestiegen. Diese Zahl sollte Sie jedoch nicht dazu verleiten, anzunehmen, dass unser Code komplexer wurde. Dies ist eine natürliche Tendenz von gut überarbeitetem Code, da die Anzahl der Methoden und Aufrufe an sie zunimmt.
Sobald wir die durchschnittliche Klassenlänge betrachten, können wir einen drastischen Rückgang der Codezeilen von 88 auf 36 feststellen.
Es ist einfach erstaunlich, wie lange die Methodenlänge von durchschnittlich sieben Zeilen auf nur zwei Codezeilen gesunken ist.
Während die Anzahl der Zeilen ein guter Indikator für das Codevolumen pro Maßeinheit ist, liegt der tatsächliche Gewinn in den Analysen der zyklomatischen Komplexität. Jedes Mal, wenn wir eine Entscheidung in unserem Code treffen, erhöhen wir die zyklomatische Komplexität. Wenn wir ketten ob
Aussagen ineinander, steigt die zyklomatische Komplexität dieser Methode exponentiell an. Unsere fortgesetzten Extraktionen führten zu Methoden mit nur einer einzigen Entscheidung, wodurch die durchschnittliche Komplexität pro Methode von 3,18 auf 1,00 reduziert wurde. Sie können dies lesen, da "unsere überarbeiteten Methoden 3,18-mal einfacher sind als der ursprüngliche Code". Auf Klassenebene ist der Rückgang der Komplexität noch erstaunlicher. Es ging von 25.00 bis 6.50 Uhr zurück.
Gut. Das ist es. Ende der Serie. Fühlen Sie sich frei, Ihre Meinung zu äußern, und wenn Sie der Meinung sind, dass wir ein Refactoring-Thema verpasst haben, fragen Sie nach den Kommentaren unten. Wenn sie interessant sind, werde ich sie in zusätzliche Teile dieser Serie umwandeln.
Vielen Dank für Ihre ungeteilte Aufmerksamkeit.