Einzeiler vs. Lesbarkeit: Wann sollte die Reduzierung des Codes eingestellt werden? [geschlossen]

14

Kontext

Vor kurzem habe ich mich dafür interessiert, besser formatierten Code zu produzieren. Und damit meine ich, "Regeln zu befolgen, die von genug Leuten gebilligt wurden, um sie als eine gute Praxis zu betrachten" (da es natürlich niemals einen einzigen "besten" Weg zum Code geben wird).

Heutzutage codiere ich hauptsächlich in Ruby, daher habe ich angefangen, einen Linter (Rubocop) zu verwenden, um mir einige Informationen über die "Qualität" meines Codes zu liefern (diese "Qualität" wird vom Community-orientierten Projekt Ruby-Style-Guide definiert ).

Beachten Sie, dass ich „Qualität“ , wie in „Qualität der Formatierung“, nicht so sehr um die Effizienz des Codes verwenden, auch wenn in einigen Fällen der Codeeffizienz tatsächlich wird durch folgende Faktoren beeinträchtigt , wie der Code geschrieben wird.

Jedenfalls wurde mir bei all dem einiges klar (oder zumindest fiel mir ein):

  • Einige Sprachen (vor allem Python, Ruby und andere) ermöglichen es, großartige Code-Einzeiler zu erstellen
  • Das Befolgen einiger Richtlinien für Ihren Code kann ihn erheblich kürzer und dennoch sehr klar machen
  • Wenn Sie diese Richtlinien jedoch zu streng befolgen, ist der Code möglicherweise weniger klar und einfach zu lesen
  • Der Code kann einige Richtlinien fast perfekt einhalten und dennoch von schlechter Qualität sein
  • Die Lesbarkeit des Codes ist größtenteils subjektiv (wie in "Was ich als klar empfinde, ist für einen Mitentwickler möglicherweise völlig undurchsichtig").

Das sind nur Beobachtungen, natürlich keine absoluten Regeln. Sie werden auch bemerken, dass die Lesbarkeit von Code und das Befolgen von Richtlinien an dieser Stelle möglicherweise nicht miteinander zusammenhängen. In diesem Fall sind die Richtlinien jedoch eine Möglichkeit, die Anzahl der Möglichkeiten zum Neuschreiben eines Codeblocks einzugrenzen.

Nun einige Beispiele, um das alles klarer zu machen.

Beispiele

Nehmen wir einen einfachen Anwendungsfall: Wir haben eine Anwendung mit einem " User" Modell. Ein Benutzer hat optional firstnameund surnameund eine obligatorische emailAdresse.

Ich möchte eine Methode " name" schreiben, die dann name ( firstname + surname) des Benutzers zurückgibt, wenn mindestens sein firstnameoder surnamevorhanden ist, oder emailals Fallback - Wert, wenn nicht.

Ich möchte auch, dass diese Methode einen " use_email" als Parameter (Boolean) verwendet und die Benutzer - E - Mail als Fallback - Wert verwendet. Dieser " use_email" Parameter sollte standardmäßig (falls nicht übergeben) " true" lauten.

Der einfachste Weg, dies in Ruby zu schreiben, wäre:

def name(use_email = true)
 # If firstname and surname are both blank (empty string or undefined)
 # and we can use the email...
 if (firstname.blank? && surname.blank?) && use_email
  # ... then, return the email
  return email
 else
  # ... else, concatenate the firstname and surname...
  name = "#{firstname} #{surname}"
  # ... and return the result striped from leading and trailing spaces
  return name.strip
 end
end

Dieser Code ist der einfachste und verständlichste Weg, dies zu tun. Auch für jemanden, der Ruby nicht "spricht".

Nun wollen wir versuchen, das zu verkürzen:

def name(use_email = true)
 # 'if' condition is used as a guard clause instead of a conditional block
 return email if (firstname.blank? && surname.blank?) && use_email
 # Use of 'return' makes 'else' useless anyway
 name = "#{firstname} #{surname}"
 return name.strip
end

Dies ist kürzer, immer noch leicht zu verstehen, wenn nicht sogar einfacher (Guard-Klausel ist natürlicher zu lesen als ein bedingter Block). Die Guard-Klausel macht es auch konformer mit den Richtlinien, die ich verwende, also win-win hier. Wir reduzieren auch die Einrückungsstufe.

Verwenden wir jetzt etwas Ruby-Magie, um es noch kürzer zu machen:

