Sind lange Methoden immer schlecht? [geschlossen]


64

Als ich mich also früher umsah, bemerkte ich einige Kommentare darüber, dass lange Methoden schlechte Praxis sind.

Ich bin mir nicht sicher, ob ich der Meinung bin, dass lange Methoden schlecht sind (und ich möchte Meinungen von anderen).

Zum Beispiel habe ich einige Django-Ansichten, die ein wenig die Objekte bearbeiten, bevor sie an die Ansicht gesendet werden. Eine lange Methode sind 350 Codezeilen. Ich habe meinen Code so geschrieben, dass er sich mit den Parametern befasst - das Abfrageset wird sortiert / gefiltert, und dann werden die von meiner Abfrage zurückgegebenen Objekte nach und nach verarbeitet.

Die Verarbeitung ist also hauptsächlich eine bedingte Aggregation mit ausreichend komplexen Regeln, die nicht einfach in der Datenbank ausgeführt werden können. Daher habe ich einige Variablen außerhalb der Hauptschleife deklariert, die dann während der Schleife geändert werden.

variable_1 = 0
variable_2 = 0
for object in queryset :
     if object.condition_condition_a and variable_2 > 0 :
     variable 1+= 1
     .....
     ...    
     . 
      more conditions to alter the variables

return queryset, and context 

Nach der Theorie sollte ich also den gesamten Code in kleinere Methoden zerlegen, damit die View-Methode maximal eine Seite lang ist.

Nachdem ich in der Vergangenheit an verschiedenen Codebasen gearbeitet habe, finde ich manchmal, dass sie den Code weniger lesbar machen, wenn Sie ständig von einer Methode zur nächsten springen müssen, um alle Teile herauszufinden, während Sie die äußerste Methode im Kopf behalten.

Ich finde, dass man mit einer langen Methode, die gut formatiert ist, die Logik leichter erkennen kann, da sie in inneren Methoden nicht verborgen bleibt.

Ich könnte den Code in kleinere Methoden zerlegen, aber oft gibt es eine innere Schleife, die für zwei oder drei Dinge verwendet wird, was zu komplexerem Code oder Methoden führt, die nicht nur eine Sache, sondern zwei oder drei machen (alternativ dazu) Ich könnte innere Schleifen für jede Aufgabe wiederholen, aber dann wird es einen Leistungstreffer geben.

Gibt es einen Fall, in dem lange Methoden nicht immer schlecht sind? Gibt es immer einen Fall für Schreibmethoden, wenn sie nur an einem Ort verwendet werden?

UPDATE: Sieht so aus, als hätte ich diese Frage vor über einem Jahr gestellt.

Deshalb habe ich den Code nach der (gemischten) Antwort hier überarbeitet und in Methoden aufgeteilt. Da es sich um eine Django-App handelt, die komplexe Mengen zusammengehöriger Objekte aus der Datenbank abruft, ist das Testargument nicht vorhanden (es hätte wahrscheinlich den größten Teil des Jahres gedauert, um relevante Objekte für die Testfälle zu erstellen. Ich habe den Typ "Das muss gestern erledigt sein" Arbeitsumgebung, bevor sich jemand beschwert). Das Beheben von Fehlern in diesem Teil des Codes ist jetzt etwas einfacher, aber nicht so massiv.

Vor :

#comment 1 
bit of (uncomplicated) code 1a  
bit of code 2a

#comment 2 
bit of code 2a
bit of code 2b
bit of code 2c

#comment 3
bit of code 3

jetzt:

method_call_1
method_call_2
method_call_3

def method_1 
    bit of (uncomplicated) code 1a  
    bit of code 2a

def method_2 
    bit of code 2a
    bit of code 2b
    bit of code 2c

def method_3
    bit of code 3

156
Alle absoluten sind schlecht. Immer.
Joachim Sauer

30
Ich sehe das Argument "Methoden extrahieren, wenn Sie sie wiederverwenden können" ziemlich oft (in dieser oder ähnlichen Formen), aber ich kaufe es nicht: Wenn die Methode mehr als eine Sache tut, sollten Sie Methoden aus Gründen der Lesbarkeit daraus extrahieren. Wartbarkeit, auch wenn diese neuen Methoden nur an einer Stelle in Ihrem Code aufgerufen werden.
Joachim Sauer

4
@gnat: Wow, wäre hier nicht eine Art manuelles Inlining (über einen Präprozessor) im Build-Schritt eine bessere Lösung?
Joachim Sauer

11
Einer der besten Programmierer, die ich kenne, meinte, wenn Sie wirklich eine Kennzahl wollen, ist die Anzahl der lokalen Variablen besser als die tatsächliche Länge. Er arbeitete an einem komplexen Pfadoptimierer, bei dem die Eingeweide eine Methode waren, die mehrere hundert Zeilen lang war, aber die Menge an Zuständen (lokalen Variablen), die aufbewahrt wurden, sehr gering war.
Chuu

