1 Punkte von GN⁺ 2023-11-16 | 1 Kommentare | Auf WhatsApp teilen

Bedingte Anweisungen innerhalb von Funktionen nach oben verschieben

  • Wenn es in einer Funktion eine if-Bedingung gibt, sollte erwogen werden, sie zum Aufrufer (caller) zu verschieben.
  • Anstatt dass die Funktion intern Vorbedingungen prüft und bei nicht erfüllten Bedingungen „nichts tut“, sollte der Aufrufer die Vorbedingungen prüfen, sodass über den Typ garantiert wird, dass die Vorbedingungen erfüllt sind.
  • Insbesondere das „Nach-oben-Verschieben“ von Vorbedingungen kann den gesamten Prüfaufwand verringern, was eine der Motivationen für diese Regel ist.

Schleifen nach unten verschieben

  • Eine Regel aus dem datenzentrierten Denken: Dabei wird das Konzept eines Objekt-„Batch“ eingeführt, Batch-Verarbeitung als Standardfall genommen und die skalare Version als Sonderfall der Batch-Version behandelt.
  • Der Hauptvorteil ist eine bessere Performance; Startkosten können amortisiert werden, und bei der Verarbeitungsreihenfolge kann mehr Flexibilität bestehen.
  • Zum Beispiel kann bei FFT-basierter Polynom-Multiplikation die gleichzeitige Auswertung eines Polynoms an mehreren Punkten schneller sein als einzelne Auswertungen.

Meinung von GN⁺

  • Das Wichtigste an diesem Artikel sind die beiden Programmierregeln „Bedingungen nach oben verschieben“ und „Schleifen nach unten verschieben“, mit denen sich in der Softwareentwicklung Performance und Klarheit des Codes verbessern lassen.
  • Diese Regeln helfen dabei, die Lesbarkeit des Codes zu erhöhen, die Performance zu optimieren und die Wahrscheinlichkeit von Bugs zu verringern.
  • Da der Artikel Einblicke darin gibt, wie man die Komplexität des Software Engineering beherrscht und effizienten Code schreibt, ist er für viele Entwickler interessant und nützlich.

1 Kommentare

 
GN⁺ 2023-11-16
Hacker-News-Kommentare
  • Es wird angemerkt, dass der Widerstand gegen Ratschläge zum datenorientierten Design überraschend ist. Da die meisten Forennutzer Webanwendungen schreiben, kann dieser Rat bedeutungslos erscheinen. Wenn man im Arbeitsalltag nicht über den Instruction Cache nachdenken muss, sollte man diesen Rat ignorieren. Ein Blick auf Mike Actons "Typical C++ Bullshit" kann helfen, die Bedeutung dieses Rats zu verstehen.
  • Es wird die Ansicht vertreten, dass Programmierer zwar darauf achten, Code im „Kleinen“ schön zu gestalten, sich aber nicht genug um die angemessene Gestaltung der gesamten Codebasis kümmern. Wenn eine Funktion gut benannt ist, ein gutes Interface hat, einen klaren Zweck erfüllt, angemessen dokumentiert ist und Nebenwirkungen nicht übermäßig nutzt, sollte man sich nicht allzu sehr darum kümmern, ob die Funktion unordentlich ist oder wie if und for angeordnet sind.
  • Von jemandem, der in der Wissenschaft mit dem Programmieren begonnen hat, kommt die Einschätzung, dass kleine Optimierungen wichtig sind. Wenn man die Reihenfolge von for-Schleifen falsch wählt, kann sich die Laufzeit einer Simulation von einer Woche auf eine Stunde verkürzen. Wer aus so einem Hintergrund kommt, optimiert die Reihenfolge von for und if instinktiv.
  • Es wird argumentiert, dass man, wenn es einen „Container“ gibt, nicht Funktionen für den Container schreiben sollte, sondern für das Domain-Level-„Thing“, das der Container enthält. Das macht den Code flexibler und trennt den Kerndomainbereich klarer von den Belangen der Anwendung.
  • Ein Nachteil des Hochziehens von if besteht darin, dass Vorbedingungen und Nachbedingungen einer Funktion in der Funktionsdefinition selbst nicht mehr direkt sichtbar sind. In großen Projekten können solche Funktionen außerhalb des beabsichtigten Kontexts wiederverwendet werden und Bugs verursachen. Die Verwendung eines Contract-Frameworks könnte eine Lösung sein, allerdings müssen Bedingungen dann sowohl im Vertrag als auch im Code doppelt geschrieben werden.
  • An einem Beispiel mit der Sprache Rust wird gezeigt, dass Rusts starkes Typsystem defensive Programmierung verhindert, die in anderen Sprachen nötig ist. Es ist nicht wünschenswert, wenn ein C-Programmierer die Gültigkeit eines an eine Funktion übergebenen Pointers nicht prüft und dadurch eine NULL-Dereferenz erzeugt. Manche if sollten eher am Anfang als am Ende einer Funktion stehen, und Fehler sollten sauber propagiert werden.
  • Es wird angemerkt, dass der Artikel auf ein bestimmtes Codebeispiel hinauszulaufen schien, dies aber tatsächlich nicht tat. Statt des erwarteten Codebeispiels wird ein anderes Beispiel präsentiert.
  • Ohne angemessenen Kontext könnte dieser Rat seltsam oder sogar schlecht sein. for-Schleifen und if-Anweisungen sind beides Kontrollflussoperationen, daher wirken manche Behauptungen im Artikel bedeutungslos. Das Leistungsargument ist am stärksten, sollte bei allgemeinen Ratschlägen aber zuletzt bedacht werden.
  • Es wird bezweifelt, dass sich solche allgemeinen Regeln auf echten Code anwenden lassen. Solche Regeln würden oft als falsches Dogma betrachtet, und junge Programmierer könnten sie missverstehen und dadurch schlechteren Code schreiben. Oft hängt eine Bedingung von einem walrus ab, weshalb sich if nicht nach oben ziehen lässt.
  • Es wird die Ansicht vertreten, dass es eine schreckliche Idee ist, Vorbedingungs-if zum Aufrufer zu verlagern. In Sonderfällen mag das sinnvoll sein, im Allgemeinen möchte man das jedoch nicht. In Bibliotheken sollten Vorbedingungen an den externen Grenzen geprüft werden, damit die interne Implementierung ohne interne Annahmen fortfahren kann. Sich darauf zu verlassen, dass der Aufrufer prüft, würde den Zweck zunichtemachen.