def name(use_email = true)
 return email if (firstname.blank? && surname.blank?) && use_email
 # Ruby can return the last called value, making 'return' useless
 # and we can apply strip directly to our string, no need to store it
 "#{firstname} #{surname}".strip
end

Noch kürzer und den Richtlinien perfekt folgend ... aber viel weniger klar, da das Fehlen einer return-Anweisung es für diejenigen, die mit dieser Praxis nicht vertraut sind, etwas verwirrend macht.

Hier können wir die Frage stellen: Lohnt es sich wirklich? Sollten wir "Nein" sagen, machen Sie es lesbar und fügen Sie return"" hinzu (da wir wissen, dass dies die Richtlinien nicht einhält). Oder sollten wir sagen "Es ist in Ordnung, es ist die Ruby Art, die verdammte Sprache zu lernen!"?

Wenn wir Option B wählen, warum nicht noch kürzer machen:

def name(use_email = true)
 (email if (firstname.blank? && surname.blank?) && use_email) || "#{firstname} #{surname}".strip
end

Hier ist es, der Einzeiler! Natürlich ist es kürzer ... hier nutzen wir die Tatsache, dass Ruby den einen oder anderen Wert zurückgibt, je nachdem, welcher definiert ist (da E-Mail unter den gleichen Bedingungen wie zuvor definiert wird).

Wir können es auch schreiben:

def name(use_email = true)
 (email if [firstname, surname].all?(&:blank?) && use_email) || "#{firstname} #{surname}".strip
end

Es ist kurz, nicht so schwer zu lesen (ich meine, wir haben alle gesehen, wie ein hässlicher Einzeiler aussehen kann), guter Ruby, es entspricht der Richtlinie, die ich verwende ... Aber dennoch, verglichen mit der ersten Art zu schreiben es ist viel weniger leicht zu lesen und zu verstehen. Wir können auch argumentieren, dass diese Zeile zu lang ist (mehr als 80 Zeichen).

Frage

Einige Codebeispiele können zeigen, dass die Wahl zwischen einem Code "voller Größe" und vielen seiner reduzierten Versionen (bis auf den berühmten Einzeiler) schwierig sein kann, da Einzeiler, wie wir sehen können, nicht so beängstigend sein können, aber Trotzdem wird nichts den "Full-Size" -Code in Bezug auf die Lesbarkeit übertreffen ...

Hier ist also die eigentliche Frage: Wo aufhören? Wann ist kurz, kurz genug? Wie kann man wissen, wann der Code "zu kurz" und weniger lesbar wird (wenn man bedenkt, dass er ziemlich subjektiv ist)? Und noch mehr: Wie kann ich immer dementsprechend programmieren und vermeiden, Einzeiler mit "normalen" Codestücken zu mischen, wenn ich Lust dazu habe?

TL; DR

Die Hauptfrage hier ist: Wenn es darum geht, zwischen einem "langen, aber klaren, lesbaren und verständlichen Codeabschnitt" und einem "leistungsfähigen, kürzeren, aber schwerer zu lesenden / zu verstehenden Einzeiler" zu wählen, müssen Sie wissen, dass diese beiden die obersten und die obersten sind Der untere Teil einer Skala und nicht die beiden einzigen Optionen: Wie kann man definieren, wo die Grenze zwischen "klar genug" und "nicht so klar, wie es sein sollte" liegt?

Die Hauptfrage ist nicht die klassische "Einzeiler vs. Lesbarkeit: Welcher ist besser?" aber "Wie finde ich das Gleichgewicht zwischen diesen beiden?"

Bearbeiten 1

Kommentare in den Codebeispielen sollen "ignoriert" werden, sie sollen klarstellen, was passiert, sind jedoch bei der Bewertung der Lesbarkeit des Codes nicht zu berücksichtigen.