2
Lange Methoden sind nicht immer schlecht; aber sie sind etwas, das man sich immer ansehen und fragen sollte: "Ist das schlimm?"
Carson63000

Antworten:


80

Nein, lange Methoden sind nicht immer schlecht.

In dem Buch Code Complete wird gemessen, dass lange Methoden manchmal schneller und einfacher zu schreiben sind und nicht zu Wartungsproblemen führen.

In der Tat ist es wirklich wichtig, trocken zu bleiben und die Trennung der Anliegen zu respektieren. Manchmal ist die Berechnung nur langwierig, wird aber in Zukunft keine Probleme bereiten.

Nach meiner persönlichen Erfahrung fehlt es den meisten langen Methoden jedoch an einer Trennung der Bedenken. Tatsächlich stellen lange Methoden eine einfache Möglichkeit dar, um zu erkennen, dass im Code möglicherweise etwas nicht stimmt, und bei der Codeüberprüfung ist hier besondere Vorsicht geboten.

BEARBEITEN: Wenn Kommentare abgegeben werden, füge ich der Antwort einen interessanten Punkt hinzu. Tatsächlich würde ich auch Komplexitätsmetriken für die Funktion prüfen (NPATH, zyklomatische Komplexität oder noch besser CRAP).

In der Tat empfehle ich, solche Metriken nicht bei langen Funktionen zu überprüfen, sondern sie mit automatisierten Werkzeugen (wie zum Beispiel Checkstyle für Java) auf JEDE FUNKTION aufmerksam zu machen.


41
+1: "Nein, lange Methoden sind nicht immer schlecht", aber sie sind fast immer schlecht
Binary Worrier

67
Lange Methodenkörper sind ein klassischer Codegeruch : Es ist an sich kein Problem, aber ein Hinweis darauf, dass es dort wahrscheinlich ein Problem gibt.
Joachim Sauer

6
+1, aber ich würde trotzdem empfehlen, die zyklomatische Komplexität der langen Methode zu überprüfen . Hohe Werte weisen auf Methoden hin, die für einen Komponententest praktisch unmöglich sind (und bei langen Methoden fehlt sehr selten die Kontrollflusslogik).
Daniel B

11
Ich benutze Methodennamen, um Kommentare zu minimieren. Das führt manchmal zu Sachen wie "getSelectedNodeWithChildren", aber mein Kollege sagt mir immer wieder, dass mein Code gut lesbar ist. Ich versuche auch Abkürzungen zu vermeiden, sie sind schön zu schreiben, aber nicht so schön zu lesen.
K ..

4
@ da_b0uncer Das ist auch eine Politik, der ich folge. Das Lesen von Code ist schwieriger als das Schreiben. Daher lohnt sich der zusätzliche Aufwand beim Schreiben, um den Code lesbarer zu machen.
Deadalnix

55

Die meisten der Fokus hier scheint um das Wort zu sein , immer . Ja, Absolutes sind schlecht, und Software-Engineering ist fast so viel Kunst wie Wissenschaft, und all das ... aber ich muss sagen, dass für das von Ihnen angegebene Beispiel die Methode besser wäre, wenn sie geteilt wäre Nach oben. Dies sind die Argumente, die ich normalerweise verwende, um die Aufteilung Ihrer Methode zu rechtfertigen:

Lesbarkeit: Bei anderen bin ich mir nicht sicher, aber ich kann nicht schnell 350 Codezeilen lesen. Ja, wenn es sich um meinen eigenen Code handelt und ich viele Annahmen dazu machen kann, könnte ich ihn sehr schnell durchgehen, aber das ist nicht der springende Punkt. Überlegen Sie, wie viel einfacher diese Methode zu lesen wäre, wenn sie aus 10 Aufrufen anderer Methoden (jeweils mit einem beschreibenden Namen) bestünde. Auf diese Weise haben Sie eine Überlagerung in den Code eingefügt, und die High-Level-Methode bietet dem Leser einen kurzen Überblick über die aktuellen Vorgänge.

Bearbeiten - um das in ein anderes Licht zu rücken: Wie würden Sie diese Methode einem neuen Teammitglied erklären? Sicherlich hat es eine gewisse Struktur , die Sie entlang der Linien zusammenfassen kann : „Nun, es beginnt ab A zu tun, dann B, dann manchmal C, etc“. Eine kurze "Übersicht" -Methode, die andere Methoden aufruft, macht diese Struktur offensichtlich. Es ist äußerst selten, 350 Codezeilen zu finden, die keinen Nutzen bringen. Das menschliche Gehirn soll sich nicht mit Listen beschäftigen, die Hunderte von Elementen lang sind. Wir gruppieren sie.

