Unreadable Code 101



  • One of the most accessible techniques for writing unreadable code is to make extremely little use of your programming language's built-in functions. For example, instead of using assigning the output of array_diff to a descriptively-named variable, consider writing a stream-of-consciousness foreach loop with a nested if(in_array()) check, and simply move the rest of the code in your function inside that check. This simple technique can be applied as many times as you like until even the NSA can't decipher your code.

    foreach ($listOfNames as $name)
    {
        if (!in_array($name, $otherNames))  
        { 
            foreach ($otherNames as $otherName) 
            { 
                if (array_key_exists($otherName, $goodNames)) 
                { 
                    foreach ($goodNames as $goodName) 
                    {
                        if (isset($greatNames[$goodName]))
                        {
                            // insert lengthy code here to process the set of goodNames that
                            // are in the list of great names and the list of other names
                            // and not in the list of names at the same time
                        }
                    }
                }
                else 
                {
                    // under what circumstances will this happen? who knows!
                    // how exciting for everyone!
                    throw new CriticalSystemDestructionError; 
                }
            }
        } 
    }
    

    If you find yourself struggling to remember what each of the cliff-face of closing braces at the end corresponds to, you may be tempted to refactor your code in order to fix this. This is a common mistake among rookie coders and severely harms the unreadability of your code. The correct method is to append any such closing braces with a little comment containing a duplicated version of the opening line, like so:

        } // foreach
    
    } // if
    

    The handy thing about this approach is that it's almost guaranteed that nobody will update these little comments. As a result they can quickly become out of sync with the opening statements at the other side of the pyramid. Job done!



  • Let's expand on our earlier introduction to the use of comments as a weapon against readability. The guiding principle for writing comments that harm readability is this: reiterate the code. For example, perhaps you write a line of code assigning some value to a variable. This is a great opportunity to add a comment.

    // get user ID from user
    $userID = $user->getID();

    What's really special about this approach is that it gradually trains readers of your code to ignore your comments. This gives the entire codebase a sort of "readability cancer" because everybody's so accustomed to the comments containing no interesting information that nobody ever looks at any comments any more, including useful ones not written by you. An important aspect of this method is the useless boilerplate docblock. For example:

    /**
     * Return the user ID
     *
     * @return integer
     */
    public function getID() {
        // return the user's ID
        return $this->id;
    }

    In the above example, we introduced only one line of syntactically important code, but by embedding it among many other information-free lines we complicate even a simple thing.



  • Whitespace is another powerful tool in the fight against readability. Hopefully your team has a code style guide document somewhere, containing details of things like what tab width is standard and so on. You must study this document carefully, and go against it in any way possible. If the standard demands a tab width of four, you must stanuchly refuse to use anything other than eight-space tabs in all your work. In order to get maximum utility from this method, it's important to carefully align all your equals signs, array declarations and so on using eight-space tabs. It may appear to improve readability on your own screen, but don't be put off. This is what your colleagues will see:

    $aDataArray = array(
        'something'       => 1,
        'other'                              => 2,
        'More'    => 3,
    );

    Once applied to an entire subset of the codebase, this approach alone is enough to establish a sort of "code territory" for yourself within it. You may also have noticed the unfamiliar little "a" in the example above. See it now? That's an example of "Hungarian Notation". If your workplace's code standard does not specify the usage of Hungarian notation, then you are in luck. Study up on it, and apply it religiously in all code you touch.

    $oUser = new User($iUserID);
    $sUser = $oUser->getName();
    $sTitle = "Hello $sUser!";

    The core thing to remember when using Hungarian notation against a codebase is to drastically reduce the expressiveness of your variable names. Now that you're including the variable's tyoe as part of its name, it's just about possible to work out what's going on without too much more help from the name. In the above snippet, for example, note how we assigned the user's name to $sUser. You may have been tempted to call that variable $sUserName out of habit, but look how it's more or less possible to work out the difference between $oUser and $sUser without really providing any other helpful context.



  • The unreadability cause extends far beyond the boundaries of your IDE's window borders. There are many opportunities out there in meatspace for you to exert a harmful effect on communication within your team. Perhaps your team engages in the practice of holding daily scrum meetings, for example. The usefulness of these meetings is based on a few simple core rules:

    • Timeboxed to 15 minutes
    • Come prepared
    • Start on time
    r

    If you manage to sabotage these rules, you can cripple you team's ability to coordinate. Arriving late and unprepared is easy. The difficult part in this technique is to break the timeboxing rule. You are going to have to *talk*. A lot. Ideally, you should be spending 4 or 5 times longer talking than anyone else. You may be wondering, "What am I supposed to talk about?". You can draw on the most tiny details and minutiae from the last day of work. Ramble endlessly about how difficult it is to write unit tests. Poor scorn on the team lead for notifying you of a requirements change that came from elsewhere in the company. Deliver a short speech about what a stupid idea you think this feature is. And most importantly of all: do all of this at a barely audible whisper so that even those who stay awake are unable to hear you.

    The opportunities to be a bad team member don't end with the daily scrum meeting, mind you. If anyone in your team has any kind of leadership responsibilities, make them a target for constant contrarian harrassment. The slightest request must be met with your utmost disdain. Answer all questions with meandering, irrelevant diatribes about whatever you happen to be having difficulty with right now. Fight every decision or change to your working environment no matter how petty or inconsequential.



  • @GNU Pepper said:

    What's really special about this approach is that it gradually trains readers of your code to ignore your comments.

    Funny, it'd have the opposite effect on me … (I just write the occasional program, mostly for my own use; I tend to struggle reading blocks of code because I find myself skipping from comment to comment as they contain actual text that makes immediate sense (well, sometimes anyway) whereas trying to follow the code quickly gets tiring :)



  • @GNU Pepper said:

    The difficult part in this technique is to break the timeboxing rule. You are going to have to *talk*. A lot. Ideally, you should be spending 4 or 5 times longer talking than anyone else. You may be wondering, "What am I supposed to talk about?". You can draw on the most tiny details and minutiae from the last day of work. Ramble endlessly about how difficult it is to write unit tests. Poor scorn on the team lead for notifying you of a requirements change that came from elsewhere in the company. Deliver a short speech about what a stupid idea you think this feature is. And most importantly of all: do all of this at a barely audible whisper so that even those who stay awake are unable to hear you.
     

    Amateur. You can do the old boring thing, and become marked as a bad team player. Or you can try to excell at team disruption.

    Instead of complainning about others, do a half an hour discurse that is flatering to everybody on your team, but adds no real insight. Instead of complainning about changing requirements, simply explain them in detail, but be sure to get every odd detail wrong, so that your team must either lose time correcting you or change them later. Instead of complainning about the dificulty of writting unit tests, ask for feedback on your tests, and makesure there is someusefull feedback to get by making some small (almost undetectable) mistake on them, also, offer feedback on the tests of other team members, make sure to give them usefull info, and get it wrong from time to time. Instead of complainning that a feature is stupid, choose a really stupid idea, and make a long speed about how great it is.

    O bit on-topic digression: If you arecoding in C/C++, be sure to remember that all paired operators ('[', '{', '(' and the respective closing ones) can be used in macros.

     


  • ♿ (Parody)

    @GNU Pepper said:

    The difficult part in this technique is to break the timeboxing rule. You are going to have to talk. A lot. Ideally, you should be spending 4 or 5 times longer talking than anyone else. You may be wondering, "What am I supposed to talk about?". You can draw on the most tiny details and minutiae from the last day of work. Ramble endlessly about how difficult it is to write unit tests. Poor scorn on the team lead for notifying you of a requirements change that came from elsewhere in the company. Deliver a short speech about what a stupid idea you think this feature is. And most importantly of all: do all of this at a barely audible whisper so that even those who stay awake are unable to hear you.

    I usually ask these people to repeat themselves. The rest of the team is never sure if they should hate me or the original bore.OTOH, I've been known to give one word status reports.



  • @GNU Pepper said:

    Let's expand on our earlier introduction to the use of comments as a weapon against readability. The guiding principle for writing comments that harm readability is this: reiterate the code. For example, perhaps you write a line of code assigning some value to a variable. This is a great opportunity to add a comment.

    // get user ID from user
    $userID = $user->getID();

    What's really special about this approach is that it gradually trains readers of your code to ignore your comments. This gives the entire codebase a sort of "readability cancer" because everybody's so accustomed to the comments containing no interesting information that nobody ever looks at any comments any more, including useful ones not written by you. An important aspect of this method is the useless boilerplate docblock. For example:

    /**
     * Return the user ID
     *
     * @return integer
     */
    public function getID() {
        // return the user's ID
        return $this->id;
    }

    In the above example, we introduced only one line of syntactically important code, but by embedding it among many other information-free lines we complicate even a simple thing.

    Thank you so very much for this. I hate useless comments like crazy. There are so many people who say "but each and every method must be commented" I say "No!" At least not in cases like these, getters and setters don't need comments. Name your methods so their name makes its purpose obvious. Give the parameters meaningful names, too. No "aString" or other nonsense names, call it "username" instead. There is so much useless bloat in stupid comments that don't add anything useful to the code.



  • Has anyone made something that goes through source code and comments before every line with a tautology? That could be useful for people paid by the line.



  • @GNU Pepper said:

    ... An important aspect of this method is the useless boilerplate docblock. For example:

    /**
     * Return the user ID
     *
     * @return integer
     */
    public function getID() {
        // return the user's ID
        return $this->id;
    }

    In the above example, we introduced only one line of syntactically important code, but by embedding it among many other information-free lines we complicate even a simple thing.


    Not quite true. There's one line of useful comment in there.

    /**
     * @return integer
     */
    public function getID() {
        return $this->id;
    }

    allows the IDE to tell you the type, which it is otherwise unlikely to infer since this is PHP and dynamically typed.



  • @Ben L. said:

    Has anyone made something that goes through source code and comments before every line with a tautology? That could be useful for people paid by the line.

    Isn't that what GhostDoc does?



  • @Mcoder said:

    If you arecoding in C/C++, be sure to remember that all paired operators ('[', '{', '(' and the respective closing ones) can be used in macros

    If you really want to make enemies...

    // Buried deeply in a masterfully hidden include file: language.h
    #define StartBlock       {
    #define FinishBlock      }
    #define StartDecision    if
    #define EndDecision
    #define DoBlock      
    #define DoDifferentBlock else 
    

    ...

    StartDecision (x > 5)
    DoBlock StartBlock
    ...
    FinishBlock
    DoDifferentBlock StartBlock
    ...
    FinishBlock
    EndDecision


    ...although this probably loses some of its WTF-ness with modern IDEs.



  • @snoofle said:

    @Mcoder said:

    If you arecoding in C/C++, be sure to remember that all paired operators ('[', '{', '(' and the respective closing ones) can be used in macros

    If you really want to make enemies...

    // Buried deeply in a masterfully hidden include file: language.h
    #define StartBlock       {
    #define FinishBlock      }
    #define StartDecision    if
    #define EndDecision
    #define DoBlock      
    #define DoDifferentBlock else 
    

    ...

    StartDecision (x > 5)
    DoBlock StartBlock
    ...
    FinishBlock
    DoDifferentBlock StartBlock
    ...
    FinishBlock
    EndDecision


    ...although this probably loses some of its WTF-ness with modern IDEs.

     

    StartDecision (x > 5)

    StartBlock

    ......

    }

    DoBlock{

    ......

    EndBlock

     



  •  obligitory the guide to writing un-maintainable code. http://thc.org/root/phun/unmaintain.html or less monolithic with menus http://mindprod.com/jgloss/unmain.html 

    Note: link in first link to the second link is borked!



  • @TheRider said:

    There are so many people who say "but each and every method must be commented" I say "No!" At least not in cases like these, getters and setters don't need comments.

    I both agree and disagree. I agree in the sense that writing getter/setter docblocks containing nothing but informationless boilerplate is a waste of time. In fact it's worse than a waste of time as it actually harms readability. I disagree in that there very occasionally actually is something to document for these methods, but it's very easy to miss the opportunity if you're not in the habit of stopping and thinking. And the best way to guarantee you'll never be in the habit of stopping and thinking is by training yourself to prepend every bit of code you write with thoughtless boilerplate.

    I know a few developers who consider themselves very good software engineers on the grounds that they pay mindless lip-service to a few bits and pieces of process pot-pourri like this.



  • Some Simple steps:

    1. Turn on empathic capabilities. (most human being develop Theory of Mind by age 4 or 5. If you have difficulties with this, find a coworker you believe to have friends and a social life, and show him/her your code)
    2. Ask yourself "can someone without my current insights decipher the purpose (not the functionality) of this code?"
    3. YES -> don't comment. NO -> comment.

    For ordinary methods that implement some business rule, #3 almost always evaluates to NO. Exceptions granted.



  • @dhromed said:

    most human being develop Theory of Mind by age 4 or 5.
     

    Hell, I remember strill trying to get that at the age of 12. And needed a lot of empiricism.



  • @Mcoder said:

    @dhromed said:

    most human being develop Theory of Mind by age 4 or 5.
     

    Hell, I remember strill trying to get that at the age of 12. And needed a lot of empiricism.

     

    I'll try not to use much sarcasm or flowery poetics when addressing you.

     


  • Discourse touched me in a no-no place

    @snoofle said:

    @Mcoder said:

    If you arecoding in C/C++, be sure to remember that all paired operators ('[', '{', '(' and the respective closing ones) can be used in macros

    If you really want to make enemies...

    // Buried deeply in a masterfully hidden include file: language.h
    #define StartBlock       {
    #define FinishBlock      }
    #define StartDecision    if
    #define EndDecision
    #define DoBlock      
    #define DoDifferentBlock else 
    

    ...

    StartDecision (x > 5)
    DoBlock StartBlock
    ...
    FinishBlock
    DoDifferentBlock StartBlock
    ...
    FinishBlock
    EndDecision


    ...although this probably loses some of its WTF-ness with modern IDEs.

     

    Supposedly one of the older Unix shells did just this, converting C into some mishmash of COBOL and Pascal by #defining all the keywords and operators.  I thought it was bash, but I went and looked in the repository, so if it was ever there, it appears to be long gone.



  • @TheRider said:

    There are so many people who say "but each and every method must be commented"
     

    Do they give reasons why? Or are they just brainwashed kata morons?

    @esoterik said:

     obligitory the guide to writing un-maintainable code. http://thc.org/root/phun/unmaintain.html or less monolithic with menus http://mindprod.com/jgloss/unmain.html 

    Neat links. Bookmarked.

     

     



  • @dhromed said:

    2. Ask yourself "will a raving psychotic with my home address tasked with maintaining my code be paying me a visit late on night?"
     

    FTFY.

    You know my views on code maintainability.



  • @FrostCat said:

    Supposedly one of the older Unix shells did just this, converting C into some mishmash of COBOL and Pascal by #defining all the keywords and operators.  I thought it was bash, but I went and looked in the repository, so if it was ever there, it appears to be long gone.
    It was the Bourne shell, and it #defined C to something algol-like (which AFAIK is what the sh scripting language was modelled after). bash is a GNU implementation of the Bourne shell, but it doesn't share any code with it.


Log in to reply