Sudiukil
quelle
7
Zu kurz für eine Antwort: Wiederholen Sie das iterative Refactoring, bis Sie sich nicht sicher sind, ob es besser als die vorherige Iteration ist. Beenden Sie dann die letzte Refactorisierung und machen Sie sie rückgängig.
Dom
8
Ich würde Variante 3 mit dem returnhinzugefügten Schlüsselwort bevorzugen . Diese sieben Zeichen verleihen meinen Augen einiges an Klarheit.
cmaster
2
Wenn Sie sich wirklich schrecklich fühlen, können Sie das Ganze als [firstname,surname,!use_email].all?(&:blank?) ? email : "#{firstname} #{surname}".strip... schreiben, weil es false.blank?true zurückgibt und der ternäre Operator Ihnen ein paar Zeichen erspart ... ¯ \ _ (ツ) _ / ¯
DaveMongoose
1
OK, ich muss fragen: Welche Klarheit soll das returnSchlüsselwort hinzufügen ?! Es werden keinerlei Informationen bereitgestellt . Es ist reine Unordnung.
Konrad Rudolph
2
Der Gedanke, dass Kürze Klarheit schafft, leidet nicht nur unter dem Gesetz der Abnahme der Renditen, sondern kehrt sich auch um, wenn man ihn aufs Äußerste drängt. Wenn Sie eine kurze Funktion umschreiben, um sie zu verkürzen, verschwenden Sie Ihre Zeit und das Gleiche gilt für den Versuch, die Übung zu rechtfertigen.
Sdenham

Antworten:

26

Egal welchen Code Sie schreiben, lesbar ist am besten. Short ist zweitbester. Und lesbar bedeutet in der Regel kurz genug, damit Sie den Code, die gut benannten Bezeichner und die gebräuchlichen Redewendungen der Sprache, in der der Code geschrieben ist, verstehen können.

Wenn dies sprachunabhängig wäre, wäre dies definitiv meinungsbasiert, aber im Rahmen der Ruby-Sprache denke ich, dass wir darauf antworten können.

Erstens besteht ein Merkmal und eine idiomatische Art, Ruby zu schreiben, darin, das returnSchlüsselwort wegzulassen, wenn ein Wert zurückgegeben wird, es sei denn, Sie kehren frühzeitig von einer Methode zurück.

Ein weiteres Merkmal und eine weitere Redewendung sind nachfolgende ifAnweisungen, um die Lesbarkeit des Codes zu verbessern. Eine der treibenden Ideen in Ruby ist das Schreiben von Code, der als natürliche Sprache gelesen wird. Dazu gehen wir zu _why's Poignant Guide to Ruby, Kapitel 3 .

Lesen Sie sich das Folgende vor.

5.times { print "Odelay!" }

In englischen Sätzen ist die Zeichensetzung (wie Punkte, Ausrufezeichen, Klammern) stumm. Interpunktion verleiht Wörtern Bedeutung und gibt Hinweise darauf, was der Autor mit einem Satz beabsichtigt hat. Lesen wir also Folgendes: Fünf Mal wird "Odelay!" Gedruckt.

Aus diesem Grund ist Codebeispiel 3 für Ruby am typischsten:

def name(use_email = true)
  return email if firstname.blank? && surname.blank? && use_email

  "#{firstname} #{surname}".strip
end

Wenn wir nun den Code lesen, heißt es:

Senden Sie die E-Mail zurück, wenn der Vorname und der Nachname leer sind, und verwenden Sie die E-Mail

(Rückkehr) Vorname und Nachname entfernt

Das kommt dem eigentlichen Ruby-Code ziemlich nahe.

Es sind nur 2 Zeilen des eigentlichen Codes, also ist es ziemlich knapp und es entspricht den Redewendungen der Sprache.

Greg Burghardt
quelle
Schöner Punkt. Es ist wahr, dass die Frage nicht auf Ruby ausgerichtet sein sollte, aber ich stimme zu, dass es hier nicht möglich ist, eine sprachunabhängige Antwort zu erhalten.
Sudiukil
8
Ich finde die Idee, Code wie natürliche Sprache klingen zu lassen, überbewertet (und manchmal sogar problematisch). Aber auch ohne diese Motivation komme ich zu dem gleichen Ergebnis wie diese Antwort.
Konrad Rudolph
1
Es gibt noch eine Optimierung, die ich möglicherweise am Code vornehmen würde. Das heißt, use_emailvor die anderen Bedingungen zu stellen, da es sich eher um eine Variable als um einen Funktionsaufruf handelt. Aber die String-Interpolation überflutet trotzdem den Unterschied.
John Dvorak
Das Strukturieren von Code nach natürlichen Sprachstrukturen kann dazu führen, dass Sie in die Sprachfallen geraten. Wenn Sie beispielsweise die nächsten Anforderungen lesen do send an email if A, B, C but no D, ist es selbstverständlich, 2 if / else -Blöcke einzugeben, wenn die Codierung wahrscheinlich einfacher ist if not D, send an email. Seien Sie beim Lesen der natürlichen Sprache vorsichtig und wandeln Sie sie in Code um, da Sie so eine neue Version der "Neverending Story" schreiben können . Mit Klassen, Methoden und Variablen. Immerhin keine große Sache.
Laiv
@Laiv: Das Lesen von Code in natürlicher Sprache bedeutet nicht, die Anforderungen wörtlich zu übersetzen. Es bedeutet, Code so zu schreiben, dass der Leser beim Vorlesen die Logik verstehen kann, ohne jedes Bit Code, Zeichen für Zeichen, Sprachkonstrukt für Sprachkonstrukt zu lesen. Wenn die Codierung if !Dbesser ist, ist das in Ordnung, da Des einen aussagekräftigen Namen hat. Und wenn sich der !Operator zwischen den anderen Codes verirrt, NotDwäre es angemessen , einen Bezeichner aufzurufen.
Greg Burghardt
15