Wiederverwendbarkeit: Lange Methoden haben in der Regel eine geringe Kohäsion - sie tun oft mehr als eine Sache. Geringer Zusammenhalt ist der Feind der Wiederverwendung; Wenn Sie mehrere Aufgaben in einer Methode kombinieren, wird sie an weniger Stellen wiederverwendet, als es hätte sein sollen.

Testbarkeit und Kohäsion: Ich erwähnte die zyklomatische Komplexität oben in einem Kommentar - es ist ein ziemlich gutes Maß dafür, wie komplex Ihre Methode ist. Es stellt die Untergrenze der Anzahl der eindeutigen Pfade durch Ihren Code dar, abhängig von den Eingaben (Bearbeiten: Korrigiert gemäß MichaelTs Kommentar). Dies bedeutet auch, dass Sie zum ordnungsgemäßen Testen Ihrer Methode mindestens so viele Testfälle benötigen, wie Sie für die zyklomatische Komplexität angegeben haben. Wenn Sie Code-Teile zusammenstellen, die nicht wirklich voneinander abhängig sind, können Sie leider nicht sicher sein, dass diese Abhängigkeit nicht vorhanden ist, und die Komplexität multipliziert sich in der Regel. Sie können sich diese Kennzahl als Hinweis auf die Anzahl der verschiedenen Dinge vorstellen, die Sie versuchen, zu tun. Wenn es zu hoch ist, ist es Zeit, sich zu teilen und zu erobern.

Refactoring und Struktur: Lange Methoden sind oft Anzeichen dafür, dass im Code eine Struktur fehlt. Oft konnte der Entwickler nicht herausfinden, welche Gemeinsamkeiten zwischen den verschiedenen Teilen dieser Methode bestehen und wo eine Grenze zwischen ihnen gezogen werden könnte. Zu erkennen, dass eine lange Methode ein Problem ist, und zu versuchen, sie in kleinere Methoden aufzuteilen, ist der erste Schritt auf einem längeren Weg, um tatsächlich eine bessere Struktur für das Ganze zu identifizieren. Vielleicht müssen Sie eine oder zwei Klassen erstellen. Am Ende wird es nicht unbedingt komplexer!

Ich denke auch, dass in diesem Fall die Entschuldigung für eine lange Methode ist "... einige Variablen, die außerhalb der Hauptschleife deklariert wurden, werden dann während der Schleife geändert". Ich bin kein Python-Experte, aber ich bin mir ziemlich sicher, dass dieses Problem durch eine Art Referenzübergabe trivial behoben werden könnte.


13
+1 für das Verleugnen des Immer-Teils der Frage und das Konzentrieren auf das Fleisch: Ob lange Methoden schlecht sind oder nicht. Ich denke, das OP sucht nach einer Rechtfertigung, als wäre sein Szenario ein Randfall. Wenn ich jedoch höre, dass die Leute ihre schlechten Praktiken als notwendig für das ungewöhnliche Szenario erklären, dann nur, weil sie sich nicht sehr bemüht haben, gute Praktiken anzuwenden. Die ungewöhnlichen Szenarien sind wirklich sehr ungewöhnlich, lange Methoden sind jedoch leider recht verbreitet.
Jimmy Hoffa

2
Wenn Sie sich die obige Liste ansehen, ist die Lesbarkeit meiner Erfahrung nach besser, wenn die Methode länger ist, viele Kommentare enthält und gut formatiert ist, als wenn Sie über den Code von Methode zu Methode springen müssen. Dies ist jedoch wahrscheinlich sehr subjektiv. Ich erwarte nicht, dass die Teile des Codes wiederverwendet werden. Der Großteil der Wiederverwendung des Codes erfolgt derzeit durch Vererbung.
wobbily_col

1
@wobbily_col Übrigens, wenn Sie nach einem gut geschriebenen Text suchen, der die Gründe für kürzere Methoden aufzeigt, lesen Sie die ersten Kapitel von Clean Code .
Daniel B

5
@wobbily_col Sie sagen, dass es verwirrend ist, zu viel herumspringen zu müssen, um den Code mit vielen Methoden zu verstehen. Ich denke, der fehlende Punkt hier liegt in der Wichtigkeit der Benennung. Wenn eine Methode einen guten Namen hat, müssen Sie sie nicht ansehen, um herauszufinden, was sie tut. Die aufrufende Methode sollte vollständig nachvollziehbar sein, ohne dass Sie die Funktionsweise der aufgerufenen Methoden kennen, die Sie beispielsweise jemals angewendet someVar.toString()und erlebt haben Sie mussten den Code von toString sehen, um zu wissen, was es tut? Sie haben es einfach abgelesen, weil Sie eine gute Methode benannt haben.
Jimmy Hoffa

