it-swarm-eu.dev

Kann eine Funktion zu kurz sein?

Immer wenn ich die gleiche Logik mehr als einmal schreibe, stecke ich sie normalerweise in eine Funktion, sodass es nur einen Ort in meiner Anwendung gibt, an dem ich diese Logik beibehalten muss. Ein Nebeneffekt ist, dass ich manchmal ein oder zwei Zeilenfunktionen habe, wie zum Beispiel:

function conditionMet(){
   return x == condition;
}

OR

function runCallback(callback){
   if($.isFunction(callback))
     callback();
}

Ist das faul oder eine schlechte Praxis? Ich frage nur, weil dies zu einer größeren Anzahl von Funktionsaufrufen führt, die sehr kleine logische Teile erfordern.

128
Mark Brown

Hehe, oh Mr. Brown, wenn ich nur alle Entwickler, die ich treffe, davon überzeugen könnte, ihre Funktionen so klein wie möglich zu halten, glauben Sie mir, die Software-Welt wäre ein besserer Ort!

1) Ihre Lesbarkeit des Codes verzehnfacht sich.

2) Aufgrund der Lesbarkeit ist es so einfach, den Prozess Ihres Codes herauszufinden.

3) DRY - Wiederholen Sie sich nicht - Sie passen sich dem sehr gut an!

4) Testbar. Winzige Funktionen sind millionenfach einfacher zu testen als die 200-Zeilen-Methoden, die wir viel zu oft sehen.

Oh und mach dir keine Sorgen über "Funktionssprung" in Bezug auf die Leistung. "Release" Builds und Compiler-Optimierungen kümmern sich für uns sehr gut darum, und die Leistung ist 99% der Zeit irgendwo anders im Systemdesign.

Ist das faul? - Im Gegenteil!

Ist das eine schlechte Praxis? - Absolut nicht. Es ist besser, diese Art der Herstellung von Methoden anzuwenden als die Teerbälle oder "Gottobjekte", die ach so zu häufig sind.

Mach weiter so, mein Handwerkskollege;)

166
Martin Blore

Ich würde sagen, dass eine überarbeitete Methode zu kurz ist, wenn:

  • Es dupliziert eine primitive Operation, und zwar zu keinem anderen Zweck, als sie zu einer Methode zu machen:

Ex:

boolean isNotValue() {
   return !isValue();
}

oder...

  • Der Code wird nur einmal verwendet und seine Absicht ist auf einen Blick leicht zu verstehen.

Ex:

void showDialog() {
    Dialog singleUseDialog = new ModalDialog();
    configureDialog(singleUseDialog);
    singleUseDialog.show();
}

void configureDialog(Dialog singleUseDialog) {
    singleUseDialog.setDimensions(400, 300);
}

Dies könnte ein gültiges Muster sein, aber ich würde in diesem Beispiel nur die Methode configureDialog () einbinden, es sei denn, ich wollte es überschreiben oder diesen Code an anderer Stelle wiederverwenden.

64
RMorrisey

Kann eine Funktion zu kurz sein? Im Allgemeinen nein.

In der Tat der einzige Weg, um sicherzustellen, dass:

  1. Sie haben alle Klassen in Ihrem Design gefunden
  2. Ihre Funktionen tun nur eines.

Ist es, Ihre Funktionen so klein wie möglich zu halten. Oder mit anderen Worten, extrahieren Sie Funktionen aus Ihren Funktionen, bis Sie nicht mehr extrahieren können. Ich nenne das "Extrahieren bis zum Umfallen".

Um dies zu erklären: Eine Funktion ist ein Bereich mit Funktionsblöcken, die über Variablen kommunizieren. Eine Klasse ist auch ein Bereich mit Funktionsblöcken, die über Variablen kommunizieren. Eine lange Funktion kann also immer durch eine oder mehrere Klassen mit kleiner Methode ersetzt werden.

Eine Funktion, die groß genug ist, um eine andere Funktion daraus zu extrahieren, führt mehr als eine Sache aus per Definition. Wenn Sie also können eine Funktion aus einer anderen extrahieren, sollten diese Funktion extrahieren.

