Sollte mein Code TROCKEN oder lesbar sein, wenn es nicht beides sein kann?

14

Ich schreibe Ruby-Code für eine einfache Verschlüsselungsübung und bin häufig auf dieses Dilemma gestoßen (die Übung ist eine Solitär-Chiffre, wenn Sie es wissen müssen). Es ist eine Frage, ob ich meine Logik mit beschreibenden Variablen und Einzelschrittanweisungen ausstatten soll, die die Funktion lesbar machen, anstatt mit präzisen, sogar dichten Anweisungen, die Wiederholungen eliminieren und / oder Fehlermöglichkeiten minimieren.

Mein letztes Beispiel: Mein Programm nimmt Eingaben entgegen und kann aufgrund strenger Formatrichtlinien leicht feststellen, ob Eingaben verschlüsselt oder entschlüsselt werden sollen. Wenn der Verschlüsselungsschlüssel und die Nachricht kompatibel konvertiert / generiert sind, müssen Sie zur Vereinfachung den Schlüssel von der verschlüsselten Nachricht subtrahieren oder den Schlüssel zu einer unverschlüsselten Nachricht hinzufügen, um die gewünschte Ausgabe zu erhalten (stellen Sie sich den Schlüssel als Verschlüsselung vor, Nachricht + Verschlüsselung = Code; Code - Verschlüsselung = Nachricht). Die DRY-Position sagt mir, dass ich meine verschlüsselte Nachricht anders als meine unverschlüsselte Nachricht konvertieren soll, damit die Funktion, die den Verschlüsselungsschlüssel verwendet und auf die Nachricht anwendet, niemals zu unterscheiden braucht. Ich habe festgestellt, dass dies bedeutet, ich brauche einige verschachtelte if-Anweisungen in der Funktion, aber die Logik scheint solide zu sein. Dieser Code ist jedoch nicht leicht lesbar.

Andererseits könnte ich zwei verschiedene Funktionen schreiben, die basierend auf einem Flag aufgerufen werden, das gesetzt wird, wenn die Anwendung die Verschlüsselung oder Entschlüsselung bestimmt. Dies wäre einfacher zu lesen, würde jedoch die übergeordnete Funktion des Anwendens des Verschlüsselungsschlüssels auf eine Nachricht duplizieren (wodurch diese verschlüsselt oder entschlüsselt wird).

Soll ich mich zu lesbarem Code oder zu prägnantem Code neigen? Oder habe ich einen anderen Weg verpasst, um diese Funktionalität zu erhalten und beide Prinzipien zu erfüllen? Ist es eine Position in einer Größenordnung, in der man den Zweck des Projekts berücksichtigen und die besten Entscheidungen treffen muss, um diesem Zweck zu dienen?

Bisher tendiere ich dazu, prägnanten, DRY-Code gegenüber lesbarem Code hervorzuheben.

lutze
quelle
2
Erstens verwendbar, zweitens trocken, drittens lesbar. Hochverwendbarer Code führt zu hoch lesbarem, verbrauchendem Code, der DRY leichter erfüllt und lesbar ist. Dies ist der Grund, warum Sie böse Komplexitäten in Kauf nehmen und sie irgendwo mit einer netten API packen möchten, wenn sie nicht besser gemacht werden können. Zumindest wird der Code, der mit ihnen interagiert, davon verschont, bei diesem Ansatz ebenfalls schlecht zu sein.
Jimmy Hoffa
4
Einige aktuelle Codebeispiele könnten hilfreich sein. Ich vermute, Sie vermissen einen dritten Weg wie Funktionen höherer Ordnung, um trockenen und lesbaren Code zu haben
jk.
2
Kein Duplikat. Concise vs. Readable und DRY vs. Readable sind zwei sehr unterschiedliche Vergleiche. Nicht trocken zu sein ist viel gefährlicher als nicht präzise zu sein.
Djechlin
Gehen Sie einfach nicht in die Falle, dass die Annahme, dass stark duplizierter Code besser lesbar ist, weil er in ein vorhersehbares Muster fällt. Ich vermute, dass es einfach sein kann, so zu denken, bis Sie ein System gepflegt haben, das so stark dupliziert ist, dass Sie in einem Zweig subtile Fehler finden, die sich nicht in dem anderen, fast identischen Zweig befinden.
KChaloux
Ich verstehe nicht, was Sie unter "Funktion auf hoher Ebene zum Anwenden des Verschlüsselungsschlüssels auf die Nachricht" verstehen. Wenn Sie meinen, dass es eine Überlappung zwischen Ver- und Entschlüsselung gibt, ziehen Sie die Verwendung der Refactoring-Methode zum Extrahieren in Betracht, um die gemeinsamen Teile herauszufiltern.
Aaron Kurtzhals

