In meinem aktuellen Job wurde ich einige Male damit beauftragt, alten Code zu bereinigen. Oft ist der Code ein Labyrinth und die Daten dahinter sind noch verworrener. Ich finde mich dabei, Dinge in nette, saubere, modulare Methoden zu zerlegen. Jede Methode macht eine Sache und macht es gut. Dann geht es in den Süden ...
Ausnahmslos habe ich eine saubere API und keine wirkliche Möglichkeit, alles zusammenzubinden. Die Lösung bestand darin, eine große hässliche "Kleber" -Methode (im Allgemeinen voll von bedingten Anweisungen) zu schreiben, die schließlich alle meine "sauberen" Methoden aufruft.
Die Klebemethode ist in der Regel eine knappe Version des Code- / Datengewirrs, das ich bereinigen wollte. Es ist in der Regel besser lesbar, aber es ist immer noch ärgerlich.
Wie kann ich solche Methoden vermeiden? Ist dies ein Symptom für die verwickelten Daten oder ein Spiegelbild von etwas, das ich falsch mache?
Antworten:
Ich werde Ihnen unsere Erfahrung beim Refactoring von LedgerSMB geben. Wir haben uns schon früh dafür entschieden, die Dinge anders zu machen und tun immer noch genau das, was Sie beschreiben, aber ohne viele Klebemethoden (wir haben übrigens ein paar Klebemethoden, nur nicht viele).
Leben mit zwei Codebasen
LedgerSMB hat ungefähr 5 Jahre mit zwei Codebasen überlebt, und es wird noch einige Jahre dauern, bis die alte Codebasis beseitigt ist. Die alte Codebasis ist ein wahrer Horror. Bei schlechtem db-Design konstruiert Perl wie
IS->some_func(\%$some_object);
Code, der genau zeigt, warum die Spaghetti-Metapher manchmal verwendet wird (Ausführungspfade, die sich zwischen Modulen und zurück und zwischen Sprachen ohne Reim oder Grund bewegen). Die neue Codebasis vermeidet dies, indem Datenbankabfragen in gespeicherte Prozeduren verschoben werden, ein saubereres Framework für die Verarbeitung von Anforderungen zur Verfügung steht und vieles mehr.Das erste, was wir uns vorgenommen haben, war zu versuchen, Modul für Modul umzugestalten. Dies bedeutet, alle Funktionen in einem bestimmten Bereich in ein neues Modul zu verschieben und dann den alten Code in das neue Modul einzufügen. Wenn die neue API sauber ist, ist dies keine große Sache. Wenn die neue API nicht funktioniert, werden die Dinge unruhig und das ist eine Einladung, ein bisschen härter an der neuen API zu arbeiten.
Die zweite Sache ist, dass es viele Male gibt, in denen neuer Code auf Logik in altem Code zugreifen muss. Dies ist so weit wie möglich zu vermeiden, da es zu hässlichen Klebemethoden führt, die man aber nicht immer vermeiden kann. In diesem Fall sollten die Klebemethoden so weit wie möglich minimiert und vermieden werden, aber bei Bedarf eingesetzt werden.
Damit dies funktioniert, müssen Sie alle Funktionen in einem bestimmten Bereich neu schreiben . Wenn Sie beispielsweise den gesamten Kundeninformations-Tracking-Code auf einmal umschreiben können, bedeutet dies, dass der Code, der dies vom alten Code aufruft, nicht schwer zu verarbeiten ist und der Versand an den alten Code vom neuen Code minimiert wird.
Die zweite Sache ist, dass Sie, wenn Sie vernünftige Abstraktionen an Ihrer Stelle haben, in der Lage sein sollten, zu wählen, welche Ebene der API aufgerufen werden soll und wie diese sauber gehalten werden soll. Sie sollten jedoch darüber nachdenken, die Teile, die Ihre API aufrufen, neu zu schreiben, damit sie auch ein bisschen sauberer sind.
Es gibt viele Bereiche von Geschäftstools, die irreduzibel komplex sind. Sie können nicht alle Komplexität loswerden. Sie können es jedoch verwalten, indem Sie sich auf saubere APIs konzentrieren, die genau das tun, was Sie tun müssen, und auf Module, die diese API konstruktiv nutzen. Kleber sollte ein letzter Ausweg sein, wenn man bedenkt, dass das Umschreiben des restlichen aufrufenden Codes möglicherweise schneller ist.
quelle
Es hört sich so an, als ob Sie ein Wirrwarr aus einer vor- uralen Codebasis genommen und eine schöne modulare vor- urale Codebasis erstellt haben.
Mit prozeduralem Code (auch wenn er als OO getarnt ist) wird immer irgendwo ein sequentieller Workflow definiert, der häufig mit komplexen bedingten Verzweigungen gefüllt ist, wie Sie beschreiben. Ich vermute, es ist diese prozedurale Natur des Codes, die Sie das Gefühl gibt, dass etwas nicht stimmt. Dies ist nicht unbedingt eine schlechte Sache, und wenn Sie mit Legacy-Code arbeiten, ist dies möglicherweise unvermeidlich
quelle
Sie sollten die große hässliche Klebemethode genauso bereinigen, wie Sie die ursprüngliche Codebasis bereinigt haben. Teilen Sie es in übersichtliche modulare Methoden auf. Sie haben wahrscheinlich Gruppen von Codezeilen, die einige Aufgaben erledigen, die diese Zeilen in Methoden aufteilen. Wenn Sie einige Variablen gemeinsam nutzen, können Sie erwägen, die gemeinsam genutzten Variablen und die neuen Methoden in eine Klasse einzuteilen.
quelle
Grundsätzlich fügen Sie immer wieder Abstraktionsebenen hinzu, bis jede Ebene für sich betrachtet wird . Das Paradoxe an der Abstraktion ist, dass Sie die Komplexität erhöhen, um sie zu reduzieren, da Sie sich beim Lesen von abstrahiertem Code immer nur mit einer Ebene beschäftigen. Wenn jede Schicht klein genug ist, um leicht verstanden zu werden, spielt es keine Rolle, auf wie vielen Schichten sie ruht.
Das macht es auch schwierig, Abstraktionen zu schreiben. Sogar etwas so Einfaches wie ein Bleistift kann den Verstand beugen, wenn Sie versuchen, alle Abstraktionsebenen gleichzeitig in Ihrem Kopf zu halten. Der Schlüssel besteht darin, eine Ebene so zu erstellen, wie Sie es möchten, und dann die Komplexität zu vergessen, die dieser Ebene zugrunde liegt, und dasselbe auf der nächsten Ebene zu tun.
quelle
Es hört sich so an, als würden Sie die API umgestalten, indem Sie nur an die Implementierung der API denken, aber nicht genug über den Code nachdenken, der die API verwendet - also den "Klebercode", von dem Sie sprechen.
Wenn das stimmt, versuchen Sie vielleicht, am anderen Ende zu beginnen. Schreiben Sie die Dinge, die zu Ihrem hässlichen Code werden könnten, neu und erstellen Sie einige noch nicht implementierte Schnittstellen, die in diesem Prozess zu Ihrer API werden. Denken Sie noch nicht zu viel über die tatsächliche Implementierung dieser API nach - es ist in Ordnung, wenn Sie das Gefühl haben, dies zu tun. Und erst dann schreiben Sie das Codelabyrinth neu, damit es mit dieser API übereinstimmt. Natürlich wird es in diesem Prozess einige Änderungen an der API und am Klebercode geben, aber es sollte besser zusammenpassen.
quelle