Ich glaube nicht, dass Sie eine bessere Antwort erhalten, als "nach bestem Wissen und Gewissen". Kurz gesagt, Sie sollten eher nach Klarheit als nach Kürze streben . Oft ist der kürzeste Code auch der klarste. Wenn Sie sich jedoch nur auf die Erzielung von Kürze konzentrieren, kann die Klarheit darunter leiden. Dies ist eindeutig in den letzten beiden Beispielen der Fall, deren Verständnis mehr Aufwand erfordert als die der vorherigen drei Beispiele.

Ein wichtiger Gesichtspunkt ist das Publikum des Codes. Die Lesbarkeit hängt natürlich vollständig von der lesenden Person ab. Kennen die Leute, von denen Sie erwarten, dass sie den Code lesen (außer sich selbst), die Redewendungen der Ruby-Sprache? Nun, diese Frage können nicht zufällige Leute im Internet beantworten, dies ist nur Ihre eigene Entscheidung.

JacquesB
quelle
Ich stimme dem Publikum zu, aber es ist Teil meines Kampfes: Da meine Software oft Open Source ist, kann das Publikum sowohl aus Anfängern als auch aus "Ruby Gods" bestehen. Ich könnte es einfach halten, es den meisten Menschen zugänglich zu machen, aber es fühlt sich irgendwie wie eine Verschwendung der Vorteile an, die die Sprache bietet.
Sudiukil
1
Als jemand, der einen wirklich schrecklichen Code übernehmen, erweitern und warten musste, muss Klarheit gewinnen. Erinnern Sie sich an das alte Sprichwort - Schreiben Sie Ihren Code, als wäre der Betreuer ein rachsüchtiger Höllenengel, der weiß, wo Sie wohnen und wo Ihre Kinder zur Schule gehen.
uɐɪ
2
@Sudiukil: Das ist ein wichtiger Punkt. Ich schlage vor, dass Sie in diesem Fall nach idiomatischem Code streben (dh von guten Sprachkenntnissen ausgehen), da es unwahrscheinlich ist, dass Anfänger ohnehin zum Open-Source-Code beitragen. (
Andernfalls
7

Ein Teil des Problems ist hier "Was ist Lesbarkeit". Für mich schaue ich mir dein erstes Codebeispiel an:

def name(use_email = true)
 # If firstname and surname are both blank (empty string or undefined)
 # and we can use the email...
 if (firstname.blank? && surname.blank?) && use_email
  # ... then, return the email
  return email
 else
  # ... else, concatenate the firstname and surname...
  name = "#{firstname} #{surname}"
  # ... and return the result striped from leading and trailing spaces
  return name.strip
 end
end

Und ich finde es schwer zu lesen, da es voller "lauter" Kommentare ist, die nur den Code wiederholen. Zieh sie aus:

def name(use_email = true)
 if (firstname.blank? && surname.blank?) && use_email
  return email
 else
  name = "#{firstname} #{surname}"
  return name.strip
 end
end

und es ist jetzt so viel besser lesbar. Wenn ich es dann lese, denke ich "hmm, ich frage mich, ob Ruby den ternären Operator unterstützt? In C # kann ich es schreiben als:

string Name(bool useEmail = true) => 
    firstName.Blank() && surname.Blank() && useEmail 
    ? email 
    : $"{firstname} {surname}".Strip();

Ist so etwas in Ruby möglich? Ich arbeite mich durch Ihren Beitrag und sehe, dass es Folgendes gibt:

def name(use_email = true)
 (email if (firstname.blank? && surname.blank?) && use_email) || "#{firstname} #{surname}".strip
end

Alles gute Zeug. Aber das ist für mich nicht lesbar; einfach weil ich scrollen muss um die ganze zeile zu sehen. Also lassen Sie uns das beheben:

def name(use_email = true)
 (email if (firstname.blank? && surname.blank?) && use_email) 
 || "#{firstname} #{surname}".strip
end

Jetzt bin ich glücklich. Ich bin mir nicht ganz sicher, wie die Syntax funktioniert, aber ich kann verstehen, was der Code tut.

Aber das bin nur ich. Andere Leute haben sehr unterschiedliche Vorstellungen darüber, was ein gut lesbares Stück Code ausmacht. Sie müssen also Ihre Zielgruppe kennen, wenn Sie Code schreiben. Wenn Sie ein absoluter Anfänger sind, sollten Sie es einfach halten und möglicherweise wie Ihr erstes Beispiel schreiben. Wenn Sie unter professionellen Entwicklern mit langjähriger Ruby-Erfahrung arbeiten, schreiben Sie Code, der die Sprache nutzt, und halten Sie ihn kurz. Wenn es irgendwo dazwischen liegt, dann ziele auf irgendwo dazwischen.

Eines würde ich allerdings sagen: Vorsicht vor "cleverem Code", wie in Ihrem letzten Beispiel. Fragen Sie sich, [firstname, surname].all?(&:blank?)ob Sie sich nicht schlau fühlen, weil es Ihre Fähigkeiten unter Beweis stellt, auch wenn es jetzt etwas schwieriger zu lesen ist? Ich würde sagen, dass dieses Beispiel wahrscheinlich in diese Kategorie passt. Wenn Sie jedoch fünf Werte vergleichen würden, wäre das ein guter Code. Auch hier gibt es keine absolute Grenze. Sei dir nur bewusst, dass du zu schlau bist.

Fazit: Um lesbar zu sein, müssen Sie Ihre Zielgruppe kennen und Ihren Code entsprechend ausrichten und prägnanten, aber klaren Code schreiben. Schreiben Sie niemals "cleveren" Code. Halte es kurz, aber nicht zu kurz.

David Arno
quelle
2
Nun, ich habe vergessen, es zu erwähnen, aber die Kommentare sollten "ignoriert" werden. Sie sind nur hier, um denen zu helfen, die Ruby nicht gut kennen. Ein wichtiger Punkt für das Publikum, darüber habe ich nicht nachgedacht. Was die Version angeht, die Sie glücklich macht: Wenn es auf die Zeilenlänge ankommt, macht die dritte Version meines Codes (die mit nur einer return-Anweisung) das irgendwie und ist sogar ein bisschen verständlicher, nicht wahr?
Sudiukil
1
@Sudiukil, kein Ruby-Entwickler, fand ich am schwersten zu lesen und es passte nicht zu dem, was ich suchte (aus der Perspektive einer anderen Sprache) als die "beste" Lösung. Für jemanden, der mit der Tatsache vertraut ist, dass Ruby eine dieser Sprachen ist, die den Wert des letzten Ausdrucks zurückgibt, stellt es wahrscheinlich die einfachste und am einfachsten zu lesende Version dar. Auch hier dreht sich alles um Ihr Publikum.
David Arno
Ich bin kein Ruby-Entwickler, aber das ist für mich viel sinnvoller als die Antwort mit der höchsten Bewertung, die lautet: "Hier ist, was ich zurückgeben werde [Fußnote: unter einer bestimmten langen Bedingung]. Außerdem ist hier eine Zeichenfolge, die zu spät gekommen ist zu der Party." Logik, die im Wesentlichen nur eine case-Anweisung ist, sollte wie eine einzelne, einheitliche case-Anweisung geschrieben werden und nicht über mehrere scheinbar nicht zusammenhängende Anweisungen verteilt sein.
Paul
Persönlich würde ich mit Ihrem zweiten Codeblock gehen, außer ich würde die beiden Anweisungen in Ihrem else-Zweig zu einer kombinieren:return "#{firstname} #{surname}".strip
Paul
2

Dies ist wahrscheinlich eine Frage, bei der es schwierig ist, keine meinungsbasierte Antwort zu geben, aber hier sind meine zwei Cent.

Wenn Sie feststellen, dass die Kürzung des Codes die Lesbarkeit nicht beeinträchtigt oder sogar verbessert, entscheiden Sie sich dafür. Wenn der Code weniger lesbar ist, müssen Sie prüfen, ob es einen guten Grund gibt, ihn so zu belassen. Es nur zu tun, weil es kürzer oder cool ist oder weil man es kann, sind Beispiele für schlechte Gründe. Sie müssen auch überlegen, ob eine Kürzung des Codes für andere Personen, mit denen Sie zusammenarbeiten, weniger verständlich ist.

Was wäre also ein guter Grund? Eigentlich ist es ein Urteil, aber ein Beispiel könnte so etwas wie eine Leistungsoptimierung sein (nach Leistungstests natürlich nicht im Voraus). Etwas, das Ihnen Vorteile bringt, für die Sie bereit sind, mit verminderter Lesbarkeit zu bezahlen. In diesem Fall können Sie den Nachteil abmildern, indem Sie einen hilfreichen Kommentar abgeben (der erklärt, was der Code bewirkt und warum er ein bisschen kryptisch gemacht werden musste). Noch besser ist, Sie können diesen Code in eine separate Funktion mit einem aussagekräftigen Namen extrahieren, sodass nur eine Zeile an der Aufrufstelle erklärt, was (über den Namen der Funktion) vor sich geht, ohne auf Details einzugehen (die Leute haben jedoch unterschiedliche Namen) Meinungen dazu, so ist dies ein weiteres Urteil, das Sie machen müssen).

