Nur Ästetik oder mehr?

Status
Nicht offen für weitere Antworten.

voidee

Mitglied
Hi,

mal wieder ein philospohisches Problem. Oft hat man - naja, wenigstens bei mir ist es so - dass:

Code:
boolean aFunction() {
 
  boolean l_return = false;

  if ( <Bedingung>) {
    // einzeiliger oder zweizeiliger Code
    return l_return;
  }
  else {
    // hier folgen jetzt viele, viele Zeilen Code
    ...
  }
  
  return l_return;
} // -- eof aFunction() -- //

soll ich den else-Block weglassen, ist ja eh obsolet. Oder macht der else-Block irgendeinen Sinn? Oder gibt es für den einen oder anderen Weg das zu kodieren noch weitere Argumente?

Ich bin da hin- und hergerissen. Logisch ist es ein if-else Konstrukt. Programmtechnisch müsste man es aber so nicht umsetzen. Ode soll die "Lange" Bedingung nach vorne, und die "kleinere" in den else-Block. Dann aber, finde ich, übersieht man das else eher mal.

Gruß
Tom
 
Weil ich ein sehr fauler Mensch bin, lass ich es immer weg.

Ich finde es auch sehr aufgeräumt wenn zuerst Abbruchbedingungen stehen, möglicherweise Exceptions die geworfen werden und danach die eigentliche Funktionalität.
 
Na, wenn ich doch vorher feststellen kann, das ich den ganzen Aufwand nicht treiben muss, weil ich einfach abbrechen kann ... (mit einer Exception oder einem Standardwert)
 
wenn sehr viele zeilen code folgen (mehr als auf eine 'seite' passt), dann halte ich es aber für schöner, wenn der eigentliche code in eine extra funktion ausgelagert wird, die frei ist von prüfung von vorbedingungen.
 
Ja, ist wohl hauptsächlich Geschmacksache. IMHO ist hauptsächlich wichtig, dass das ganze richtig kommentiert ist - einschließlich solcher "Kleinigkeiten" wie mindestens einer Leerzeile zwischen dem "early return" und dem Rest... da braucht man ggf. nichtmal die Variable für den Returnwert
Code:
/**
 * This function does [this-and-that] if [conditions]
 * otherwise, it does [whatever]
 *
 * @return ...
 * @throws ...
 */
boolean doSomething()
{
    // First check the [conditions]. If they are NOT met, do [whatever]
    if (!conditionsAreMet())
    {
        doWhatever();
        return false;
    }

    // Now, all [conditions] are verified. Do [this-and-that]
    doThisAndThat();
    return true;
}
 
Ich halte es zwar nicht ganz durch, versuche aber, die Anzahl der returns zu minimieren, auch wenn man ein paar Zeilen mehr braucht:
Code:
boolean doSomething() {
    boolean result = false;
    // First check the [conditions]. If they are NOT met, do [whatever]
    if (!conditionsAreMet())
    {
        doWhatever();
        result = false;
    } else {

      // Now, all [conditions] are verified. Do [this-and-that]
      doThisAndThat();
       result = true; 
    }
    return result;
}
Der Grund ist, dass man sonst versehentlich etwas hinter die if-Anweisung schreibt, das in *allen* Fällen abgearbeitet werden muss, und übersieht, dass weiter oben schon ein "Ausgang" ist. Natürlich ist das nicht hübsch, aber man vermeidet Fehler und bekommt einen sanften Schubs, zu langen Methoden zwei Untermethoden (für den Test und die eigentliche Arbeit) zu spendieren.
 
Ich finde das mit mehreren Methoden nicht gut. Wenn es SEHR viel Code ist, steckt man das
in eine eigene Klasse. Aber nicht eine Klasse zumüllen mit tausend Teil-Methoden, man sieht da auf den
ersten Blick gar nicht mehr, welche Funktionalität diese Klasse eigentlich anbietet.

Wenn man ordentlich kommentiert und den Code für das Auge sauber trennt (zwischen Abbruch-Bedingung
und dem auszuführenden Code), dann passt das und ist mmN viel besser als wenn man jetzt hin und her
springen muss wenn man die Logik einer Methode nachvollziehen will.

Natürlich sind Methoden die öfters gebraucht werden (zB Hilfsmethoden) eine Ausnahme.
 
sobald etwas mehr als einmal benötigt wird, kann man sie bedenkenlos in eine methode auslagern. dabei sollte man auch nicht davor zurückschrecken, 'simple' berechnungen, die lediglich in einer zeile mit ein paar variablen jonglieren, einfach mal in eine methode auszulagern.

viele methoden werden erst dann unübersichtlich, wenn sie schlechte bezeichner haben, oder mehr erledigen, als nötig wäre.

wenn man funktionalität immer schön auslagert und die methoden sehr kurz hält, hat man auch automatisch den vorteil spendiert bekommen, zu erkennen, ab wann sich neue klassen lohnen. es mag auf den ersten blick verlockend erscheinen, einfach alles in 500 zeilen runterzuschreiben, aber solcher code wird irgendwann - meist schneller, als man denkt - schlecht wartbar.

daher code ruhig extrem modular halten.
 
Ganz nebenbei: Mir ist immer noch schleierhaft, warum Java das erlaubt:
Code:
public void f() {
   class F{
      F(){
          System.out.println("lokale Klasse"); 
      }
   }
   new F();
}
und das nicht:
Code:
public void f() {
    void g() {
          System.out.println("Hurra!"); 
    }
    g(); g(); g();
}
Letzteres wäre viel nützlicher, oder habt ihr schonmal eine lokale Klasse gebraucht? Mit lokalen Methoden ließen sich größere Methoden hübsch sauber zerlegen, ohne den Namensraum vollzumüllen...
 