Antworten:

20

DRY ist eine Richtlinie, keine Religion. Diejenigen, die es vor allem auf den Punkt bringen, haben es zu weit gebracht.

In erster Linie ist verwendbarer Code von größter Bedeutung. Wenn der Code nicht nützlich und verwendbar ist, ist er nicht ... und es macht keinen Sinn, ihn überhaupt zu schreiben.

Zweitens muss irgendwann jemand Ihren Code warten. Wenn Ihr Code nicht gewartet werden kann, werden sie Ihr "schönes" dichtes, prägnantes, trockenes Design unterbrechen, während Sie Ihren Namen verfluchen. Mach das nicht. Ich war diese Person und jedes Mal, wenn ich einen bestimmten Namen in der Code-Annotation sehe, schaudere ich.

Es ist clever, dichten Code ohne "beschreibende Variablen" zu erstellen und alles ohne Dokumentation in verschachtelte ternäre Ausdrücke mit Lambdas zu packen. Es ist schön zu wissen, dass Sie das können - aber nicht. Cleverer Code ist sehr schwer zu debuggen. Vermeiden Sie es, cleveren Code zu schreiben .

Die meiste Zeit in der Software wird für die Wartung der Software aufgewendet - nicht beim ersten Schreiben. Schreiben Sie den Code so, dass Sie (oder eine andere Person) Fehler schnell und einfach beheben und nach Bedarf Funktionen hinzufügen können, wobei nur wenige grundlegende Änderungen am Design erforderlich sind.

Gemeinschaft
quelle
Intuitiv oder nicht, Sie sind auf ein Problem gestoßen, das ich übersehen habe. Ich habe so viel wie möglich 'cleveren' Code für diese Übung geschrieben, nur um zu wissen, dass ich es tun kann. Das finde ich auch gut zu wissen, aber ich stimme Ihnen hier zu, dass es eine schlechte Praxis ist. Jetzt muss ich viel überarbeiten.
Lutze
1
@lutze Ich bin ein Perl- und manchmal Ruby-Programmierer und kann die Versuchung, dort cleveren Code zu schreiben, durchaus nachvollziehen. Eine Vorabversion dieser Antwort enthielt ein Zitat von Larry Wall über Hybris - ich glaube, dass dies eine sehr wichtige Tugend bei der Arbeit mit Code ist, die eines Tages beibehalten wird. Aufgrund der möglichen Kürze der Sprachen ist es manchmal schwierig, den Vorteil zu nutzen, mehr Code zu schreiben, anstatt nach cleverem, dichtem Code zu suchen ... bis Sie ihn pflegen müssen.
17

Aufgrund der Frage, ob Sie DRY verstehen, bin ich mir nicht sicher. DRY-Code ist nicht dasselbe wie prägnant. Sehr oft ist es umgekehrt.

Hier bin ich nicht sicher, was die große Sache für dieses Beispiel ist. Erstellen Sie eine Funktion zum Verschlüsseln, eine Funktion zum Entschlüsseln, Hilfsprogramme für allgemeine Funktionen (Mischbytes) und ein einfaches Front-End, um Eingaben zu treffen und das Ver- / Entschlüsseln zu bestimmen ... Keine Wiederholung.

Im Allgemeinen sind jedoch sowohl DRY als auch Lesbarkeit vorhanden, um die Pflege und Erweiterung des Codes zu unterstützen. Nicht alle Szenarien sind gleich, ein großer Lesbarkeitstreffer, um ein wenig Wiederholung zu entfernen, ist nicht gut, und es gibt auch keine Duplizierung, um ein wenig Lesbarkeit hinzuzufügen.

Wenn gedrückt, würde ich die Lesbarkeit bevorzugen. Duplizierter Code kann weiterhin getestet werden - unlesbarer Code führt dazu, dass Sie das Falsche tun (und testen).

Telastyn
quelle
Tolle Punkte, ich hatte in der Tat das DRY-Prinzip ein wenig mit dem Ziel eines prägnanten Codes kombiniert.
Lutze
12

Ich bin mit Ihrem speziellen Fall nicht vertraut, kann aber einige allgemeine Richtlinien geben.

Der Zweck sowohl der Lesbarkeit als auch von DRY ist die Wartbarkeit .

