Thursday, July 10, 2008

Spartan Programming: A Real Man's approach to engineering

man and machine flexible coolthree keyboard

13 years of coding don't pass without leaving a trace. You start to get stuck for hours in a shower on shampoo instructions that read "Apply, lather, rinse, repeat", type with a speed of a machine gun, navigate the code files using only your keyboard with inhuman agility, your fingers become longer and neck develops an aristocratic stoop. You also develop some sort of a style: the way you write code, the way you prefer to solve design problems, and a guideline that you use to evaluate code written by others. Your coding style is a distinct feature of you: it is honed all those years. Like an oriental master of combat that polishes his kung-fu for 60 years, you polish your code: the way it looks, the way it feels and even performs.

Through my programming experience, I never had an 'ultimate guideline to coding style'. My coding style was developed by seeing millions of lines of code from hundreds of other developers and by writing code myself. If I saw something that I considered cool I eventually adopted that in the code I wrote. If I saw something looks and performs fine — I was reusing that construct again and again. Never I had the name for my style — and if I was asked yesterday, I would define it in a couple of taciturn men words. But today, I have even a better definition — after stumbling at Jeff Atwood's article in my feed reader I finally know the name of the coding style I acknowledged and tried to follow and hone through all my coding career.

The name is short, precise and manly: Spartan programming.

300 Spartans movie screenshot
(I can't stand it, I just have to snatch this picture from the original Jeff's post).

Spartan programming. Two words say it all. Minimal, ascetic, open, yet powerful and to the point. The whole spartan armor set consists of a helmet and a shield — yet one look at a spartan leaves not even a small doubt in his immense strength and physical invincibility. There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies.— C.A.R. Hoare.



A quote from a Spartan programming description:
Spartan programming strives for simultaneous minimization of all of the following measures of code complexity:
  1. horizontal complexity, that is, the depth of nesting of control structures, just as the total line length.

  2. vertical complexity, that is, the code length in lines.

  3. token count

  4. character count

  5. parameters that is the number of parameters to a routine or a generic structure.

  6. variables

  7. looping instruction, that is the number of iterative instructions and their nesting level.

  8. conditionals, that is the number of if and multiple branch switch statements.

This is how Leonidas would write the code if he lived in our days and wasn't busy fighting with Chuck Norris for world dominance.

It is my deep belief that code should be as simple and as straightforward as possible. As Albert Einstein said, Any fool can make things bigger, more complex, and more violent. It takes a touch of genius - and a lot of courage - to move in the opposite direction.

The code should be short, sharp and to the point. If you think it's a good design idea to implement "just a couple more classes" because "it makes sense" to inherit CFelisCatus from CAnimalia->CChordata->CMammalia->CCarnivora->CFelidae->CFelis instead of inheriting CCat from CAnimal — you are wrong. The next engineer with 80% probability will simply not know what Felis catus is, and after a week of futile attempts to understand how to do things with your "advanced code that makes perfect sense" will simply decide "its not here" and will write his own CCat and CAnimal. That, my friend, is called code doubling, and practices like that give births to Codethulhus that feed on human souls. Remember: every time you write CFelisCatus, God kills a kitten.

if(true == bSucceeded)

{

  return XOK;

}

else

{

  return XNOK;

}

Anyone who writes code like this deserves to have both his hands chopped up to the elbow with a big (and dull) viking axe. If you think this is "readable", then you are wrong: human eye has a limited focus area for grabbing the code as a whole construct and human patience and concentration has its limits as well: after scrolling through 20 pages of open/close braces you just stop trying to read and understand the code and start to pretend that you are reading it. Unless you are a first-year culinary institute student or an indian programmer that is payed on per-line basis, you should restrain from writing code like that or I will break your face if I see you in public. And I mean it.

Compare the previous code with the code snippets below:if ( bSucceeded )

  return XOK;

return XNOK;
Or even with this one:return bSucceeded ? XOK : XNOK;

The code speaks for itself. It doesn't clutter your screen and is perfectly readable. If you can't understand how ternary operator works — what the hell are you doing at your can-feed-half-of-Africa-with-a-daily-salary engineering job?

Don't get me wrong. Even though I'm a fan of reversi.c, I do not approve that style of coding at work either. But there just should be a limit for code over-stretching.

My personal guidelines for manly code in C++

  • Ternary operator — master it. It turns a lot of code into elegant one-liners:printf("Ninja mode %s.", bStealth ? "enabled" : "disabled");

  • Prefer prefix form of incrementation/decrementation — it's simply faster then postfix. And with prefix form you can write cool things like this ++++++i;

  • Don't explicitly compare with NULL or false: if (enabled == true) looks tremendously stupid.

  • Delay variable declaration until it's initialization. This is simple. This immediately shows the type of a variable, and in case of non-integral variables (even std::string), you delay constructor and destructor call until it's obvious it's absolutely necessary — the execution point might never reach the code (for example, if it fails on parameter validation and returns).

  • Prefer integer constants to string constants — integer comparisons are many times faster, especially if you use std::string or similar — remember, you will also need to instantiate the std::string instance (and destroy it afterwards). Smaller memory footprint, more processor cache hits — there is no reason to use string constants over integer ones. Need strings for debug purposes? Create a static function that returns a const char* representation of this integer value. Oh, and with integer constants you can use switch instead of never-ending blocks of else if(...)'s

  • Trust noone — always check for the sanity of passed arguments, as well as function returns. Even if you have checked the code of the function (or even wrote it yourself) and are absolutely sure it can't return this specific value. Code is getting rewritten now and then, and trust me — nobody will try to change the behavior of your careless function until it loudly crashes on a big presentation day. And it will be you who will take salary cut the blame. Code, return values and arguments change — your function should still behave like a spartan and don't bring down the whole server because "this result is just not possible". Remember, the name 'bug' comes from the actual, real, material moth that got stuck in a relay of one of the first computers. And remember Adidas marketing slogan.

    Whatever happens, spartan code must stand. Or at least crash responsibly.

  • Avoid braces      } // else

        } // case

       } //switch

      } //while

     } //if( data != NULL)

    }
    Familiar construction? Even comments after braces don't help much. Avoid that. Don't encase the 'main processing' code into precondition-checking nested if blocks — check for precondition and return when it fails to fulfill. Don't encase single operation into braces. It is not better then indentation. It is worse. The only exception from this rule is a construct where you for some reason have nested if keywords paired with else keywords as well:

    bool intelligentDesign = true, spagettiMonster = false;

    if(intelligentDesign == true)

      if(spagettiMonster == true)

        printf("The world was created by God with the help of Flying Spagetti Monster.\n");

    else // if intelligentDesign != true, then the world was created by spagettiMonster alone

      printf("The world was created by Flying Spagetti Monster alone\n.");

    In cases like that, do encase even one-keyword blocks into braces. Don't trust indentation alone.

  • Naming convention. Naming convention is a controversial topic and many battles were lost before they have even started because spartans simply couldn't reach an agreement on a naming convention that should be used. (Read Linus Torvalds and Bjarne Stroustrup against Hungarian notation). And since spartans are used to talk short and to a point, we will stop writing this ode to manliness now and cover naming conventions in our next article.

If you liked this article, subscribe to this blog's ATOM feed to make sure you won't miss the end of the story. Meanwhile, feel free to express your opinion by writing a comment, or share spartan wisdom with others:
0
said thank you for this page

Liked this article? Bookmark/share it with others: Didn't like the article, found a mistake or just want to express your own opinion? Post a comment!

0 comments:

Post a Comment

Have anything to say? Leave a comment!
Too shy or got a too private question? Email me
Alternatively, you can drop me a line on Twitter