it-swarm.dev

Sauberer lesbarer Code im Vergleich zu schnellem, schwer lesbarem Code. Wann die Grenze überschreiten?

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 Nice Clean Code zu etwas hässlicherem Code wechseln müssen, um ihn schneller zu machen.

Wann ist es in Ordnung, diese Grenze zu überschreiten?

67
Ken Cochrane

Sie überqueren die Grenze, wenn

  • Sie haben gemessen , dass Ihr Code zu langsam für die beabsichtigte Verwendung ist .
  • Sie haben alternative Verbesserungen ausprobiert, bei denen der Code nicht durcheinander gebracht werden muss.

Hier ist ein Beispiel aus der Praxis: Ein experimentelles System, das ich verwende, produzierte Daten zu langsam, 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 mit nicht hässlichem Code hinzugefügt, und jetzt liegt die CPU-Auslastung über 98%. Problem gelöst; Keine Hässlichkeit erforderlich.

118
Norman Ramsey

Es ist eine falsche Zweiteilung. Sie können Code schnell machen und einfach zu pflegen.

Sie schreiben es sauber, insbesondere mit einer möglichst einfachen Datenstruktur.

Dann finden Sie heraus, wo die Zeitverschwendung liegt (indem Sie es ausführen, nach Sie haben es geschrieben, nicht vorher), und beheben sie nacheinander. (Hier ist ein Beispiel.)

Hinzugefügt: Wir hören immer von Kompromissen, richtig, wie einem Kompromiss zwischen Zeit und Speicher oder einem Kompromiss zwischen Geschwindigkeit und Wartbarkeit? Obwohl solche Kurven durchaus existieren können, sollte nicht angenommen werden, dass ein bestimmtes Programm auf der Kurve oder sogar irgendwo in der Nähe davon ist.

Jedes Programm, das sich auf der Kurve befindet, kann leicht (indem es einem bestimmten Programmierertyp übergeben wird) sowohl viel langsamer als auch viel weniger wartbar gemacht werden, und dann ist es nicht in der Nähe der Kurve. Ein solches Programm bietet dann viel Raum, um schneller und wartbarer zu werden.

Nach meiner Erfahrung beginnen hier viele Programme.

58
Mike Dunlavey

In meiner OSS-Existenz mache ich eine Menge Bibliotheksarbeit, die auf Leistung abzielt und eng mit der Datenstruktur caller's verbunden ist (dh außerhalb der Bibliothek), wobei (von Natur aus) kein Mandat mehr besteht die eingehenden Typen. Hier ist der beste Weg, dies zu machen performant 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 Bibliothek Code kann "hässlicher" sein als Anwendung Code, einfach weil er hat weniger ( oder vielleicht keine) Kontrolle über die Eingänge, muss also einige Aufgaben durch verschiedene Mechanismen erfüllen. Oder wie ich es neulich ausdrückte:

"Codierung über der Klippe des Wahnsinns, also musst du nicht"

Jetzt Anwendung Code ist etwas anders, da dort "normale" (vernünftige) Entwickler normalerweise einen Großteil ihrer kollaborativen/beruflichen Zeit investieren; Die Ziele und Erwartungen der einzelnen sind (IMO) leicht unterschiedlich.

IMO, die obigen Antworten, die darauf hindeuten, dass es schnell sein kann und einfach zu warten, beziehen sich auf Anwendung Code, bei dem der Entwickler mehr Kontrolle über die Datenstrukturen hat. und verwendet keine Tools wie Meta-Programmierung. Es gibt jedoch verschiedene Möglichkeiten, Metaprogrammierung durchzuführen, mit unterschiedlichem Wahnsinn und unterschiedlichem Overhead. Auch in diesem Bereich müssen Sie die geeignete Abstraktionsebene auswählen. Aber wenn Sie aktiv, positiv und wirklich wollen, dass es unerwartete Daten auf die absolut schnellste Weise behandelt; es kann durchaus hässlich werden. Beschäftige dich damit; p

31
Marc Gravell

Wenn Sie den Code profiliert und überprüft haben, dass er tatsächlich zu einer erheblichen Verlangsamung führt.

27
Joel Rein

Sauberer Code ist bei schnell ausführendem Code nicht unbedingt exklusiv. Normalerweise wurde schwer lesbarer Code geschrieben, weil er schneller zu schreiben war, nicht weil er schneller ausgeführt wurde.

