1UnitedPower: Blocks zur Quelltext-Strukturierung

Meine Herren,

ein eher unbekanntes und selten genutztes Feature von Javascript sind standalone-blocks, also Code-Blöcke umschlossen von geschweiften Klammern, die nicht zu einer Kontrollstruktur oder Funktion gehören. Wie ich finde, praktischer Weise, lassen sich Blocks mit labeln benennen. Ich finde damit lässt sich Quelltext recht schön strukturieren, ein Beispiel:

function foo ( options ) {  
   validateParameters : {  
  
      console.log("I'm a block! I will take care of your parameters");  
  
   }  
  
   doOtherStuff : {  
  
      console.log("I'm a block, too! And i'm doing stuff, that is completly unrelated to parameter-validation!");  
      break doOtherStuff;  
      console.log("This line will never be executed!");  
  
   }  
}

Gibt es irgendwelche Gründe die dagegensprechen Blöcke zur Quelltext-Strukturierung einzusetzen?

  1. Moin Moin!

    Gibt es irgendwelche Gründe die dagegensprechen Blöcke zur Quelltext-Strukturierung einzusetzen?

    * Tippaufwand! ;-)
    * Optisch sehr ähnlich zu einer normalen Methodendeklaration oder auch zu einem Stückchen JSON.
    * Wenn Du den Code einer Funktion / Methode mit solchen Krücken struktuieren mußt, ist sie zu lang und sollte in kleinere Funktionen / Methoden zerlegt werden. Spätestens die Vergabe von Namen zeigt, dass Du eigentlich kleinere, eigenständige Funktionen / Methoden haben willst.

    Ob Du die Pseudo-Strukturen mit sinnlosen Labels und anonymen Blöcken baust oder stumpf mit Kommentarzeilen voll Line Noise, macht keinen Unterschied. Letztere schmeißt schon der Precompiler bzw. Parser raus, erstere macht so ziemlich jeder Optimizer im Compiler platt. Und beides ist IMHO falsch:

    Ich habe im Studium noch gelernt, dass eine Funktion nicht länger als eine Bildschirmseite sein soll, wobei Bildschirm ein VT420 im VT100-Modus meint, also 25 Zeilen à 80 Zeichen, minus zwei oder drei Zeilen, die Editor und Terminal selbst brauchen.

    Und ja, die Diskussionen, wie groß eine Bildschirmseite ist, ist wesentlich älter als mein Diplom.

    Einige Hardcore-Profs waren der Meinung, dass ein Kommentar mit Dokumentationscharacter (POD für die alten Hasen, Javadoc für die Frischlinge) Bestandteil dieser 25 Zeilen ist. Die Daumenregel für Dokumentation besagt, dass die mindestens etwa doppelt so lang wie der Code ist, bleiben also etwa 14 Zeilen Doku und 7 bis 8 Zeilen Code pro Funktion. (Relaxtere Profs haben ein Doku-Code-Verhältnis von etwa 1:1 akzeptiert, sehr relaxte Lab-Ings haben auch mal Funktionen erlaubt, die die 80x25 Zeichen maximal ausgereizt haben.)

    Das kann ich heute auch nur jedem raten. Nicht als einbetonierte Regel, die zu solchem Code führt:

      
    function Spaghetti_Part1(...)  
    {  
      // 20 Zeilen Code  
      return Spaghetti_Part2(...)  
    }  
      
    function Spaghetti_Part2(...)  
    {  
      // 20 Zeilen Code  
      return Spaghetti_Part3(...)  
    }  
      
    function Spaghetti_Part3(...)  
    {  
      // 20 Zeilen Code  
      return Spaghetti_Part4(...)  
    }  
      
    function Spaghetti_Part4(...)  
    {  
      // 20 Zeilen Code  
      return Spaghetti_Part5(...)  
    }  
      
    // usw. bis  
      
    function Spaghetti_Part997(...)  
    {  
      // 10 Zeilen Code  
      return 42;  
    }  
    
    

    Sondern als Richtschnur. Regeln kann man brechen. Man muß nur wissen, wann man sich an die Regeln hält (so oft wie möglich), und wann man sie ignoriert (selten, wenn nötig).

    Eine andere Daumenregel: Eine Funktion oder Methode sollte immer nur einen einzigen logischen Schritt erledigen. Die "innersten" Funktionen bestehen dann teilweise nur aus zwei oder drei Zeilen Code, die nächste Schicht darüber ruft im wesentlichen die innerste Schicht auf, die Schicht darüber die Funktionen aus der Schicht darunter, und so weiter, bis zum Hauptprogramm.

    Winzige Funktionen, bei denen für den Aufruf mehr Assembler-Code generiert wird als letztendlich im Funktionskörper steht, darf der geneigte Coder als inline deklarieren, wobei moderne Compiler das mit geeigneten Optimierungsflags auch schon automatisch können.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
    1. Meine Herren,

      erstmal Danke für die ausführliche Antwort!

      Gibt es irgendwelche Gründe die dagegensprechen Blöcke zur Quelltext-Strukturierung einzusetzen?

      * Tippaufwand! ;-)

      Ich bin nicht tippfaul und du offenbar auch nicht ;)

      * Optisch sehr ähnlich zu einer normalen Methodendeklaration oder auch zu einem Stückchen JSON.

      Das ist in der Tat bedenklich.

      * Wenn Du den Code einer Funktion / Methode mit solchen Krücken struktuieren mußt, ist sie zu lang und sollte in kleinere Funktionen / Methoden zerlegt werden. Spätestens die Vergabe von Namen zeigt, dass Du eigentlich kleinere, eigenständige Funktionen / Methoden haben willst.

      Meh, Funktionen sind doch vor allem dann sinnvoll, wenn man dadurch Wiederverwendbarkeit erzielen kann, nicht wenn ich irgendwas benennen kann.

      Ob Du die Pseudo-Strukturen mit sinnlosen Labels und anonymen Blöcken baust oder stumpf mit Kommentarzeilen voll Line Noise, macht keinen Unterschied. Letztere schmeißt schon der Precompiler bzw. Parser raus, erstere macht so ziemlich jeder Optimizer im Compiler platt.

      Mir geht es in erster Linie auch nicht um Performanz, davon bin ich lange Weg. Jeder kann für einen Computer programmieren, gute Programmierer programmieren für Programmierer.

      Und beides ist IMHO falsch:

      Ich habe im Studium noch gelernt, dass eine Funktion nicht länger als eine Bildschirmseite sein soll, wobei Bildschirm ein VT420 im VT100-Modus meint, also 25 Zeilen à 80 Zeichen, minus zwei oder drei Zeilen, die Editor und Terminal selbst brauchen.

      Naja, die Bildschirme sind ja ein Zeuge dafür aus welcher Zeit diese "Best Practices" stammen. Ich sehe in solchen Aussagen keinen akademischen wert. Codezeilen halte ich sogar für ein ausgesprochen schlechtes Qualitätsmerkmal für Quelltexte. Usability und Reusability sind die beiden Faktoren, die ich für relevant bei der Qualitätsanalyse halte. Ein großes Thema dabei ist die richtige Stufe der Abstraktion ausfindig zu machen und eben nicht immer alles bis auf die kleinste Funktion runterzubrechen. Das mag dann zu einer Komponente mit unglaublicher Reusability führen, die Usability läuft aber von unten gegen 0.

      Einige Hardcore-Profs waren der Meinung, dass ein Kommentar mit Dokumentationscharacter (POD für die alten Hasen, Javadoc für die Frischlinge) Bestandteil dieser 25 Zeilen ist. Die Daumenregel für Dokumentation besagt, dass die mindestens etwa doppelt so lang wie der Code ist, bleiben also etwa 14 Zeilen Doku und 7 bis 8 Zeilen Code pro Funktion. (Relaxtere Profs haben ein Doku-Code-Verhältnis von etwa 1:1 akzeptiert, sehr relaxte Lab-Ings haben auch mal Funktionen erlaubt, die die 80x25 Zeichen maximal ausgereizt haben.)

      Wie gesagt mit dem Gedanken, Codezeilen oder Zeichen als Qualitätsmerkmal heranzuziehen kann ich nichts anfangen. Mal ein Beispiel: Wenn ich JSDoc-Syntax verwende, um spzeifizierende Kommentare zu machen, sind die 14 Zeilen Doku schnell erschöpft, Kommentare zu Implementations-Details sind da noch garnicht drin.

      Eine andere Daumenregel: Eine Funktion oder Methode sollte immer nur einen einzigen logischen Schritt erledigen.

      Das passt mir schon eher in den Kram. Wobei "ein logischer Schritt" ein dehnbarer Begriff ist ;)

      --
      Hey Girl,
      i wish you were asynchronous, so you'd give me a callback.
      1. Moin Moin!

        * Wenn Du den Code einer Funktion / Methode mit solchen Krücken struktuieren mußt, ist sie zu lang und sollte in kleinere Funktionen / Methoden zerlegt werden. Spätestens die Vergabe von Namen zeigt, dass Du eigentlich kleinere, eigenständige Funktionen / Methoden haben willst.

        Meh, Funktionen sind doch vor allem dann sinnvoll, wenn man dadurch Wiederverwendbarkeit erzielen kann, nicht wenn ich irgendwas benennen kann.

        Das wird aber oft deckungsgleich, spätestens, wenn man den Code im Laufe der Jahre immer wieder anfassen muß, weil sich die Anforderungen ändern.

        Glaub mir, ich wühle seit drei Jahren in teilweise über 30 Jahre altem MUMPS-Code, der von Amateuren zusammengefrickelt wurde. Ich kann Dir aus dem Code für wirklich jede schlechte Idee, auf die man beim Coden kommen kann, mindestens drei Beispiele zeigen. Auch für falsch aufgeteilte Funktionen, zu lange oder zu kurze Funktionen. Von Copy&Paste und Ignorieren der System-Doku will ich gar nicht anfangen.

        Ob Du die Pseudo-Strukturen mit sinnlosen Labels und anonymen Blöcken baust oder stumpf mit Kommentarzeilen voll Line Noise, macht keinen Unterschied. Letztere schmeißt schon der Precompiler bzw. Parser raus, erstere macht so ziemlich jeder Optimizer im Compiler platt.

        Mir geht es in erster Linie auch nicht um Performanz, davon bin ich lange Weg. Jeder kann für einen Computer programmieren, gute Programmierer programmieren für Programmierer.

        Nö, gute Programmierer schrieben den Code so, dass der für einen anderen Programmierer, der die Syntax der jeweiligen Sprache kennt, ohne weiteres lesbar und verständlich ist. Unverständliche Konstrukte werden mit Kommentaren versehen, die das Konstrukt erklären. Insbesondere, wenn man fiese Tricks für irgendwelche Optimierungen nutzt.

        Um Mini-Optimierungen (Loop unrolling, Inlining und ähnliches) kümmert sich der Compiler. Die großen Optimierungen, angefangen bei Hints für den Compiler über Auswahl von Algorithmen und Datenstrukturen, sind immer noch Job des Programmierers.

        Und beides ist IMHO falsch:

        Ich habe im Studium noch gelernt, dass eine Funktion nicht länger als eine Bildschirmseite sein soll, wobei Bildschirm ein VT420 im VT100-Modus meint, also 25 Zeilen à 80 Zeichen, minus zwei oder drei Zeilen, die Editor und Terminal selbst brauchen.

        Naja, die Bildschirme sind ja ein Zeuge dafür aus welcher Zeit diese "Best Practices" stammen. Ich sehe in solchen Aussagen keinen akademischen wert. Codezeilen halte ich sogar für ein ausgesprochen schlechtes Qualitätsmerkmal für Quelltexte.

        Natürlich sind LoC ein schlechtes Maß. Aber LoC ist besser als gar nichts. Und die (Daumen-)Regel "max. 20 LoC pro Funktion" verhindert einigermaßen, dass Leute alles in eine Funktion stopfen. Manchmal braucht eine Funktion 30 LoC, dann ignoriert man die Regel eben. Aber 100 oder 200 LoC sollten wenigstens eine Alarmlampe aufleuchten lassen. Sicherlich gibt es auch Fälle, wo 200 LoC in einer Funktion sinnvoll sind, aber die sind eher selten.

        Eine andere Daumenregel: Eine Funktion oder Methode sollte immer nur einen einzigen logischen Schritt erledigen.

        Das passt mir schon eher in den Kram. Wobei "ein logischer Schritt" ein dehnbarer Begriff ist ;)

        Der "logische Schritt" ergibt sich aber von selbst, wenn man das große Problem Stufe für Stufe in kleinere Schritte unterteilt. Dabei fallen Klassen- und Methodennamen fast von selbst an. Natürlich hält kein Plan der Wirklichkeit stand, aber mit etwas Übung muß man während der Programmierung am Plan nicht mehr viel ändern.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
        1. Om nah hoo pez nyeetz, Alexander (HH)!

          Um Mini-Optimierungen (Loop unrolling, Inlining und ähnliches) kümmert sich der Compiler[, ]

          der natürlich auch von Programmierern ständig verbessert wird.

          Matthias

          --
          Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Pol und Pole.

  2. Gibt es irgendwelche Gründe die dagegensprechen Blöcke zur Quelltext-Strukturierung einzusetzen?

    Ich habe noch nicht gesehen, daß Blöcke zur Strukturierung eingesetzt werden, und finde das auch eher unschön.
    In anderen Sprachen wird es manchmal verwendet um die Lebensdauer von Variablen auf dem Stack zu begrenzen (vor allem bei Smartpointern). Aber dass fällt bei JS ja auch weg.

    Also ich stimme Alexander (HH) mit Punkt 3 voll zu!

    1. Meine Herren,

      In anderen Sprachen wird es manchmal verwendet um die Lebensdauer von Variablen auf dem Stack zu begrenzen (vor allem bei Smartpointern). Aber dass fällt bei JS ja auch weg.

      Dann kannst du dich auf ECMAScript 6 freuen, da wird es Block-Scope geben, Schlüsselwort dafür ist let.

      --
      Hey Girl,
      i wish you were asynchronous, so you'd give me a callback.
  3. Meine Herren,

    Ich bin kein Herr, aber ich darf hoffentlich trotzdem antworten.

    Gibt es irgendwelche Gründe die dagegensprechen Blöcke zur Quelltext-Strukturierung einzusetzen?

    In deinem Beispiel sehe ich jetzt keinen sinnvollen Einsatz. Da tut es auch ein Kommentar.

    In perl gibt es auch labeled blocks. Dort kann man auch Schleifen mit einem Label versehen.

    Beispiele in perl:

    FOO: for my $thread (@threads) {  
        ...  
        for my $article (@articles) {  
            last FOO if $article->blah;  
        }  
    }
    

    Man kann also in einer inneren Schleife die äussere beenden, ohne sich umständlich eine Statusvariable zuzulegen, die man in der äusseren schleife abfragen muss.

    Bei einfachen Blöcken kann man es auch zur Vermeidung von verschachtelten if/elsifs verwenden

      
    my $file;  
    UPLOAD: {  
      
        last UPLOAD if length($data) > ...;  
      
        my $mimetype = get_mimetype($data);  
        last UPLOAD unless exists $allowed_types{ $mimetype };  
      
        my ($x, $y) = get_size($data);  
        if ($x > 100 or $y > 100) {  
            last UPLOAD;  
        }  
      
        # everything ok  
        $file = save_data($data);  
    }  
    # weiter mit $file  
    if (defined $file) {  
        ...  
    }  
    
    

    Sowas lässt sich alternativ nur mit einer eigenen Funktion und return lösen (was bei längerem Code dann auch sinnvoll ist), oder mit Exceptions. Ich setze sowas ab und zu ein.

    1. Meine Herren,

      In deinem Beispiel sehe ich jetzt keinen sinnvollen Einsatz. Da tut es auch ein Kommentar.

      Da geb ich dir recht, das Beispiel diente nur dazu die Syntax vorzustellen.

      In perl gibt es auch labeled blocks. Dort kann man auch Schleifen mit einem Label versehen.
      Man kann also in einer inneren Schleife die äussere beenden, ohne sich umständlich eine Statusvariable zuzulegen, die man in der äusseren schleife abfragen muss.

      Das gibt es in JS auch, in PHP gibts zwar keine labels aber man kann hinter dem break bzw. continue mit einer Ganzzahl angeben, wie weit gesprungen wird.

      Bei einfachen Blöcken kann man es auch zur Vermeidung von verschachtelten if/elsifs verwenden

      Ich kann kein Perl, aber das scheint mir ziemlich ähnlich zum dem Konstrukt aus dem zweiten Block "doOtherStuff" aus meinem Beispiel zu sein.

      Sowas lässt sich alternativ nur mit einer eigenen Funktion und return lösen (was bei längerem Code dann auch sinnvoll ist), oder mit Exceptions. Ich setze sowas ab und zu ein.

      Habe neulich eine interessante Debatte über Exceptions und Kontrollflüsse gelesen. Den Link reich ich nach, konnte ich auf die Schnell nicht ausfindig machen.

      --
      Hey Girl,
      i wish you were asynchronous, so you'd give me a callback.
      1. Meine Damen und Herren,

        Sowas lässt sich alternativ nur mit einer eigenen Funktion und return lösen (was bei längerem Code dann auch sinnvoll ist), oder mit Exceptions. Ich setze sowas ab und zu ein.

        Habe neulich eine interessante Debatte über Exceptions und Kontrollflüsse gelesen. Den Link reich ich nach, konnte ich auf die Schnell nicht ausfindig machen.

        Hier ist der fehlende Link: http://net.tutsplus.com/articles/general/round-table-1-should-exceptions-ever-be-used-for-flow-control/

        --
        Hey Girl,
        i wish you were asynchronous, so you'd give me a callback.
        1. Hier ist der fehlende Link: http://net.tutsplus.com/articles/general/round-table-1-should-exceptions-ever-be-used-for-flow-control/

          Ich hab jetzt gerade keine Zeit das alles zu lesen, hoffe aber das als Ergebniss mal irgendwo steht, daß Exeptions langsamm sind, den Kontrollfluss kaputt machen und nicht das Allheilmittel sind, für dass sie immer gepriesen werden.

          1. Hier ist der fehlende Link: http://net.tutsplus.com/articles/general/round-table-1-should-exceptions-ever-be-used-for-flow-control/

            Ich hab jetzt gerade keine Zeit das alles zu lesen, hoffe aber das als Ergebniss mal irgendwo steht, daß Exeptions langsamm sind, den Kontrollfluss kaputt machen und nicht das Allheilmittel sind, für dass sie immer gepriesen werden.

            WORD!

            ganz, gaaaaanz sparsam uns sinnvoll eingesetzt ist es ja eine schöne Sache. Aber manchmal sieht man Code, der nur nur auch aus Exceptions besteht. Warum? Ich glaube, es liegt daran, dass einfache if-else-Klauseln so uncool und veraltet wirken. Man will ja kein Gestriger sein.

            Mir ist ein if(is_file(file) && is_readable(file)) lieber als eine dämliche FilenotFound-Exception abzufangen. Vielleicht oldschool, aber lesbarer. Imho

      2. Tach!

        in PHP gibts zwar keine labels aber man kann hinter dem break bzw. continue mit einer Ganzzahl angeben, wie weit gesprungen wird.

        Es gibt goto - mit Labels. Aber ich hab das noch nie in freier Wildbahn gesehen.

        dedlfix.