Wenn ich Code schreibe, versuche ich immer, meinen Code so sauber und lesbar wie möglich zu machen.
Hin und wieder kommt eine Zeit, in der Sie die Grenze überschreiten und von nettem sauberem Code zu etwas hässlicherem Code wechseln müssen, um ihn schneller zu machen.
Wann ist es in Ordnung, diese Grenze zu überschreiten?
performance
optimization
quality
readability
maintainability
Ken Cochrane
quelle
quelle
Antworten:
Sie überqueren die Grenze, wenn
Hier ist ein Beispiel aus der Praxis: Ein experimentelles System, das ich verwende, produzierte Daten zu langsam. Es dauerte über 9 Stunden pro Lauf und verbrauchte nur 40% der CPU. Anstatt den Code zu sehr durcheinander zu bringen, habe ich alle temporären Dateien in ein In-Memory-Dateisystem verschoben. Es wurden 8 neue Zeilen nicht hässlichen Codes hinzugefügt, und die CPU-Auslastung liegt jetzt über 98%. Problem gelöst; Keine Hässlichkeit erforderlich.
quelle
foo
und benenne sie um. Normalerweise befindetfoo_ref
sie sich direkt darüberfoo
in der Quelldatei. In meinem Testgeschirr fordere ichfoo
undfoo_ref
zur Validierung und relativen Leistungsmessung.Es ist eine falsche Zweiteilung. Sie können Code schnell und einfach pflegen.
Die Art und Weise, wie Sie es tun, ist, es sauber zu schreiben, insbesondere mit einer möglichst einfachen Datenstruktur.
Dann finden Sie heraus, wo die Zeit abläuft (indem Sie es ausführen, nachdem Sie es geschrieben haben, nicht vorher), und beheben Sie sie nacheinander. (Hier ist ein Beispiel.)
Hinzugefügt: Wir hören immer von Kompromissen, richtig, wie einem Kompromiss zwischen Zeit und Gedächtnis oder einem Kompromiss zwischen Geschwindigkeit und Wartbarkeit? Obwohl solche Kurven durchaus existieren können, sollte nicht angenommen werden, dass sich ein bestimmtes Programm auf der Kurve oder in der Nähe davon befindet.
Jedes Programm, das sich auf der Kurve befindet, kann auf einfache Weise (indem es einem bestimmten Programmierer übergeben wird) sowohl langsamer als auch weitaus weniger wartbar gemacht werden, und dann ist es bei weitem nicht in der Nähe der Kurve. Ein solches Programm hat dann viel Platz, um sowohl schneller als auch wartungsfreundlicher zu werden.
Nach meiner Erfahrung beginnen hier viele Programme.
quelle
In meiner OSS-Existenz mache ich eine Menge Bibliotheksarbeit, die auf Leistung abzielt und stark mit der Datenstruktur des Aufrufers (dh außerhalb der Bibliothek) verknüpft ist , ohne (beabsichtigt) das Mandat über die eingehenden Typen. Hier ist der beste Weg, um diese Performance zu verbessern, die Meta-Programmierung, was (da ich in .NET-Land bin) IL-Emit bedeutet. Das ist ein hässlicher, hässlicher Code, aber sehr schnell.
Auf diese Weise akzeptiere ich gerne, dass Bibliothekscode möglicherweise "hässlicher" als Anwendungscode ist, nur weil er weniger (oder möglicherweise keine) Kontrolle über die Eingaben hat und daher einige Aufgaben über verschiedene Mechanismen erledigen muss. Oder wie ich es neulich ausdrückte:
Jetzt ist der Anwendungscode etwas anders, da "normale" (vernünftige) Entwickler in der Regel einen Großteil ihrer gemeinsamen / beruflichen Zeit investieren. Die Ziele und Erwartungen der einzelnen (IMO) sind leicht unterschiedlich.
IMO, die obigen Antworten, die darauf hindeuten, dass es schnell und einfach zu warten ist, beziehen sich auf Anwendungscode , bei dem der Entwickler mehr Kontrolle über die Datenstrukturen hat und keine Tools wie Metaprogrammierung verwendet. Das heißt, es gibt verschiedene Möglichkeiten, Metaprogramme zu erstellen, mit unterschiedlichem Wahnsinn und unterschiedlichem Overhead. Auch in diesem Bereich müssen Sie die entsprechende Abstraktionsebene auswählen. Aber wenn Sie aktiv und positiv sind, möchten Sie wirklich, dass unerwartete Daten auf die absolut schnellste Art und Weise verarbeitet werden. es kann durchaus hässlich werden. Beschäftige dich damit; p
quelle
Wenn Sie den Code profiliert und überprüft haben, dass er tatsächlich zu einer erheblichen Verlangsamung führt.
quelle
Sauberer Code ist nicht unbedingt exklusiv für schnell ausgeführten Code. Normalerweise wurde schwer lesbarer Code geschrieben, weil er schneller zu schreiben war und nicht, weil er schneller ausgeführt wurde.
Es ist wohl unklug, "schmutzigen" Code zu schreiben, um ihn schneller zu machen, da Sie nicht sicher sind, ob Ihre Änderungen tatsächlich etwas verbessern. Knuth drückte es am besten aus:
Mit anderen Worten, schreiben Sie den Code zuerst sauber. Profilieren Sie dann das resultierende Programm und prüfen Sie, ob dieses Segment tatsächlich ein Leistungsengpass ist. Wenn dies der Fall ist, optimieren Sie den Abschnitt nach Bedarf und fügen Sie zahlreiche Dokumentationskommentare (möglicherweise einschließlich des Originalcodes) hinzu, um die Optimierungen zu erläutern. Erstellen Sie dann ein Profil des Ergebnisses, um zu überprüfen, ob Sie tatsächlich eine Verbesserung vorgenommen haben.
quelle
Da die Frage "schnell schwer lesbarer Code" lautet, lautet die einfache Antwort "nie". Es gibt keine Entschuldigung dafür, schwer lesbaren Code zu schreiben. Warum? Zwei Gründe.
quelle
Wenn es Wegwerfcode ist. Ich meine das wörtlich: wenn Sie ein Skript schreiben , eine einmalige Berechnung oder Aufgabe auszuführen, und wissen so sicher werden Sie nie wieder , dass die Aktion zu tun haben , dass Sie ‚rm Quelle-Datei‘ , ohne zu zögern, dann können Sie wählen , die hässliche Route.
Ansonsten ist es eine falsche Zweiteilung - wenn Sie denken, dass Sie es hässlich machen müssen, um es schneller zu machen, machen Sie es falsch. (Oder Ihre Prinzipien über das, was guter Code ist, müssen überarbeitet werden. Die Verwendung von goto ist in der Tat recht elegant, wenn es die richtige Lösung für das Problem ist. Dies ist jedoch selten der Fall.)
quelle
Immer wenn die geschätzten Kosten für eine geringere Leistung auf dem Markt höher sind als die geschätzten Kosten für die Codewartung für das betreffende Codemodul.
Die Leute machen immer noch verdrehte handcodierte SSE / NEON / etc. Versammlung, zum der Software irgendeines Konkurrenten auf dem populären CPU-Span dieses Jahres zu versuchen und zu schlagen.
quelle
Vergessen Sie nicht, dass Sie schwer lesbaren Code durch entsprechende Dokumentation und Kommentierung leicht verständlich machen können.
Im Allgemeinen Profil, nachdem Sie einfach zu lesenden Code geschrieben haben, der die gewünschte Funktion ausführt. Bei Engpässen müssen Sie möglicherweise etwas tun, das das Erscheinungsbild komplizierter macht, aber Sie beheben dies, indem Sie sich selbst erklären.
quelle
Für mich ist es ein gewisses Maß an Stabilität (wie in Beton zementiert, im Ofen gebrannter Ton, in Stein gemeißelt, in permanenter Tinte geschrieben). Je instabiler Ihr Code ist, je höher die Wahrscheinlichkeit ist, dass Sie ihn in Zukunft ändern müssen, desto flexibler muss er sein, um wie nasser Lehm produktiv zu bleiben. Ich betone auch die Geschmeidigkeit und nicht die Lesbarkeit. Für mich ist die Leichtigkeit, Code zu ändern, wichtiger als die Leichtigkeit, ihn zu lesen. Code kann einfach zu lesen und ein Albtraum zu ändern sein, und was nützt es, Implementierungsdetails zu lesen und leicht zu verstehen, wenn sie ein Albtraum sind, der geändert werden muss? Wenn es sich nicht nur um eine akademische Übung handelt, müssen Sie in der Regel in der Lage sein, Code in einer Produktionscodebasis leicht zu verstehen, um ihn bei Bedarf leichter ändern zu können. Wenn es schwierig ist, zu ändern, Dann gehen viele der Vorteile der Lesbarkeit aus dem Fenster. Lesbarkeit ist im Allgemeinen nur im Zusammenhang mit Nachgiebigkeit nützlich, und Nachgiebigkeit ist nur im Zusammenhang mit Instabilität nützlich.
Natürlich ist selbst der schwierigste Code, den man sich vorstellen kann, unabhängig davon, wie einfach oder schwer er zu lesen ist, kein Problem, wenn es keinen Grund gibt, ihn zu ändern, sondern nur zu verwenden. Und es ist möglich, eine solche Qualität zu erzielen, insbesondere für Low-Level-Systemcode, bei dem die Leistung häufig am meisten zählt. Ich verwende immer noch regelmäßig C-Code, der sich seit Ende der 80er Jahre nicht geändert hat. Es musste sich seitdem nicht mehr ändern. Der Code ist flüchtig und wurde in den Tagen des Fummelns geschrieben, und ich verstehe ihn kaum. Trotzdem ist es bis heute gültig, und ich muss die Implementierung nicht verstehen, um es optimal nutzen zu können.
Gründliches Schreiben von Tests ist eine Möglichkeit, die Stabilität zu verbessern. Ein anderer ist die Entkopplung. Wenn Ihr Code von nichts anderem abhängt, besteht der einzige Grund für eine Änderung darin, dass er sich selbst ändern muss. Manchmal kann eine geringe Menge an Code-Duplikaten als Entkopplungsmechanismus dienen, um die Stabilität auf eine Weise dramatisch zu verbessern, die es zu einem angemessenen Kompromiss macht, wenn Sie im Gegenzug Code erhalten, der jetzt völlig unabhängig von allem anderen ist. Jetzt ist dieser Code für Änderungen an der Außenwelt unverwundbar. In der Zwischenzeit hat Code, der von 10 verschiedenen externen Bibliotheken abhängt, den zehnfachen Grund, sich in Zukunft zu ändern.
Eine andere hilfreiche Sache in der Praxis ist es, Ihre Bibliothek von den instabilen Teilen Ihrer Codebasis zu trennen, möglicherweise sogar separat zu erstellen, wie dies für Bibliotheken von Drittanbietern der Fall ist (die ebenfalls nur dazu gedacht sind, verwendet zu werden, zumindest nicht von Ihnen geändert zu werden) Mannschaft). Nur diese Art von Organisation kann verhindern, dass Menschen daran manipulieren.
Ein weiterer Grund ist der Minimalismus. Je weniger Ihr Code versucht zu tun, desto wahrscheinlicher ist es, dass er das kann, was er gut kann. Monolithische Designs sind fast permanent instabil, da sie umso unvollständiger erscheinen, je mehr Funktionen hinzugefügt werden.
Stabilität sollte Ihr vorrangiges Ziel sein, wenn Sie Code schreiben möchten, der unweigerlich nur schwer zu ändern ist, z. Sie wirken der Schwierigkeit der Codewartung entgegen, indem Sie die Wahrscheinlichkeit maximieren, dass Sie den Code nicht ändern müssen und ihn daher in Zukunft nicht mehr warten müssen. Das senkt die Wartungskosten auf null, egal wie schwierig die Wartung des Codes ist.
quelle