Naja mit Closures in Java 7 (so sie denn kommen) kannst du vermutlich auch sowas bauen. Schön find ich allerdings nichts davon.

Lokale Klassen hab ich übrigens schon hin und wieder verwendet, an Stellen wo ich normalerweise eine anonyme Klasse verwendet hätte, aber die Klasse mehrfach verwenden musste.

In letzter Zeit versuche ich allerdings, sowas zu vermeiden - außer in irgendwelchen kurz dahingehackten Sächelchen.
 
Closures werden allen Anschein nach nicht mit Java7 kommen, obwohl es ja bereits funktionierende Implementierungen für verschiedene Vorschläge gibt.

Damit gerät Java endgültig ins Hintertreffen - die restlichen Änderungen sind im Verhältnis zu Closures so wichtig wie varargs verglichen mit Generics, nämlich nahe null.

Die Sprache hat durchaus noch Schwung, sicher: Ungefähr so, wie ein heranstürmendes Nashorn, dass man im vollen Lauf abgeschossen hat. Zeit, sich neue Gefilde zu suchen...

Übrigens: Lokale Klassen habe ich bisher nur einmal verwendet, nämlich als Key für eine HashMap. Und auch da hätte ich sie nicht gebraucht, wenn Java eine ordentliche Tupel-Implementierung mitbringen würde.
 
Landei hat gesagt.:
Ich halte es zwar nicht ganz durch, versuche aber, die Anzahl der returns zu minimieren, auch wenn man ein paar Zeilen mehr braucht:
Code:
boolean doSomething() {
    boolean result = false;
    // First check the [conditions]. If they are NOT met, do [whatever]
    if (!conditionsAreMet())
    {
        doWhatever();
        result = false;
    } else {

      // Now, all [conditions] are verified. Do [this-and-that]
      doThisAndThat();
       result = true; 
    }
    return result;
}
Solchen Code mag ich gar nicht, weil er spätere schwerer lesbar ist. Bei einem direkten Return weiss ich genau, wann der Workflow der Methode endet. Bei Deiner Variante muss ich immer die gesamte Methode lesen. Das dauert nicht nur länger, sondern ist häufig auch anstrengender, denn bei der Fehlersuche interessiert häufig nur ein ganz bestimmter Fall.

So schreibe ich es:
Code:
boolean doSomething() {
    if (!conditionsAreMet()) {
        doWhatever();
        return false;
    }

    doThisAndThat();
    return true;
}
Das Else ist unnötig. Weniger Blöcke = besser lesbar imo.

PS: Die Kommentare oben sind imo teilweise unnötig. First check the conditions sagt mir nichts anderes, als der Code eine Zeile darunter.
 
Bei solchen einfachen Beispielen mag es noch gehen, aber ich bin schon ein paarmal auf die Nase gefallen, weil ich ein return weiter oben in der Methode übersehen habe - insbesondere dann, wenn ich in fremden Code rumwurschteln musste. Natürlich sieht meine Lösung bei einem 5-Zeilen-Beispiel übertrieben aus, aber wenn du mal in zweihundert-Zeilen-Methoden (die oft so geschrieben sind, dass sie sich auch ja nicht zerlegen lassen) mit zehn returns arbeiten durftest, kommst du bestimmt auch ins Grübeln...
 
Muss mich auch häufig mit solchen Monolithen rumärgern. Aber grade da finde ich direkte Returns schöner. Wenn ich eine Methode lese und sie returnt in einem Zweig, dann brauche ich die restlichen 500 Zeilen gar nicht mehr angucken. Wenn da nur ein result = blub; steht, dann muss ich alles lesen, bis irgendwann mal das return result; steht. Das finde ich extrem lästig und zeitraubend.
 
Bei Eclipse zumindest kann man dem Schlüsselwort "return" einen eigenen Stil im Syntax-Highlighter zuweisen. Wenn du es fett und leuchtend rot machst, wirst du es auch in (zweifelhaften) 200-Zeilen-Monster nicht mehr übersehen.
 
byto hat gesagt.:
PS: Die Kommentare oben sind imo teilweise unnötig. First check the conditions sagt mir nichts anderes, als der Code eine Zeile darunter.

Das waren natürlich "Platzhalter" (genauso wie die Sachen in den [Klammern]) - und zwar für Erläuterungen, die über das hinausgehen, was schon als code dasteht :wink:
 
didjitalist hat gesagt.:
wenn sehr viele zeilen code folgen (mehr als auf eine 'seite' passt), dann halte ich es aber für schöner, wenn der eigentliche code in eine extra funktion ausgelagert wird, die frei ist von prüfung von vorbedingungen.
da hab ich eine andere Philospie: wenn vor der eigentlichen Funktionsausführung auf fehlerhafte Parameter oder aus klasseninternen Gründen Abbruchkonstellationen bestehen, dann gehört das meines Erachtens auch in diese Funktion.
Wenn ich mir, deiner Idee folgend, irgendwann später die Funktion mal nähers betrachte, werde ich feststellen, dass sie potenziell Buggy ist, weil bestimmte Konstellationen nicht beachtet sind. Dass dies eventuell in einer vorgelagerten Funktion erfolgt, kann ich dann nicht sehen (und will ehrlich gesagt auch nicht allen Funktionen nachjagen, die eventuell diese reine funktionale Funktion aufrufen).

byto hat gesagt.:
Wenn ich eine Methode lese und sie returnt in einem Zweig, dann brauche ich die restlichen 500 Zeilen gar nicht mehr angucken. Wenn da nur ein result = blub; steht, dann muss ich alles lesen, bis irgendwann mal das return result; steht. Das finde ich extrem lästig und zeitraubend.
Dem kann ich mich eigentlich anschliessen.
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Zurück
Oben