Die Wartbarkeit ist in den meisten Situationen wichtig, in denen Sie mehr Zeit mit der Pflege von Code verbringen als mit dem Schreiben. Dies gilt insbesondere dann, wenn Sie das Schreiben von Code als besondere Wartungsmaßnahme betrachten.

Leider wird DRY oft missverstanden. Dies liegt zum Teil daran, dass es so einfach zu sein scheint, aber wie viele einfache Dinge kann es auch ... kompliziert sein.

Die Absicht von DRY ist, dass jede Funktionseinheit nur an einem Ort vorhanden ist. Wenn das Prinzip befolgt wird, kann der Code-Betreuer, der die Aufgabe hat, die Funktionalität zu ändern oder zu überprüfen, den Code einmal verarbeiten. Wenn DRY nicht befolgt wird, besteht die sehr reale Gefahr, dass eine Kopie der Funktionalität nicht ordnungsgemäß verwaltet wird.

Die offensichtlichste Verletzung von DRY ist das Kopieren und Einfügen, bei dem ganze Codeblöcke wörtlich in der Codebasis wiederholt werden. Dies ist meiner Erfahrung nach überraschend häufig und trägt in keiner Weise zur besseren Lesbarkeit bei. Das Umgestalten des Codes, um eine gemeinsame Methode einzuführen, erhöht daher unweigerlich die DRY-Konformität und Lesbarkeit.

Die zweithäufigste Übertretung ist "Kopieren und etwas ändern". Das Refactoriing, um eine Comon-Methode mit Parametern einzuführen, oder das Zerlegen einer Funktion in Schritte und das Abstrahieren der Gemeinsamkeiten erhöht fast immer die Lesbarkeit.

Dann gibt es die subtileren Verstöße, bei denen die Funktionalität dupliziert wird, der Code jedoch anders ist. Dies ist nicht immer leicht zu erkennen, aber wenn Sie es sehen und überarbeiten, um den allgemeinen Code in eine einzige Methode / Klasse / Funktion zu ziehen, ist der Code normalerweise besser lesbar als zuvor.

Schließlich gibt es die Fälle der Wiederholung des Designs. Beispielsweise haben Sie das Statusmuster möglicherweise mehrmals in Ihrer Codebasis verwendet, und Sie erwägen eine Umgestaltung, um diese Wiederholung zu vermeiden. In diesem Fall ist Vorsicht geboten. Möglicherweise verringern Sie die Lesbarkeit, indem Sie mehr Abstraktionsebenen einführen. Gleichzeitig handelt es sich nicht wirklich um eine Verdoppelung der Funktionalität, sondern um eine Verdoppelung der Abstraktion. Manchmal ist es das wert ... aber oft nicht. Ihr Leitsatz wird sein, zu fragen, "welche davon besser zu warten ist".

Wann immer ich diese Urteilsrufe mache, versuche ich zu überlegen, wie viel Zeit die Leute damit verbringen werden, den Code zu pflegen. Wenn Code die Kernfunktionalität des Geschäfts darstellt, ist wahrscheinlich mehr Wartung erforderlich. In diesen Fällen möchte ich den Code für Personen wartbar machen, die mit der Codebasis und den damit verbundenen Abstraktionen vertraut sind. Ich würde mich freuen, etwas mehr Abstraktion einzuführen, um Wiederholungen zu reduzieren. Im Gegensatz dazu ist ein Skript, das selten verwendet und selten gewartet wird, für die Betreuer möglicherweise weniger leicht zu verstehen, wenn es zu viel Abstraktion beinhaltet. In diesem Fall würde ich mich auf der Seite der Wiederholung irren.

Ich berücksichtige auch das Erfahrungsniveau anderer Mitglieder meines Teams. Ich vermeide "ausgefallene" Abstraktionen mit unerfahrenen Entwicklern, nutze aber branchenweit anerkannte Designmuster für reifere Gruppen.

Zusammenfassend lässt sich sagen, dass die Antwort auf Ihre Frage darin besteht, alles zu tun, was Ihren Code am wartungsfreundlichsten macht. Was dies in Ihrem Szenario bedeutet, müssen Sie selbst entscheiden.