4
Nebenbei bemerkt, eine Methode, die n Parameter benötigt, ist auch ein Codegeruch und zeigt an, dass die Methode möglicherweise mehr als eine Aufgabe erfüllt. Gleiches gilt für eine Methode, die schwer zu benennen ist. Und wenn es wirklich all diese Parameter braucht, sind sie normalerweise Teil eines umfassenderen Konzepts, das in eine Klasse für sich eingeschlossen werden kann und sollte. Natürlich könnten wir uns ein Beispiel einfallen lassen, bei dem es besser ist, diese Regel nicht zu verwenden. Mein Punkt ist, dass, wenn Sie eine solche Methode sehen, sie gründlich untersuchen, sie wahrscheinlich in irgendeiner Weise schlecht ist.
KL

28

Lange Methoden sind immer schlecht, aber manchmal besser als die Alternativen.


5
Ohne eine Erklärung kann diese Antwort für den Fall unbrauchbar werden, dass jemand anders eine gegenteilige Meinung äußert. Zum Beispiel, wenn jemand eine Behauptung wie "Lange Methoden sind nie schlecht, aber gelegentlich schlechter als die Alternativen." , wie würde diese Antwort dem Leser helfen, zwei gegensätzliche Meinungen zu treffen? Überlegen Sie , ob Sie es in eine bessere Form bringen
möchten

9

Lange Methoden sind ein Codegeruch . Sie zeigen normalerweise an, dass etwas nicht stimmt, aber es ist keine feste Regel. Normalerweise beinhalten Fälle, in denen sie gerechtfertigt sind, viele staatliche und ziemlich komplexe Geschäftsregeln (wie Sie festgestellt haben).

Was Ihre andere Frage betrifft, ist es häufig hilfreich, Teile der Logik in separate Methoden zu unterteilen, selbst wenn sie nur einmal aufgerufen werden. Dies erleichtert das Erkennen der übergeordneten Logik und kann die Ausnahmebehandlung ein wenig übersichtlicher machen. Nur solange Sie nicht zwanzig Parameter eingeben müssen, um den Verarbeitungsstatus darzustellen!


7

Lange Methoden sind nicht immer schlecht. Sie sind normalerweise ein Zeichen dafür, dass möglicherweise ein Problem vorliegt.

Auf dem System, an dem ich arbeite, gibt es ungefähr ein halbes Dutzend Methoden, die mehr als 10.000 Zeilen lang sind. Eine ist derzeit 54.830 Zeilen lang. Und es ist in Ordnung.

Diese lächerlich langen Funktionen sind sehr einfach und werden automatisch generiert. Dieses große, 54.830 Zeilen lange Monster enthält die täglichen Polarbewegungsdaten vom 1. Januar 1962 bis zum 10. Januar 2012 (unsere letzte Veröffentlichung). Wir veröffentlichen auch ein Verfahren, mit dem unsere Benutzer diese automatisch generierte Datei aktualisieren können. Diese Quelldatei enthält die Polarbewegungsdaten von http://data.iers.org/products/214/14443/orig/eopc04_08_IAU2000.62-now , die automatisch in C ++ übersetzt wurden.

Das direkte Lesen dieser Website ist in einer sicheren Installation nicht möglich. Es besteht keine Verbindung zur Außenwelt. Das Herunterladen der Website als lokale Kopie und das Parsen in C ++ ist ebenfalls keine Option. Das Parsen ist langsam , und das muss schnell gehen. Herunterladen, automatische Übersetzung in C ++ und Kompilieren: Jetzt haben Sie etwas, das schnell ist. (Kompilieren Sie es einfach nicht optimiert. Es ist erstaunlich, wie lange ein optimierender Compiler benötigt, um 50.000 Zeilen extrem einfachen geraden Code zu kompilieren. Es dauert auf meinem Computer über eine halbe Stunde, um diese eine optimierte Datei zu kompilieren. Und die Optimierung bewirkt absolut nichts Es gibt nichts zu optimieren. Es ist einfacher gerader Code, eine Zuweisungsanweisung nach der anderen.)


6
"eine Zuweisungsanweisung nach der anderen" ... ich würde das eine "Datendatei" nennen. Warum ist es Code?
Joachim Sauer

3
@JoachimSauer - Da das Parsen einer großen Datendatei zur Laufzeit in einem Monte-Carlo-Setup eine schlechte Idee ist. Eine sehr, sehr schlechte Idee.
David Hammen

4
@DavidHammen: Tun Sie dies dann zur Initialisierungszeit, genau wie Sie Ihren Linker / Loader dazu zwingen. Oder schreiben Sie die Datendatei als C-Struktur in eine Header-Datei anstelle von C-Code. Zumindest würde der Loader dann als Datenblock laden.
Javier

