Monday 19 January 2015

Seven Deadly Programming Sins

Now that mid-January has passed, is it too late in the year to greet people with "Happy New Year" or think about New Year's resolutions?  On the latter, I like to think that it is never too late to turn over a new leaf (or at least have intentions of doing so).  Given that this time of year is often associated with detoxing our minds and bodies, I thought I would do a blog post about programming sins (very loosely related to the original Catholic sins!) that we might like to cast aside in 2015.

Pride

Disclaimer: Despite being a proud geek, I'm not actually a trekkie - Star Wars all the way!

Often considered to be the most serious of the sins and the source of all other sins, this is no less true in the world of programming.  Overconfidence or underestimating the needs of the problem at hand can have disastrous consequences later on, as you realise you have not taken into account all of the potential special cases/situations possible!  It can be all too tempting to get stuck in straight away without reading all of the specification in detail and drawing out a plan of action.  Taking a humble step back and a few minutes to model a problem with pen and paper, can save hours of potential refactoring further down the line (see a previous blog post on how to problem solve).

Checking your code before hitting the Enter key is also vital - a commonly given example is when using the command line to delete files on Unix terminals:  "rm *.doc -f " means remove (rm) all files that end with the .doc file extension and don't bother asking if I'm sure I want to do this (-f).  However "rm * .doc -f" (note the space between * and .doc) means remove ALL FILES, then remove any files that are called .doc, and oh yeah, don't bother checking whether this is what I really want to do!!

Overconfidence can also lead to forgetting to save your code (or commit changes) frequently!  Computers don't crash these days, so this is never a problem, right?!

Sloth


A lack of attention to detail or leaving it up to the compiler or your code editor to detect errors can be the root of many debugging frustrations! Whether or not you include that one little character can make all the difference and could come back and torture you for the next hour as you attempt to figure out why your code isn't working (a particularly bad state to be in when under exam conditions, as I recently discovered!!!).  From time to time, I'm sure all C programmers have been caught out at one time or other by one of these bugs...

  • while(x=y) This statement will always evaluate to true, as the variable x is being assigned a value y.  If you want to compare whether the value of x equals y, you need that all-important second equality sign!
  • for(x=0; x<100; x++);  That extra semi-colon tells the compiler that this command ends here, so it means that the for loop just increments x 100 times without actually stepping into the code that you have written in the body of the loop!
  • Passing input parameters by value rather than by reference: If you want the function to make alterations to your input parameters, rather than just making a copy of it, you need to remember to add an '&' before the parameter in the function definition!

Vanity

Ok, it's really hard to find a funny picture on vanity!

A friend once told me that they have heard it being said that "premature optimisation is the root of all evil".  Related to pride, a desire to make your code look elegant or "clever" combined with failing to understand the requirements of the specification can lead to misery, frustration and obfuscation.

I was also once the victim of vanity in a different way - after finishing writing a simple Python program, I thought I would try to tidy up the code a bit to make it look prettier - spacing out functions and comments a bit more...all the while forgetting that whitespace actually matters in Python!!! Needless to say, it took me quite a long time to work out why my program was no longer working, but it was a tough lesson learnt in how spacing affects code in Python!

Gluttony (for memory!)


Getting the hang of memory management is an integral part of C++ programming.  Computer Science students dread the "Segmentation Fault" error when doing their coursework on manipulating pointers, caused by their program trying to access areas of memory outside of the allowed bounds of their program, or an infinitely recursing program that uses up all the available memory space while running.  Using uninitialised variables can also lead to confusion - consider this code:
int x; x++; cout<<x;  No value for x is declared when the variable is created, but x is likely to hold some value - whatever previously happened to be at the memory location the computer has assigned x to, so printing/accessing/using the value of x will not fail - instead it will just be gibberish.

None of these issues are caught at compile time, but become apparent at run time.  Of course, failing to free up dynamically allocated memory is also a cardinal sin, although many modern computers "forgive" this by automatically freeing up any memory allocated on the heap when the program exits.  This issue can be avoided all together if you program in a language like Java, where unlike C++, memory management is taken care of for the programmer....this has always made me slightly suspicious of the language, as if it were leading the coder into temptation...

Repetition 


If you have lots of repeated sections in your code, there is almost certainly a way to redesign it more efficiently.  Let the computer do the repetitive work - that's what it's there for!

Obfuscation

Perhaps nobody deliberately goes out of their way to make their code difficult to understand (unless of course you are entering into a Code Obfuscation Competition), but it is worth taking the time to either comment your code or dedicate that time to making your code clearer for the sake of the sanity of your fellow programmers.  Sometimes when we have been given coursework, I often think there is clearly one obvious and mainstream way to solve the problem - this is simply not true.  The variety of ways in which people tackle problems is vast (and in itself very interesting, as well as something that is great to learn from).  At the same time, it is difficult for someone else to put themselves in your shoes, see the world from your perspective and adopt your way of thinking.

Interdependency 

I think this is the least serious of the sins I have discussed here, mostly because sometimes it is unavoidable.  Ideally, there should be as little dependency between functions or between classes as possible, with each section of code being allocated a certain task that it can carry out on its own.  Not only is this more efficient, but it should also enable speedy refactoring of your program if the need ever arises. However, sometimes you just can't avoid needing to have two classes that simultaneously rely on each other - in that scenario, all you can do is make sure you have your class declarations the right way round - I have found myself referring to this Stack Overflow link more than a few times!


This is by no means a comprehensive list of programming sins, and some may have noticed that of the seven original deadly sins , I did not incorporate Wrath, Lust and Envy, although these are emotions that I have often experienced while doing coursework (i.e. "WHY DOESN'T THIS CODE COMPILE?! GRRR, sometimes followed by asking a fellow student "How did you get it work on your machine?!").