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
quelle
Antworten:
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.
quelle
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.
quelle
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.Lange Methoden sind immer schlecht, aber manchmal besser als die Alternativen.
quelle
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!
quelle
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.)
quelle
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.
quelle
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.
quelle
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.
quelle
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.
quelle
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.
quelle
Ich wollte das Beispiel ansprechen, das Sie gegeben haben:
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.
quelle
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:
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
ist sicher lesbarer als
Richtig?
Ich stimme zu, dass absolute Aussagen schlecht sind und dass normalerweise eine lange Methode schlecht ist.
quelle
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.
quelle
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.
quelle
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:
zu
und dann zu
Sie sind jetzt auf dem besten Weg, nicht nur eine viel kürzere, sondern auch eine viel benutzerfreundlichere und verständlichere Methode zu entwickeln.
quelle
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
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:
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.
quelle
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:
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):
Dies muss überarbeitet werden, um:
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)
quelle
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.
quelle