3
@Javier: Auch zur Initialisierungszeit kann es eine sehr schlechte Idee sein, zumindest in einem Monte-Carlo-Setup. Eine Simulation, deren Initialisierung Minuten, aber nur Sekunden dauert, widerspricht der Gewohnheit, Zehntausende von Durchläufen über Nacht zu erzielen. Das Ändern der Schlüsselinitialisierungszeitaufgaben zum Kompilieren von Zeitaufgaben behebt dieses Problem. Wir haben eine Reihe von Techniken ausprobiert, einschließlich des Ansatzes der kompilierten Datenstruktur. Es funktioniert einfach nicht oder ist in einigen Fällen sehr schwierig, die Arbeit zu erledigen (z. B. ein riesiges Schwerkraftmodell). Der Straight-Line-Code-Ansatz ist einfach zu generieren und zu überprüfen. Es ist nur hässlicher Code.
David Hammen

7
+1 interessante Geschichte. generierter Code ist natürlich kein wirklicher Quellcode, daher könnte man argumentieren, dass dies nicht gegen die Regel verstößt. man nimmt an, dass der code generator selbst nette kurze methoden hatte
jk.

7

Sagen wir einfach, es gibt gute und schlechte Möglichkeiten, eine lange Methode zu beenden. "Die äußerste Methode im Kopf behalten" ist ein Zeichen dafür, dass Sie sie nicht optimal aufteilen oder dass Ihre Submethoden einen schlechten Namen haben. In der Theorie gibt es Fälle, in denen eine lange Methode besser ist. In der Praxis ist es äußerst selten. Wenn Sie nicht herausfinden können, wie Sie eine kürzere Methode lesbar machen können, lassen Sie jemanden Ihren Code überprüfen und fragen Sie ihn speziell nach Ideen zur Verkürzung der Methoden.

Bei mehreren Schleifen, die einen vermeintlichen Leistungseinbruch verursachen, ist dies ohne Messung nicht möglich. Mehrere kleinere Schleifen können erheblich schneller sein, wenn alles, was benötigt wird, im Cache verbleibt. Selbst wenn es einen Leistungseinbruch gibt, ist dieser für die Lesbarkeit in der Regel vernachlässigbar.

Ich werde sagen, dass lange Methoden oft einfacher zu schreiben sind , obwohl sie schwieriger zu lesen sind . Deshalb vermehren sie sich, obwohl sie niemand mag. Es ist nichts Falsches daran, von Anfang an bis zur Umgestaltung zu planen, bevor Sie es einchecken.


1
"Es ist nichts Falsches daran, von Anfang an bis zur Umgestaltung zu planen, bevor Sie es einchecken." +1 dafür. Die meisten IDEs verfügen heutzutage über Refactoring-Tools, die dies ebenfalls extrem einfach machen. Es gibt jedoch eine umgekehrte Methode, bei der Sie Dinge an nicht vorhandene Funktionen delegieren und später die Methoden ausfüllen, aber ich war noch nie in der Lage, auf diese Weise so viel zu codieren, wie ich versucht habe.
Tjaart

+1 für "Die äußerste Methode im Kopf behalten" ist ein Zeichen dafür, dass Sie sie nicht optimal aufteilen "
Michael Shaw

4

Lange Methoden können rechen- und platzsparender sein, die Logik besser erkennen und leichter debuggen. Diese Regeln gelten jedoch nur dann wirklich, wenn nur ein Programmierer diesen Code berührt. Der Code wird eine schmerzhafte Erweiterung sein, wenn er nicht atomar ist. Im Wesentlichen muss die nächste Person von vorne anfangen und dann das Debuggen und Testen durchführen, da sie keinen bekannten guten Code verwendet.


34
Es sind immer mindestens zwei Programmierer beteiligt: ​​"Sie" und "Sie, in drei Wochen".
Joachim Sauer

3

Es gibt etwas, was wir als funktionale Zerlegung bezeichnen, was bedeutet, dass Sie Ihre längeren Methoden nach Möglichkeit in kleinere aufteilen müssen. Wie Sie bereits erwähnt haben, handelt es sich bei Ihrer Methode um das Sortieren / Filtern. Sie sollten für diese Aufgaben separate Methoden oder Funktionen verwenden.

Genau genommen sollte sich Ihre Methode darauf konzentrieren, nur eine Aufgabe auszuführen.