Kramii
quelle
Ich denke, Sie haben genau eines meiner Probleme geklärt. Das Beispiel, das ich für die Funktionalität gegeben habe, die ich nicht duplizieren wollte, ist mit größerer Wahrscheinlichkeit eine Duplizierung der Abstraktion.
Lutze
+1. Ich habe es derzeit mit einem System zu tun, das das Kopieren und Einfügen in lächerlichem Maße missbraucht hat. Durch das Ausklammern einer einzelnen Methode aus kopiertem / eingefügtem Code wurden heute mehr als 400 Zeilen aus einer meiner Klassen entfernt. Leider fand ich es in einer 900-Zeilen-Methode ...
KChaloux
1
Wenn derzeit zwei Codekonstrukte dasselbe tun, eine Änderung an einem jedoch im Allgemeinen keine Änderung an dem anderen implizieren sollte , ist das Kopieren / Einfügen möglicherweise besser als die allgemeine Funktionalität unter Berücksichtigung von Faktoren. Wenn Code zwei zeichenweise identische Methoden verwendet, die dasselbe für unterschiedliche Zwecke ausführen und die Auswahl der Methode konsistent auf den erforderlichen Zweck stützen, müssen die Dinge später für einen dieser Zwecke geringfügig ausgeführt werden, indem nur die entsprechenden geändert werden Die Methode wirkt sich nur auf die Verhaltensweisen aus, die betroffen sein sollten. Die Verwendung einer einzigen gängigen Methode hätte die Änderung erheblich erschweren können .
Supercat
7

Wenn Ihre Funktionen komplizierter und länger (also weniger lesbar) werden, wenn Sie versuchen, sie DRY zu machen, dann machen Sie es falsch. Sie versuchen, einer Funktion zu viel Funktionalität zu geben, weil Sie der Meinung sind, dass dies die einzige Möglichkeit ist, zu vermeiden, dieselben Codeteile in einer zweiten Funktion zu wiederholen.

Code DRY zu machen bedeutet fast immer, die allgemeine Funktionalität auf kleinere Funktionen umzustellen. Jede dieser Funktionen sollte einfacher (und damit besser lesbar) sein als die ursprüngliche. Um alles in der ursprünglichen Funktion auf der gleichen Abstraktionsebene zu halten, kann dies auch bedeuten, zusätzliche Teile, die nicht anderweitig verwendet werden, neu zu faktorisieren. Ihre ursprüngliche Funktion wird dann zu einer "High-Level-Funktion", die die kleineren aufruft, und sie wird auch kleiner und einfacher.

Wenn Sie dies tun, führt dies meist zu unterschiedlichen Abstraktionsebenen in Ihrem Code - und einige Leute glauben, dass ein solcher Code weniger lesbar ist. Nach meiner Erfahrung ist dies ein Irrtum. Der wichtigste Punkt hierbei ist, den kleineren Funktionen gute Namen zu geben, gut benannte Datentypen und Abstraktionen einzuführen, die von einer zweiten Person leicht erfasst werden können. Auf diese Weise sollten "DRY" und "readability" nur sehr, sehr selten in Konflikt geraten.

Doc Brown
quelle
2

Obwohl ich mir nicht sicher bin, was genau das Problem verursacht, ist meine Erfahrung, dass es Zeit ist, etwas zu überarbeiten, wenn Sie einen Konflikt zwischen DRY und Lesbarkeit feststellen.

Loren Pechtel
quelle
0

Ich würde an jedem Wochentag lesbar (= wartbar) anstelle von TROCKEN wählen. In der Realität stimmen beide oft überein, und jemand, der das Konzept von DRY bekommt, erzeugt im Allgemeinen (meistens) lesbaren Code.

Zdravko Danev
quelle
2
Ohne eine Erklärung kann diese Antwort für den Fall unbrauchbar werden, dass jemand anders eine gegenteilige Meinung äußert. Wenn zum Beispiel jemand eine Behauptung wie "Ich würde TROCKEN wählen (= wartbar) anstatt lesbar für jeden Wochentag" postet, wie würde diese Antwort dem Leser helfen, zwei gegensätzliche Meinungen zu ermitteln? Überlegen Sie , ob Sie es in eine bessere Form bringen
möchten
0

Sehr, sehr, sehr, sehr wenige Male in meiner Karriere habe ich einen legitimen Fall gefunden, der die Lesbarkeit von DRY bestätigt. Machen Sie es zuerst lesbar. Nenne die Dinge gut. Bei Bedarf kopieren und einfügen.

Treten Sie jetzt zurück und betrachten Sie die Gesamtheit, die Sie geschaffen haben, wie ein Künstler, der zurücktritt, um sein Gemälde zu betrachten. Jetzt können Sie die Wiederholung richtig identifizieren.

Wiederholter Code sollte entweder in eine eigene Methode umgestaltet oder in eine eigene Klasse extrahiert werden.

Das Wiederholen des Codes sollte der letzte Ausweg sein. Readable AND DRY zuerst, andernfalls readable, wenn Sie den Umfang des wiederholten Codes einschränken.

Greg Burghardt
quelle