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.
Antworten:
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.
quelle
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).
quelle
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.
quelle
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.
quelle
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.
quelle
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.
quelle
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.
quelle