Und wenn es aus irgendeinem Grund erforderlich ist, eine andere Methode aufzurufen, fahren Sie andernfalls mit der Methode fort, die Sie bereits schreiben. Aus Gründen der Lesbarkeit können Sie auch Kommentare hinzufügen. Üblicherweise verwenden Programmierer mehrzeilige Kommentare (/ ** / in C, C ++, C # und Java) für Methodenbeschreibungen und einzeilige Kommentare (// in C, C ++, C # und Java). Es gibt auch gute Dokumentationstools für eine bessere Lesbarkeit des Codes (z. B. JavaDoc ). Sie können sich auch XML-basierte Kommentare ansehen, wenn Sie ein .NET-Entwickler sind.

Schleifen wirken sich auf die Programmleistung aus und können bei nicht ordnungsgemäßer Verwendung zu einem Mehraufwand für die Anwendung führen. Die Idee ist, Ihren Algorithmus so zu gestalten, dass Sie so wenig wie möglich verschachtelte Schleifen verwenden.


Auch bekannt als "Eine Funktion sollte eine Sache tun."
Lorddev

3

Es ist vollkommen in Ordnung, lange Funktionen zu schreiben. Aber es hängt vom Kontext ab, ob Sie wirklich brauchen oder nicht. Zum Beispiel werden einige der besten Almorthms am besten ausgedrückt, wenn es ein Stück ist. Andererseits wird ein großer Prozentsatz der Routinen in objektorientierten Programmen Accessor-Routinen sein, die sehr kurz sein werden. Einige der langwierigen Verarbeitungsroutinen, die langwierige Switch-Cases aufweisen, wenn die Bedingungen über tabellengesteuerte Methoden optimiert werden können.

In Code Complete 2 gibt es eine ausgezeichnete kurze Diskussion über die Länge der Routinen.

Die theoretisch beste maximale Länge von 497 wird oft als eine oder zwei Seiten Programmliste mit 66 bis 132 Zeilen beschrieben. In modernen Programmen werden häufig extrem kurze Routinen mit ein paar längeren Routinen gemischt.

Jahrzehntelange Beweise besagen, dass Routinen dieser Länge nicht fehleranfälliger sind als kürzere Routinen. Lassen Sie Themen wie Verschachtelungstiefe, Anzahl der Variablen und andere komplexitätsbezogene Überlegungen die Länge der Routine bestimmen, anstatt eine Länge festzulegen

Seien Sie vorsichtig, wenn Sie Routinen schreiben möchten, die länger als 200 Zeilen sind. In keiner der Studien wurden geringere Kosten, geringere Fehlerraten oder beides mit größeren Routinen festgestellt, die sich durch eine Größe von mehr als 200 Zeilen auszeichnen. Bei der Übergabe von 200 Codezeilen stoßen Sie zwangsläufig an eine obere Grenze der Verständlichkeit. 536 Beschränkung an sich.


2

Eine andere Abstimmung, dass es fast immer falsch ist. Ich finde jedoch zwei grundlegende Fälle, in denen dies die richtige Antwort ist:

1) Eine Methode, die im Grunde genommen nur eine Reihe anderer Methoden aufruft und selbst keine echte Arbeit leistet. Sie haben einen Prozess, der 50 Schritte erfordert, und Sie erhalten eine Methode mit 50 Aufrufen. Es gibt normalerweise nichts zu gewinnen, wenn man versucht, das aufzubrechen.

2) Disponenten. OOP-Design hat die meisten dieser Methoden überflüssig gemacht, aber eingehende Datenquellen sind von Natur aus reine Daten und können daher nicht den OOP-Prinzipien folgen. Es ist nicht ungewöhnlich, dass der Code, der die Daten verarbeitet, eine Art Dispatcher-Routine enthält.

Ich würde auch sagen, dass man die Frage beim Umgang mit autogenerierten Sachen nicht einmal berücksichtigen sollte. Niemand versucht zu verstehen, was automatisch generierter Code tut, es ist egal, ob es für einen Menschen leicht zu verstehen ist.


1
Der 50-Schritte-Prozess kann wahrscheinlich in mehrere Gruppen zusammengefasst werden. Die Schritte 1 bis 9 sind Parameterprüfungen. Erstellen Sie daher eine neue Methode mit dem Namen Parameterprüfung. (Ich bin mir sicher, dass es einige Beispiele gibt, bei denen dies nicht möglich ist. Ich wäre daran interessiert, eines zu sehen.)
Sixtyfootersdude

@sixtyfootersdude: Klar, du könntest es auflösen. Ich habe nicht gesagt, dass es unmöglich ist, ich habe gesagt, dass man nichts gewinnen kann, wenn man es aufbricht. Während es keine 50 Schritte waren, habe ich so etwas getroffen: Eine Spielwelt erschaffen. # 1 schuf die leere Welt, # 2 schuf das Terrain und danach eine ganze Reihe von Schritten, die es auf die eine oder andere Weise massierten.
Loren Pechtel

& sixtyfootersdude: Es ist erstaunlich, wie Sie Code kennen, den Sie noch nie gesehen haben, und wie Sie ihn verbessern können.
gnasher729

2

Ich wollte das Beispiel ansprechen, das Sie gegeben haben:

Zum Beispiel habe ich einige Django-Ansichten, die ein wenig die Objekte bearbeiten, bevor sie an die Ansicht gesendet werden. Eine lange Methode sind 350 Codezeilen. Ich habe meinen Code so geschrieben, dass er sich mit den Parametern befasst - das Abfrageset wird sortiert / gefiltert, und dann werden die von meiner Abfrage zurückgegebenen Objekte nach und nach verarbeitet.