Das Schreiben von "schmutzigem" Code, um ihn schneller zu machen, ist wohl unklug, da Sie nicht sicher wissen, dass Ihre Änderungen tatsächlich etwas verbessern. Knuth drückte es am besten aus:

"Wir sollten kleine Wirkungsgrade vergessen, etwa 97% der Zeit: vorzeitige Optimierung ist die Wurzel allen Übels. Dennoch sollten wir unsere Chancen in diesen kritischen 3% nicht verpassen. Ein guter Programmierer wird es tun." Lassen Sie sich durch solche Überlegungen nicht zur Selbstzufriedenheit einlullen, er wird den kritischen Code sorgfältig prüfen; aber erst nachdem dieser Code identifiziert wurde. "

Mit anderen Worten, schreiben Sie den Code zuerst sauber. Profilieren Sie dann das resultierende Programm und prüfen Sie, ob es sich bei diesem Segment tatsächlich um einen Leistungsengpass handelt. Wenn ja, 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. Profilieren Sie dann das Ergebnis, um zu überprüfen, ob Sie tatsächlich eine Verbesserung vorgenommen haben.

13
tylerl

Da die Frage "schneller schwer lesbarer Code" lautet, lautet die einfache Antwort niemals. Es gibt nie eine Entschuldigung für das Schreiben von Code, der schwer zu lesen ist. Warum? Zwei Gründe.

  1. Was passiert, wenn Sie heute Abend auf dem Heimweg von einem Bus angefahren werden? Oder (optimistischer und typischer) dieses Projekt eingestellt und etwas anderem zugewiesen? Der kleine Vorteil, den Sie sich mit Ihrem Wirrwarr an Code vorgestellt haben, wird durch die Tatsache aufgewogen, dass niemand sonst ihn verstehen kann . Das Risiko für Softwareprojekte ist schwer zu übertreiben. Ich habe einmal mit einem großen PBX Hersteller gearbeitet (wenn Sie in einem Büro arbeiten, haben Sie wahrscheinlich eines ihrer Telefone auf Ihrem Schreibtisch). Ihr Projektmanager erzählte mir eines Tages, dass ihr Kernprodukt - die proprietäre Software, die eine Standard-Linux-Box in eine Telefonzentrale mit vollem Funktionsumfang verwandelte - im Unternehmen als "The Blob" bekannt war. Niemand verstand es mehr. Jedes Mal, wenn sie eine neue Funktion implementiert haben. Sie drückten auf Kompilieren, traten zurück, schlossen die Augen, zählten bis zwanzig und schauten dann durch die Finger, um zu sehen, ob es funktionierte. Kein Unternehmen benötigt ein Kernprodukt, das es nicht mehr kontrolliert, aber es ist ein erschreckend häufiges Szenario.
  2. Aber ich muss optimieren! OK, also haben Sie alle hervorragenden Ratschläge in anderen Antworten auf diese Frage befolgt: Ihr Code hat seine Leistungstestfälle nicht bestanden Sie haben es sorgfältig profiliert, die Engpässe identifiziert, eine Lösung gefunden ... und es wird einige Bit-Twiddling beinhalten. Gut: Jetzt optimieren. Aber hier ist das Geheimnis (und vielleicht möchten Sie sich für dieses hier hinsetzen): Optimierung und Reduzierung der Quellcodegröße sind nicht dasselbe . Kommentare, Leerzeichen, Klammern und aussagekräftige Variablennamen sind große Hilfsmittel für die Lesbarkeit, die Sie absolut nichts kosten, da der Compiler sie wegwirft. (Oder wenn Sie eine nicht kompilierte Sprache wie JavaScript schreiben - und ja, es gibt sehr gute Gründe, JavaScript zu optimieren -, können sie von einem Kompressor behandelt werden.) Lange, beengte, minimalistische Zeilen Code (wie der, den muntoo gepostet hat hier ) hat nichts mit Optimierung zu tun: Das ist ein Programmierer, der versucht zu zeigen, wie klug sie sind, indem er so viel Code wie möglich in so wenige Zeichen wie möglich packt. Das ist nicht klug, es ist dumm. Ein wirklich kluger Programmierer ist einer, der seine Ideen klar anderen mitteilen kann.
10
Mark Whitaker