Filip Milovanović
quelle
1

Die Antwort ist etwas subjektiv, aber Sie müssen sich mit aller Ehrlichkeit fragen, ob Sie diesen Code verstehen könnten, wenn Sie in ein oder zwei Monaten darauf zurückkommen.

Jede Änderung sollte die Fähigkeit der durchschnittlichen Person verbessern, den Code zu verstehen. Um den Code verständlich zu machen, sollten Sie die folgenden Richtlinien beachten:

  • Respektieren Sie die Redewendungen der Sprache . C #, Java, Ruby und Python haben alle ihre bevorzugten Methoden, um dasselbe zu tun. Idiomatische Konstrukte helfen beim Verstehen von Code, mit dem Sie nicht vertraut sind.
  • Stoppen Sie, wenn Ihr Code nicht mehr lesbar ist . In dem von Ihnen bereitgestellten Beispiel geschah dies, als Sie Ihre letzten Paare reduzierenden Codes trafen. Sie haben den idiomatischen Vorteil des vorherigen Beispiels verloren und viele Symbole eingeführt, die viel Denken erfordern, um wirklich zu verstehen, was vor sich geht.
  • Verwenden Sie Kommentare nur, wenn Sie etwas Unerwartetes begründen müssen . Ich weiß, dass Ihre Beispiele dazu da waren, um Personen, die mit Ruby weniger vertraut sind, Konstrukte zu erklären, und das ist für eine Frage in Ordnung. Ich bevorzuge es, Kommentare zu verwenden, um unerwartete Geschäftsregeln zu erklären und sie zu vermeiden, wenn der Code für sich selbst sprechen kann.