In meiner Firma ist unser größtes Projekt auf Django aufgebaut und wir haben auch Langzeitsichtfunktionen (viele sind mehr als 350 Zeilen). Ich würde behaupten, dass wir nicht so lange brauchen, und sie verletzen uns.

Diese Ansichtsfunktionen erledigen eine Menge lose verwandter Arbeiten, die in das Modell, die Hilfsklassen oder die Hilfsfunktionen extrahiert werden sollten. Außerdem werden wir Ansichten wiederverwenden, um verschiedene Dinge zu tun, die stattdessen in zusammenhängendere Ansichten unterteilt werden sollten.

Ich vermute, Ihre Ansichten haben ähnliche Eigenschaften. In meinem Fall weiß ich, dass es Probleme verursacht, und ich arbeite daran, Änderungen vorzunehmen. Wenn Sie nicht einverstanden sind, dass es Probleme verursacht, müssen Sie es nicht beheben.


2

Ich weiß nicht, ob jemand dies bereits erwähnt hat, aber einer der Gründe, warum lange Methoden schlecht sind, ist, dass sie normalerweise mehrere verschiedene Abstraktionsebenen umfassen. Sie haben Schleifenvariablen und alles Mögliche passiert. Betrachten Sie die fiktive Funktion:

function nextSlide() {
  var content = getNextSlideContent();
  hideCurrentSlide();
  var newSlide = createSlide(content);
  setNextSlide(newSlide);
  showNextSlide();
}

Wenn Sie alle Animationen, Berechnungen, Datenzugriffe usw. in dieser Funktion ausgeführt hätten, wäre das ein Durcheinander gewesen. Die nextSlide () -Funktion behält eine konsistente Abstraktionsschicht (das Folienstatus-System) bei und ignoriert andere. Dadurch wird Code lesbar.

Wenn Sie ständig kleinere Methoden ausprobieren müssen, um zu sehen, was sie tun, ist die Aufteilung der Funktion fehlgeschlagen. Nur weil der Code, den Sie lesen, keine offensichtlichen Dinge in untergeordneten Methoden ausführt, bedeutet dies nicht, dass untergeordnete Methoden eine schlechte Idee sind, nur dass sie falsch ausgeführt wurden.

Wenn ich Methoden erstelle, teile ich sie normalerweise in kleinere Methoden auf, um sie zu teilen und zu erobern. Eine Methode wie

   if (hasMoreRecords()) { ... }

ist sicher lesbarer als

if (file.isOpen() && i < recordLimit && currentRecord != null) { ... } 

Richtig?

Ich stimme zu, dass absolute Aussagen schlecht sind und dass normalerweise eine lange Methode schlecht ist.


1

Wahre Geschichte. Ich bin einmal auf eine Methode gestoßen, die mehr als zweitausend Zeilen lang war. Die Methode hatte Regionen, die beschrieben, was es in diesen Regionen tat. Nachdem ich eine Region durchgelesen hatte, entschied ich mich für eine automatisierte Extraktionsmethode, die nach dem Namen der Region benannt wurde. Als ich fertig war, bestand die Methode nur aus 40 Methodenaufrufen mit jeweils etwa fünfzig Zeilen, und es funktionierte alles gleich.

Was zu groß ist, ist subjektiv. Manchmal kann eine Methode nicht weiter aufgeschlüsselt werden als bisher. Es ist wie ein Buch zu schreiben. Die meisten Menschen sind sich einig, dass lange Absätze normalerweise geteilt werden sollten. Aber manchmal gibt es nur eine Idee, und die Aufteilung führt zu mehr Verwirrung, als dies durch die Länge dieses Absatzes verursacht würde.


0

Der Sinn einer Methode besteht darin, das Aufstoßen von Code zu reduzieren. Eine Methode sollte eine bestimmte Funktion haben, für die sie verantwortlich ist. Wenn Sie Code an zahlreichen Stellen erneut aufbereiten, besteht die Gefahr, dass Code unerwartete Ergebnisse erzielt, wenn die Spezifikationen, für die die Software entwickelt wurde, geändert werden.

Eine Methode mit 350 Zeilen würde bedeuten, dass viele der Aufgaben, die sie ausführt, an anderer Stelle repliziert werden, da es ungewöhnlich ist, so viel Code für die Ausführung einer speziellen Aufgabe zu benötigen.


Helfen Sie, Code zu reduzieren, was ?
Avner Shahar-Kashtan

@ AvnerShahar-Kashtan, er bedeutet wahrscheinlich "Vervielfältigung" :-)
Péter Török

0

Es sind nicht wirklich die langen Methoden, die schlechte Praxis sind, es ist eher schlecht, wenn man sie so belässt.

