Beeinträchtigt die Funktionslänge die Produktivität eines Programmierers? Wenn ja, wie hoch ist die maximale Anzahl von Zeilen, um Produktivitätsverluste zu vermeiden?
Da dies ein Thema ist, das von großer Meinung ist, sollten Sie den Anspruch mit einigen Daten untermauern.
programming-practices
coding-standards
Peter Mortensen
quelle
quelle
Antworten:
Da ich auf diesem verrückten Schläger im Jahr 1970 in Angriff genommen, habe ich gesehen , genau ein Modul , das wirklich benötigte mehr als eine gedruckte Seite zu sein (ca. 60 Zeilen). Ich habe viele Module gesehen, die länger waren.
Im Übrigen habe ich Module geschrieben, die länger waren, aber normalerweise waren sie große Zustandsautomaten, die als große switch-Anweisungen geschrieben wurden.
Ein Teil des Problems scheint darin zu liegen, dass Programmierer heutzutage nicht in der Lage sind, Dinge zu modularisieren.
Codierungsstandards, die die Verschwendung von vertikalem Raum maximieren, scheinen ebenfalls Teil des Problems zu sein. (Ich habe noch keinen Softwaremanager getroffen, der Gerald Weinbergs " Psychology of Computer Programming " gelesen hat . Weinberg weist darauf hin, dass mehrere Studien gezeigt haben, dass das Verständnis von Programmierern im Wesentlichen auf das beschränkt ist, was der Programmierer zu einem bestimmten Zeitpunkt sehen kann Programmierer müssen blättern oder eine Seite umblättern, ihr Verständnis sinkt erheblich: sie müssen sich erinnern und abstrahieren.)
Ich bin nach wie vor davon überzeugt, dass ein Großteil der gut dokumentierten Produktivitätssteigerungen für Programmierer von FORTH auf das FORTH-Blocksystem für Quellcode zurückzuführen ist: Module waren auf ein absolutes Maximum von 16 Zeilen mit 64 Zeichen beschränkt. Sie könnten unendlich faktorisieren, aber Sie könnten unter keinen Umständen eine Routine mit 17 Zeilen schreiben.
quelle
Was ist die richtige Größe, wirklich?
Kommt auf die Sprache an, die du benutzt, aber im Allgemeinen (und für meinen persönlichen Geschmack):
Wenn es mehr ist, dann ist es etwas, worauf ich später zurückkommen und es überarbeiten muss.
Aber realistisch ist , dass jede Größe, die benötigt wird, um etwas auszuliefern, und dass es im Moment sinnvoller ist, sie so auszuspucken, es für jemanden manchmal noch einfacher macht, sie vor dem Versand zu überprüfen. (aber später noch zurück).
(Vor kurzem hat mein Team ein Programm auf unserer Codebasis ausgeführt: Wir fanden Klasse mit 197 Methoden und eine andere mit nur 3 Methoden, aber eine davon bestand aus 600 Zeilen. Süßes Spiel: Was ist das Schlimmste der 2 Übel?)
Jetzt noch eine Antwort auf die Frage nach Zen ... Im Allgemeinen wird es als gute Praxis angesehen, einen oder zwei großartige Männer zu zitieren.
Nachtrag zu Kommentarstilen
Als Ergänzung dazu sollten Ihre Funktionen eindeutige Namen haben, die ihre Absicht erklären. In Bezug auf Kommentare kommentiere ich normalerweise nicht innerhalb einer Funktion:
Ein Kommentarblock am Anfang jeder Funktion (der eine Erklärung erfordert) ist ausreichend. Wenn Ihre Funktion klein ist und Funktionsnamen explizit genug sind, müssen Sie nur sagen, was Sie erreichen möchten und warum. Ich verwende Inline-Kommentare nur für Felder in einigen Sprachen oder für Blockstarts für Funktionen, die gegen die 25-35-Zeilenregeln verstoßen, wenn die Absicht unklar ist. Ich verwende einen Blockkommentar im Code, wenn eine Ausnahmesituation eintritt (ein Catch-Block, in dem Sie nichts tun müssen oder wollen, sollte beispielsweise einen Kommentar enthalten, in dem angegeben ist, warum).
Für weitere Informationen lesen Sie bitte meine Antwort auf Stil und Empfehlungen zum Kommentieren von Code
quelle
tt
es meistens , um diese zu generieren, aber manchmal steckt man mit einer Long-Ass-Funktion (oder einer Long-Ass-Funktion) fest, die sowieso nichts von Interesse macht, also kein wirkliches Problem ist.Map(x => x.Property1); Map(x => x.Property2); Map(x => x.Property3);
so ist, ist klar, dass alles ziemlich gleich ist. (Beachten Sie, dass dies nur ein Beispiel ist. Diese Art von Funktion wird von Zeit zu ZeitMeiner Meinung nach sollte jede Funktion so klein wie möglich sein. Jede Funktion sollte nur eines tun und es gut machen. Das beantwortet nicht wirklich die Frage nach der maximalen Länge, aber es sind eher meine Gefühle bezüglich der Länge von Funktionen.
Um die Worte von Onkel Bob zu verwenden: "Extrahieren, bis Sie einfach nicht mehr extrahieren können. Extrahieren, bis Sie fallen."
quelle
Was sollte die maximale Höhe eines Gebäudes sein? Hängt davon ab, wo sich der Build befindet oder wie hoch er sein soll.
Möglicherweise erhalten Sie unterschiedliche Antworten von verschiedenen Personen aus verschiedenen Städten.
Einige Skriptfunktionen und Kernel-Interrupt-Handler sind sehr lang.
quelle
Eine Methode, die bei mir funktioniert, ist: Kann ich einem Teil einer längeren Funktion einen Namen geben, der Sinn macht. Ich denke, die Länge einer Methode ist nicht so wichtig wie eine gute Benennung. Die Methode sollte das tun, was der Name sagt, nicht mehr und nicht weniger. Und Sie sollten in der Lage sein, einen guten Namen zu geben. Wenn Sie Ihre Methode nicht gut benennen können, ist der Code wahrscheinlich nicht gut zusammengesetzt.
quelle
Solange es sein muss, um das zu tun, was es tun muss, aber nicht länger.
quelle
Ich denke, es gibt einen Kompromiss. Wenn Sie viele kurze Methoden haben, ist es oft schwieriger, sie zu debuggen als eine lange Methode. Wenn Sie den Editor 20 oder 30 Mal hintereinander verwenden müssen, um einen Methodenaufruf zu verfolgen, ist es schwierig, alles im Kopf zu behalten. In der Zwischenzeit ist es oft einfacher, im Kopf zu bleiben, wenn es eine gut geschriebene, klare Methode gibt, selbst wenn es 100 Zeilen sind.
Die eigentliche Frage ist, warum sich die Elemente in unterschiedlichen Methoden befinden sollten, und die Antwort lautet, wie oben angegeben, Wiederverwendung von Code. Wenn Sie den Code nicht wiederverwenden (oder nicht wissen), ist es möglicherweise sinnvoll, ihn in einer riesigen, einfach zu befolgenden Methode zu belassen. Teilen Sie dann, wenn Sie ihn wiederverwenden möchten, die Teile auf, die neu verwendet werden müssen. Verwendung in kleinere Methoden.
In Wirklichkeit besteht ein Teil eines guten Methodendesigns darin, funktionell zusammenhängende Methoden zu erstellen (im Wesentlichen tun sie eine Sache). Die Länge der Methoden spielt keine Rolle. Wenn eine Funktion eine genau definierte Aufgabe ausführt und 1.000 Zeilen umfasst, ist dies eine gute Methode. Wenn eine Funktion 3 oder 4 Dinge macht und nur 15 Zeilen hat, dann ist es eine schlechte Methode ...
quelle
Ich finde es einfacher zu verfolgen, was ich tue, wenn ich die gesamte Funktion auf einmal sehen kann. So schreibe ich am liebsten Funktionen:
Ich schreibe selten längere Funktionen. Die meisten davon sind gigantische C / C ++ - Schalteranweisungen.
quelle
Für mich ist eine Funktion eine beliebige Länge. Die meiste Zeit, in der ich es aufteile, werde ich Code wiederverwenden.
Grundsätzlich halte ich mich an das Prinzip 'hohe Kohäsion, niedrige Kopplung' und es gibt keine Einschränkung für die Länge.
quelle
Die Frage sollte sein, wie viele Dinge eine Funktion tun soll. Und normalerweise ist es selten, dass Sie 100 Zeilen benötigen, um "eine" Sache zu tun. Das hängt wiederum von der Ebene ab, von der aus Sie den Code betrachten: Ist das Hashen eines Passworts eine Sache? Oder ist Hashing und Speichern des Passworts eine Sache?
Ich würde sagen, beginnen Sie mit dem Speichern des Passworts als eine Funktion. Wenn Sie das Gefühl haben, dass Hashing anders ist und Sie den Code überarbeiten. Ich bin in keinster Weise ein erfahrener Programmierer, aber meiner Meinung nach ist die ganze Idee von Funktionen klein: Je atomarer Ihre Funktionen sind, desto höher ist die Wahrscheinlichkeit der Wiederverwendung von Code, und Sie müssen niemals dieselbe Änderung an mehr als einer Stelle vornehmen , usw.
Ich habe gespeicherte SQL- Prozeduren gesehen , die über 1000 Zeilen ausgeführt werden. Beträgt die Anzahl der Zeilen gespeicherter Prozeduren auch weniger als 50? Ich weiß es nicht, aber es macht das Lesen des Codes zur Hölle. Sie müssen nicht nur weiter rauf und runter scrollen, sondern Sie müssen einigen Codezeilen auch einen Namen wie "this does validation1", "this updates in the database" usw. geben - eine Arbeit, die der Programmierer hätte tun sollen.
quelle
Aus der zyklomatischen Komplexität (Wikipedia):
Ich empfehle, dass Sie diese Zahl unter 10 in einer einzigen Methode halten. Wenn es 10 wird, dann ist es Zeit, neu zu faktorisieren.
Es gibt Tools, mit denen Sie Ihren Code auswerten und eine zyklomatische Komplexitätszahl erhalten können.
Sie sollten sich bemühen, diese Tools in Ihre Build-Pipeline zu integrieren.
Verfolgen Sie nicht buchstäblich eine Methodengröße, sondern versuchen Sie, deren Komplexität und Verantwortlichkeiten zu untersuchen. Wenn es mehr als eine Verantwortung hat, ist es wahrscheinlich eine gute Idee, die Faktoren neu zu bestimmen. Wenn die zyklomatische Komplexität zunimmt, ist es wahrscheinlich an der Zeit, neu zu faktorisieren.
Ich bin mir ziemlich sicher, dass es andere Tools gibt, die Ihnen ähnliche Rückmeldungen geben, aber ich hatte noch keine Chance, dies zu untersuchen.
quelle
Normalerweise versuche ich, meine Methoden / Funktionen auf dem Bildschirm eines 1680x1050-Monitors zu belassen. Wenn es nicht passt, verwenden Sie Hilfsmethoden / -funktionen, um die Aufgabe zusammenzufassen.
Es verbessert die Lesbarkeit sowohl auf dem Bildschirm als auch auf dem Papier.
quelle
Ich beschränke nichts auf eine harte Linie, da einige Funktionen Algorithmen implementieren, die von Natur aus komplex sind, und jeder Versuch, sie zu verkürzen, die Interaktionen zwischen den neuen, kürzeren Funktionen so kompliziert machen würde, dass das Nettoergebnis keine Reduzierung der Einfachheit wäre. Ich glaube auch nicht, dass die Idee, dass eine Funktion nur "eine Sache" tun sollte, ein guter Leitfaden ist, da "eine Sache" auf einer hohen Abstraktionsebene "viele Dinge" auf einer niedrigeren Ebene sein kann.
Für mich ist eine Funktion definitiv zu lang, wenn ihre Länge im Moment subtile Verstöße gegen DRY hervorruft, und das Extrahieren eines Teils der Funktion in eine neue Funktion oder Klasse könnte dies lösen. Eine Funktion kann zu lang sein, wenn dies nicht der Fall ist. Es kann jedoch leicht eine Funktion oder Klasse extrahiert werden, die den Code modularer macht, und zwar auf eine Weise, die angesichts absehbarer Änderungen in der Zukunft wahrscheinlich nützlich ist.
quelle
Kurz genug, um richtig optimiert zu werden
Methoden sollten so kurz sein, dass sie genau eines tun. Der Grund dafür ist einfach: So kann Ihr Code richtig optimiert werden.
In einer JIT-fähigen Sprache wie Java oder C # ist es wichtig, dass Ihre Methoden einfach sind, damit der JIT-Compiler schnell Code erstellen kann. Längere, kompliziertere Methoden erfordern natürlich mehr JIT-Zeit. Außerdem bieten JIT-Compiler nur eine Handvoll Optimierungen, von denen nur die einfachsten Methoden profitieren. Diese Tatsache wurde sogar in Bill Wagners Effective C # herausgestellt .
In einer niedrigeren Sprache wie C oder C ++ ist es ebenfalls wichtig, über kurze Methoden (etwa ein Dutzend Zeilen) zu verfügen, da auf diese Weise die Notwendigkeit minimiert wird, lokale Variablen im RAM statt in einem Register zu speichern. (Aka 'Register Spilling'.) Beachten Sie jedoch, dass in diesem nicht verwalteten Fall die relativen Kosten für jeden Funktionsaufruf ziemlich hoch sein können.
Und selbst in einer dynamischen Sprache wie Ruby oder Python helfen kurze Methoden auch bei der Optimierung des Compilers. In einer dynamischen Sprache ist die Optimierung umso schwieriger, je dynamischer eine Funktion ist. Zum Beispiel wird eine lange Methode, die ein X benötigt und ein Int, Float oder String zurückgeben könnte, wahrscheinlich viel langsamer ausgeführt als drei separate Methoden, die jeweils nur einen einzigen Typ zurückgeben. Dies liegt daran, dass der Compiler, wenn er genau weiß, welchen Typ die Funktion zurückgibt, auch die Funktionsaufrufsite optimieren kann. (ZB nicht auf Typkonvertierungen prüfen.)
quelle
Es hängt sehr davon ab, was im Code enthalten ist.
Ich habe eine tausendzeilige Routine gesehen, mit der ich kein Problem hatte. Es war eine riesige switch-Anweisung, keine Option überschritt ein Dutzend Zeilen und die einzige Kontrollstruktur in jeder Option war eine einzelne Schleife. Heutzutage wäre es mit Objekten geschrieben worden, aber das war damals keine Option.
Ich betrachte auch 120 Zeilen in einem Schalter vor mir. Kein Fall überschreitet 3 Zeilen - eine Wache, eine Aufgabe und die Pause. Es analysiert eine Textdatei, Objekte sind keine Möglichkeit. Jede Alternative wäre schwerer zu lesen.
quelle
Den meisten Compilern ist die Länge einer Funktion egal. Eine Funktion sollte funktional sein, aber sowohl leicht zu verstehen, zu ändern als auch für den Menschen wiederzuverwenden sein. Wählen Sie eine Länge, die am besten zu Ihnen passt.
quelle
Meine allgemeine Regel ist, dass eine Funktion auf den Bildschirm passen sollte. Es gibt nur drei Fälle, bei denen ich einen Verstoß festgestellt habe:
1) Versandfunktionen. In früheren Zeiten waren diese häufig, aber die meisten werden heutzutage durch Objektvererbung ersetzt. Objekte funktionieren jedoch nur in Ihrem Programm, und daher sehen Sie gelegentliche Versandfunktionen, wenn Sie Daten bearbeiten, die von einem anderen Ort stammen.
2) Funktionen, die eine ganze Reihe von Schritten ausführen, um ein Ziel zu erreichen, und bei denen den Schritten eine gute Unterteilung fehlt. Am Ende haben Sie eine Funktion, die einfach eine lange Liste anderer Funktionen in der angegebenen Reihenfolge aufruft.
3) Wie Nr. 2, wobei die einzelnen Schritte jedoch so klein sind, dass sie einfach inline und nicht separat aufgerufen werden.
quelle
Vielleicht ist die Funktionslänge keine so gute Metrik. Wir versuchen, die zyklomatische Komplexität auch für Methoden zu verwenden, und eine der zukünftigen Check-in-Regeln für die Quellcodeverwaltung sieht vor, dass die zyklomatische Komplexität für Klassen und Methoden niedriger als X sein muss.
Für Methoden ist X auf 30 gesetzt und das ist ziemlich eng.
quelle