Einige Leute befürchten, dass dies zu einer Verbreitung von Funktionen führen wird. Sie haben recht. Es wird. Das ist eigentlich eine gute Sache. Es ist gut, weil Funktionen Namen haben. Wenn Sie bei der Auswahl guter Namen vorsichtig sind, fungieren diese Funktionen als Wegweiser, die andere Personen durch Ihren Code leiten. In der Tat sind gut benannte Funktionen in gut benannten Klassen in gut benannten Namespaces eine der besten Möglichkeiten, um sicherzustellen, dass Ihre Leser NICHT verloren gehen.

In Episode III von Clean Code auf cleancoders.com gibt es noch viel mehr darüber

59
Uncle Bob.

Wow, die meisten dieser Antworten sind überhaupt nicht sehr hilfreich.

Es sollte keine Funktion geschrieben werden, deren Identität ihre Definition ist . Das heißt, wenn der Funktionsname einfach der in Englisch geschriebene Codeblock der Funktion ist, schreiben Sie ihn nicht als Funktion.

Betrachten Sie Ihre Funktion conditionMet und diese andere Funktion addOne (verzeihen Sie mir mein rostiges JavaScript):

function conditionMet() { return x == condition; }

function addOne(x) { return x + 1; }

conditionMet ist eine korrekte konzeptionelle Definition; addOne ist ein Tautologie . conditionMet ist gut, weil Sie nicht wissen, was conditionMet bedeutet, indem Sie einfach "Bedingung erfüllt" sagen, aber Sie können sehen, warum addOne dumm ist, wenn Sie es auf Englisch vorlesen ::

"For the condition to be met is for x to equal condition" <-- explanatory! meaningful! useful!

"To add one to x is to take x and add one." <-- wtf!

Schreiben Sie aus Liebe zu allem, was noch heilig sein könnte, keine tautologischen Funktionen!

(Und aus dem gleichen Grund schreibe nicht für jede Codezeile Kommentare !)

53
Rei Miyasaka

Ich würde sagen, wenn Sie der Meinung sind, dass die Absicht eines Codes durch Hinzufügen eines Kommentars verbessert werden kann, extrahieren Sie den Code in eine eigene Methode, anstatt diesen Kommentar hinzuzufügen. Egal wie klein der Code war.

Zum Beispiel, wenn Ihr Code so aussehen würde:

if x == 1 { ... } // is pixel on?

lass es stattdessen so aussehen:

if pixelOn() { ... }

mit

function pixelOn() { return x == 1; }

Mit anderen Worten, es geht nicht um die Länge der Methode, sondern um selbstdokumentierenden Code.

14
Julio

Ich denke, genau das wollen Sie tun. Im Moment besteht diese Funktion möglicherweise nur aus ein oder zwei Zeilen, aber im Laufe der Zeit kann sie wachsen. Wenn Sie mehr Funktionsaufrufe haben, können Sie die Funktionsaufrufe lesen und verstehen, was dort vor sich geht. Dies macht Ihren Code sehr DRY (Wiederholen Sie sich nicht) , was viel wartbarer ist.

7
mpenrow

Ich stimme allen anderen Posts zu, die ich gesehen habe. Das ist guter Stil.

Der Overhead einer so kleinen Methode kann gleich Null sein, da der Optimierer den Anruf weg optimieren und den Code einbinden kann. Einfacher Code wie dieser ermöglicht es dem Optimierer, seine beste Arbeit zu leisten.

Der Code sollte aus Gründen der Klarheit und Einfachheit geschrieben werden. Ich versuche, eine Methode auf eine von zwei Rollen zu beschränken: Entscheidungen treffen; oder Arbeit ausführen. Dies kann einzeilige Methoden erzeugen. Je besser ich das kann, desto besser finde ich meinen Code.

Code wie dieser weist tendenziell eine hohe Kohäsion und eine niedrige Kopplung auf, was eine gute Codierungspraxis ist.

EDIT: Ein Hinweis zu Methodennamen. Verwenden Sie einen Methodennamen, der angibt, was die Methode nicht wie sie tut. Ich finde, verb_noun (_modifier) ​​ist ein gutes Namensschema. Dies gibt Namen wie Find_Customer_ByName anstelle von Select_Customer_Using_NameIdx. Der zweite Fall kann fehlerhaft werden, wenn die Methode geändert wird. Im ersten Fall können Sie die gesamte Implementierung der Kundendatenbank austauschen.

5
BillThor