Ich meine, dass der eigentliche Akt der Umgestaltung Ihrer Probe aus:

varaible_1 = 0
variable_2 = 0
for object in queryset :
     if object.condition_condition_a and variable_2 > 0 :
     variable 1+= 1
     .....
     ...    
     . 
      more conditions to alter the variables

return queryset, and context 

zu

Status status = new Status();
status.variable1 = 0;
status.variable2 = 0;
for object in queryset :
     if object.condition_condition_a and status.variable2 > 0 :
     status.variable1 += 1
     .....
     ...    
     . 
      more conditions to alter the variables (status)

return queryset, and context 

und dann zu

class Status {
    variable1 = 0;
    variable2 = 0;

    void update(object) {
        if object.condition_condition_a and variable2 > 0 {
            variable1 += 1
        }
    }
};

Status status = new Status();
for object in queryset :
     status.update(object);
     .....
     ...    
     . 
      more conditions to alter the variables (status)

return queryset, and context 

Sie sind jetzt auf dem besten Weg, nicht nur eine viel kürzere, sondern auch eine viel benutzerfreundlichere und verständlichere Methode zu entwickeln.


0

Ich denke, die Tatsache, dass die Methode sehr lang ist, ist etwas zu überprüfen, aber definitiv kein sofortiges Anti-Pattern. Das große Ding, nach dem man in riesigen Methoden suchen muss, ist viel Schachteln. Wenn Sie haben

foreach(var x in y)
{
    //do ALL the things
    //....
}

und der Körper der Schleife ist nicht extrem lokalisiert (dh Sie könnten weniger als 4 Parameter senden), dann ist es wahrscheinlich besser, ihn zu konvertieren:

foreach(var x in y)
{
    DoAllTheThings(x);
}
...
void DoAllTheThings(object x)
{
    //do ALL the things
    //....
}

Dies kann wiederum die Länge einer Funktion erheblich reduzieren. Stellen Sie außerdem sicher, dass Sie in der Funktion nach doppeltem Code suchen und diesen in eine separate Funktion verschieben

Schließlich sind einige Methoden nur langwierig und kompliziert und es gibt nichts, was Sie tun können. Einige Probleme erfordern Lösungen, die sich nicht einfach codieren lassen. Zum Beispiel kann das Parsen gegen eine Grammatik von großer Komplexität sehr lange Methoden ergeben, an denen Sie nicht viel ändern können, ohne sie zu verschlimmern.


0

Die Wahrheit ist, es kommt darauf an. Wie bereits erwähnt, ist es ein Problem, wenn der Code die Bedenken nicht trennt und versucht, alles in einer Methode zu tun. Die Aufteilung von Code in mehrere Module erleichtert das Lesen und Schreiben von Code (durch mehrere Programmierer). Zunächst empfiehlt es sich, sich an ein Modul (eine Klasse) pro Quelldatei zu halten.

Zweitens, wenn es um Funktionen / Prozeduren geht:

void setDataValueAndCheckForRange(Data *data) {/*code*/} 

Dies ist eine gute Methode, wenn nur der Bereich "Daten" geprüft wird. Es ist eine BAD-Methode, wenn derselbe Bereich für mehrere Funktionen gilt (Beispiel für fehlerhaften Code):

void setDataValueAndCheckForRange(Data *data){ /*code */}
void addDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}
void subDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}
void mulDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}

Dies muss überarbeitet werden, um:

bool isWithinRange(Data *d){ /*code*/ }
void setDataValue(Data *d) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void addDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void subDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void mulDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 

Code so oft wie möglich wiederverwenden. Und das ist möglich, wenn jede Funktion Ihres Programms EINFACH (nicht unbedingt einfach) genug ist.

ZITAT: Der BERG besteht aus winzigen Körnern der Erde. Der Ozean besteht aus winzigen Wassertropfen. (- Sivananda)


0

Lange Methoden tendieren in imperativen Sprachen zu "schlecht", was Aussagen, Nebenwirkungen und Veränderbarkeit begünstigt, gerade weil diese Merkmale die Komplexität und damit die Fehler erhöhen.

In funktionalen Programmiersprachen, die Ausdrücke, Reinheit und Unveränderlichkeit bevorzugen, gibt es weniger Anlass zur Sorge.

In funktionalen und imperativen Sprachen ist es immer am besten, wiederverwendbare Codestücke in allgemeine Routinen der obersten Ebene zu zerlegen. In funktionalen Sprachen, die das lexikalische Scoping mit verschachtelten Funktionen usw. unterstützen, ist es jedoch besser, Unterprogramme innerhalb der obersten Ebene zu kapseln -level-Funktion (Methode), als sie in andere Funktionen der obersten Ebene aufzuteilen.


In funktionalen Sprachen sind lange Methoden jedoch viel seltener.
itsbruce
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.