Wenn es sich um Wegwerfcode handelt. Ich meine das wörtlich: Wenn Sie ein Skript schreiben, um eine einmalige Berechnung oder Aufgabe durchzuführen, und mit solcher Sicherheit wissen, dass Sie diese Aktion nie wieder ausführen müssen, dass Sie die Quelldatei ohne zu zögern 'rm' können, dann können Sie die hässliche Route wählen.

Ansonsten ist es eine falsche Zweiteilung - wenn Sie denken, Sie müssen es hässlich machen, um es schneller zu machen, machen Sie es falsch. (Oder Ihre Prinzipien bezüglich des guten Codes 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.)

4
maaku

Immer dann, 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. Montage, um zu versuchen, die Software eines Mitbewerbers auf dem diesjährigen beliebten CPU-Chip zu schlagen.

3
hotpaw2

Vergessen Sie nicht, dass Sie schwer lesbaren Code durch entsprechende Dokumentation und Kommentare 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. Sie beheben dies jedoch, indem Sie sich selbst erklären.

3
Carlos

Für mich ist es ein Anteil an Stabilität (wie in Beton zementiert, Ton im Ofen gebacken, 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 leichter kann er biegsam sein, wie nasser Ton, um produktiv zu bleiben. Ich betone auch Geschmeidigkeit und nicht Lesbarkeit. Für mich ist die einfache Änderung des Codes wichtiger als die einfache Lesbarkeit. Code kann leicht zu lesen und ein Albtraum zu ändern sein. Was nützt es, Implementierungsdetails zu lesen und leicht zu verstehen, wenn es sich um einen Albtraum handelt, der geändert werden muss? Sofern es sich nicht nur um eine akademische Übung handelt, besteht der Sinn des einfachen Verständnisses von Code in einer Produktionscodebasis in der Regel darin, ihn bei Bedarf einfacher ändern zu können. Wenn es schwierig ist, Änderungen vorzunehmen, gehen viele Vorteile der Lesbarkeit aus dem Fenster. Die Lesbarkeit ist im Allgemeinen nur im Kontext der Biegsamkeit nützlich, und die Biegsamkeit ist nur im Kontext der Instabilität nützlich.

Selbst der schwierigste Code, den man sich vorstellen kann, unabhängig davon, wie einfach oder schwer er zu lesen ist, ist natürlich kein Problem, wenn es nie einen Grund gibt, ihn zu ändern, sondern nur zu verwenden. Und es ist möglich, eine solche Qualität zu erreichen, insbesondere bei Systemcode auf niedriger Ebene, bei dem die Leistung häufig am meisten zählt. Ich habe immer noch regelmäßig C-Code, der sich seit Ende der 80er Jahre nicht geändert hat. Es musste sich seitdem nicht ändern. Der Code ist flüchtig, in den Tagen des Fummelns geschrieben, und ich verstehe ihn kaum. Dennoch ist es heute noch anwendbar, und ich muss seine Implementierung nicht verstehen, um es optimal nutzen zu können.

Das gründliche 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 Codeduplizierung als Entkopplungsmechanismus dienen, um die Stabilität auf eine Weise dramatisch zu verbessern, die es zu einem würdigen 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 10-fachen Grund, sich in Zukunft zu ändern.

Eine weitere hilfreiche Sache in der Praxis ist es, Ihre Bibliothek von den instabilen Teilen Ihrer Codebasis zu trennen und sie möglicherweise sogar separat zu erstellen, wie Sie es für Bibliotheken von Drittanbietern tun könnten (die ebenfalls nur dazu gedacht sind, nicht geändert zu werden, zumindest nicht von Ihrer Mannschaft). Gerade diese Art von Organisation kann verhindern, dass Menschen daran manipulieren.

Ein anderer ist der Minimalismus. Je weniger Ihr Code versucht, 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 schwer zu ändern sein wird, z. B. parallelisierter SIMD-Code, der auf den Tod abgestimmt wurde. Sie wirken der Schwierigkeit der Pflege des Codes entgegen, indem Sie die Wahrscheinlichkeit maximieren, dass Sie den Code nicht ändern müssen und ihn daher in Zukunft nicht mehr warten müssen. Dadurch werden die Wartungskosten auf Null gesenkt, unabhängig davon, wie schwierig die Wartung des Codes ist.

0
user204677