Das Umgestalten einer Codezeile in eine Funktion scheint übertrieben. Es kann Ausnahmefälle geben, wie z. B. ver loooooong/comples Zeilen oder Expessionen, aber ich würde dies nicht tun, es sei denn, ich weiß die Funktion wird in Zukunft wachsen.

und Ihr erstes Beispiel weist auf die Verwendung von Globals hin (die möglicherweise von anderen Problemen im Code sprechen oder nicht). Ich würde es weiter überarbeiten und diese beiden Variablen als Parameter festlegen:

function conditionMet(x, condition){
   return x == condition;
}
....
conditionMet(1,(3-2));
conditionMet("abc","abc");

Das Beispiel conditionMetkönnte ist nützlich, wenn die Bedingung lang und sich wiederholend war, wie z.

function conditionMet(x, someObject){
   return x == ((someObject.valA + someObject.valB - 15.4) / /*...whole bunch of other stuff...*/);
}

Bedenken Sie:

Eine einfache Kollisionserkennungsfunktion:

bool collide(OBJ a, OBJ b)
{
    return(pow(a.x - b.x, 2) + pow(a.y - b.y, 2) <= pow(a.radius + b.radius, 2));
}

Wenn Sie diesen "einfachen" Liner die ganze Zeit in Ihren Code geschrieben haben, könnten Sie irgendwann einen Fehler machen. Außerdem wäre es wirklich qualvoll, das immer und immer wieder zu schreiben.

3
Mateen Ulhaq

Ich würde sagen, dass sie zu kurz sind, aber das ist meine subjektive Meinung.

Weil:

  • Es gibt keinen Grund, eine Funktion zu erstellen, wenn sie nur ein- oder zweimal verwendet wird. Springen zu defs saugen. Besonders mit erstaunlich schnellem VS- und C++ - Code.
  • Klassenübersicht. Wenn Sie Tausende kleiner Funktionen haben, macht mich das wütend. Ich genieße es, wenn ich Klassendefinitionen anzeigen und schnell sehen kann, was es tut, nicht wie es SetXToOne, SetYToVector3, MultiplyNumbers, + 100 Setter/Getter.
  • In den meisten Projekten werden diese Helfer nach einer oder zwei Refactoring-Phasen tot, und dann führen Sie "Alle durchsuchen" -> Löschen aus, um veralteten Code zu entfernen, normalerweise ~ 25% + davon.

Lange Funktionen sind schlecht, aber Funktionen, die kürzer als 3 Zeilen sind und nur eine Funktion ausführen, sind meiner Meinung nach genauso schlecht.

Also würde ich sagen, schreibe nur eine kleine Funktion, wenn es ist:

  • 3+ Codezeilen
  • Tut Sachen, die Junior-Entwickler vermissen könnten (nicht wissen)
  • Führt eine zusätzliche Validierung durch
  • Wird verwendet oder wird mindestens 3x verwendet
  • Vereinfacht die häufig verwendete Schnittstelle
  • Wird beim nächsten Refactoring nicht zum Eigengewicht
  • Hat eine besondere Bedeutung, zum Beispiel Vorlagenspezialisierung oder so
  • Führt einige Isolationsjobs durch - const-Referenzen, wirkt sich auf veränderbare Parameter aus und ruft private Mitglieder ab

Ich wette, der nächste Entwickler (Senior) hat bessere Dinge zu tun, als sich an alle Ihre SetXToOne-Funktionen zu erinnern. So oder so werden sie ziemlich bald totes Gewicht.

2
Coder

Nein, und das ist selten ein Problem. Wenn jemand der Meinung ist, dass keine Funktion länger als eine Codezeile sein sollte (wenn es nur so einfach sein könnte), wäre dies ein Problem und in gewisser Weise faul, weil er nicht darüber nachdenkt, was angemessen ist.

2
JeffO

Ich mag das Beispiel Nr. Nicht. 1, wegen des i-ten Gattungsnamens.

conditionMet scheint nicht generisch zu sein, steht also für eine bestimmte Bedingung? Mögen

isAdult () = { 
  age >= 18 
}

Das wäre in Ordnung. Es ist ein semantischer Unterschied

isAtLeast18 () { age >= 18; } 

wäre nicht gut für mich.

Vielleicht wird es oft verwendet und kann später geändert werden:

getPreferredIcecream () { return List ("banana", "choclate", "Vanilla", "walnut") }

ist auch in Ordnung. Wenn Sie es mehrmals verwenden, müssen Sie nur einen einzigen Ort wechseln, wenn Sie müssen - vielleicht wird Schlagsahne morgen möglich.

isXYZ (Foo foo) { foo.x > 15 && foo.y < foo.x * 2 }

ist nicht atomar und sollte Ihnen eine schöne Testmöglichkeit geben.

Wenn Sie eine Funktion übergeben müssen, übergeben Sie natürlich, was Sie möchten, und schreiben Sie ansonsten albern aussehende Funktionen.

Aber im Allgemeinen sehe ich viel mehr Funktionen, die zu lang sind, als Funktionen, die zu kurz sind.

Ein letztes Wort: Einige Funktionen sehen nur angemessen aus, weil sie zu ausführlich geschrieben sind:

function lessThan (a, b) {
  if (a < b) return true else return false; 
}

Wenn Sie sehen, dass es das gleiche ist wie

return (a < b); 

sie werden kein Problem damit haben

localLessThan = (a < b); 

anstatt

localLessThan = lessThan (a, b); 
1
user unknown

Es gibt keinen Code wie keinen Code!

Halten Sie es einfach und komplizieren Sie die Dinge nicht zu kompliziert.

Es ist nicht faul, es macht deinen Job!

0
RDL

Zu kurz ist nie ein Problem. Einige Gründe für kurze Funktionen sind:

Wiederverwendbarkeit

Z.B. Wenn Sie eine Funktion wie eine Set-Methode haben, können Sie diese bestätigen, um sicherzustellen, dass die Parameter gültig sind. Diese Überprüfung muss überall dort durchgeführt werden, wo die Variable gesetzt ist.

Wartbarkeit

Sie könnten eine Aussage verwenden, von der Sie glauben, dass sie sich in Zukunft ändern könnte. Z.B. Sie zeigen jetzt ein Symbol in einer Spalte an, aber später kann sich dies in etwas anderes (oder sogar einen Piepton) ändern.

Einheitlichkeit

Sie verwenden z. Das Fassadenmuster und das einzige, was eine Funktion tut, ist, die Funktion genau an eine andere zu übergeben, ohne die Argumente zu ändern.

0
Michel Keijzers

Wenn Sie einem Codeabschnitt einen Namen geben, dient dies im Wesentlichen dazu, ihm einen Namen zu geben. Dies kann verschiedene Gründe haben, aber der entscheidende Punkt ist, ob Sie ihm einen aussagekräftigen Namen geben können, der Ihrem Programm hinzugefügt wird. Namen wie "addOneToCounter" würden nichts hinzufügen, aber conditionMet() würde.

Wenn Sie eine Regel benötigen, um herauszufinden, ob das Snippet zu kurz oder zu lang ist, überlegen Sie, wie lange Sie brauchen, um einen aussagekräftigen Namen für das Snippet zu finden. Wenn Sie nicht innerhalb einer angemessenen Zeitspanne können, hat das Snippet keine geeignete Größe.

0
user1249

Ja, es ist in Ordnung, eine Funktionscodefunktion zu haben. Bei Methoden wie "Getter", "Setter", "Accesors" ist dies sehr häufig, wie in den vorherigen Antworten erwähnt.

Manchmal sind diese kurzen "Zugriffs" -Funktionen virtuell, da die Funktionen beim Überschreiben in Unterklassen mehr Code enthalten.

Wenn Sie möchten, dass Ihre Funktion nicht so kurz ist, verwende ich in vielen Funktionen, ob global oder methodisch, normalerweise eine "Ergebnis" -Variable (Pascal-Stil) anstelle einer direkten Rückgabe. Dies ist sehr hilfreich, wenn Sie einen Debugger verwenden.

function int CalculateSomething() {
  int Result = -1;

   // more code, maybe, maybe not

  return Result;
}
0
umlcat

Nein, aber es kann zu knapp sein.

Denken Sie daran: Code wird einmal geschrieben, aber oft gelesen.

Schreiben Sie keinen Code für den Compiler. Schreiben Sie es für zukünftige Entwickler, die Ihren Code pflegen müssen.

0
Jim G.