Es gibt jedoch Zeiten, in denen erweiterter Code zum besseren Verständnis der Vorgänge beiträgt. Ein Beispiel dafür stammt aus C # und LINQ. LINQ ist ein großartiges Tool und kann in einigen Situationen die Lesbarkeit verbessern, aber ich bin auch auf eine Reihe von Situationen gestoßen, in denen es viel verwirrender war. Ich habe im Peer Review einige Rückmeldungen erhalten, die vorschlugen, den Ausdruck in eine Schleife mit geeigneten if-Anweisungen umzuwandeln, damit andere ihn besser beibehalten können. Als ich nachkam, hatten sie recht. Technisch gesehen ist LINQ für C # idiomatischer, aber es gibt Fälle, in denen die Verständlichkeit beeinträchtigt wird und eine ausführlichere Lösung dies verbessert.

Ich sage alles, um das zu sagen:

Verbessern Sie, wann Sie Ihren Code verbessern können (verständlicher)

Denken Sie daran, dass Sie oder jemand wie Sie diesen Code später pflegen müssen. Wenn Sie das nächste Mal darauf stoßen, kann dies Monate dauern. Tun Sie sich selbst einen Gefallen und versuchen Sie nicht, die Anzahl der Zeilen zu reduzieren, um Ihren Code zu verstehen.

Berin Loritsch
quelle
0

Lesbarkeit ist eine Eigenschaft, die Sie haben möchten, wenn Sie mehrere Einzeiler haben, nicht. Anstelle von "Einzeiler vs. Lesbarkeit" sollte die Frage also lauten:

Wann verbessern Einzeiler die Lesbarkeit und wann schaden sie ihr?

Ich glaube, Einzeiler sind gut lesbar, wenn sie diese beiden Bedingungen erfüllen:

  1. Sie sind zu spezifisch, um für eine Funktion extrahiert zu werden.
  2. Sie möchten den "Fluss" des Lesens des umgebenden Codes nicht unterbrechen.

Nehmen wir zum Beispiel an, es namewar kein guter Name für Ihre Methode. Das Kombinieren des Vor- und Nachnamens oder das Verwenden der E-Mail anstelle des Namens war keine Selbstverständlichkeit. Anstelle des nameBesten, was Sie sich einfallen lassen konnten, stellte sich heraus, dass es lang und umständlich war:

puts "Name: #{user.email_if_there_is_no_name_otherwise_use_firstname_and_surname(use_email)}"

Solch ein langer Name zeigt an, dass dies sehr spezifisch ist - wenn es allgemeiner wäre, hätten Sie einen allgemeineren Namen finden können. Das Einschließen in eine Methode hilft also weder bei der Lesbarkeit (zu lang) noch bei der Trockenheit (zu spezifisch, um anderswo verwendet zu werden). Lassen Sie den Code einfach dort.

Trotzdem - warum ein Einzeiler? Sie sind normalerweise weniger lesbar als mehrzeiliger Code. Hier sollten wir meine zweite Bedingung überprüfen - den Fluss des umgebenden Codes. Was ist, wenn Sie so etwas haben:

puts "Group: #{user.group}"
puts "Title: #{user.title}"
if user.firstname.blank? && user.surname.blank?) && use_email
  name = email
else
  name = "#{firstname} #{surname}"
  name.strip
end
puts "Name: #{name}"
puts "Age: #{user.age}"
puts "Address: #{user.address}"

Der mehrzeilige Code selbst ist lesbar - aber wenn Sie versuchen, den umgebenden Code zu lesen (die verschiedenen Felder zu drucken), unterbricht dieses mehrzeilige Konstrukt den Fluss. Das ist leichter zu lesen:

puts "Group: #{user.group}"
puts "Title: #{user.title}"
puts "Name: #{(email if (user.firstname.blank? && user.surname.blank?) && use_email) || "#{user.firstname} #{user.surname}".strip}"
puts "Age: #{user.age}"
puts "Address: #{user.address}"

Ihr Fluss wird nicht unterbrochen, und Sie können sich bei Bedarf auf den spezifischen Ausdruck konzentrieren.

Ist das dein Fall? Definitiv nicht!

Die erste Bedingung ist weniger relevant - Sie haben sie bereits als allgemein genug erachtet, um eine Methode zu verdienen, und einen Namen für diese Methode gefunden, der viel besser lesbar ist als die Implementierung. Offensichtlich würden Sie es nicht wieder in eine Funktion extrahieren.

Was die zweite Bedingung betrifft - unterbricht sie den Fluss des umgebenden Codes? Nein! Der umgebende Code ist eine Methodendeklaration. Das Auswählen von nameist der einzige Zweck. Die Logik, den Namen zu wählen, unterbricht nicht den Fluss des umgebenden Codes - es ist der eigentliche Zweck des umgebenden Codes!

Fazit: Machen Sie nicht den gesamten Funktionskörper zu einem Einzeiler

Einzeiler sind gut, wenn Sie etwas Komplexes tun möchten, ohne den Fluss zu unterbrechen. Eine Funktionsdeklaration unterbricht bereits den Ablauf (damit er nicht unterbrochen wird, wenn Sie diese Funktion aufrufen), sodass die Lesbarkeit nicht dadurch verbessert wird, dass der gesamte Funktionskörper einzeilig ist.

Hinweis

Ich beziehe mich auf "ausgewachsene" Funktionen und Methoden - nicht auf Inline-Funktionen oder Lambda-Ausdrücke, die normalerweise Teil des umgebenden Codes sind und in dessen Ablauf passen müssen.

Idan Arye
quelle