Made to Order Software Corporation Logo

Don't Repeat Yourself When Writing Software

Nature tends to repeat itself, or reproduce with similar structure, but code should not.

For a very long time now, we have been using languages that support having functions that one can call. That was not always the case, although even really old versions of BASIC had a GOSUB instruction, which it had no concept of local variables so it was rather difficult to use safely.

Functions allow you to avoid repetition. You write a small snippet of code (or maybe not that small) within a function and then you call that function to reuse that snippet over and over again. Good programmers tend to do that even with one liners. However, many others often think: well, it's just one line, why don't I return copy & paste that wherever I need it, it's going to be faster.

This is where the Don't Repeat Yourself (DRY) patterns comes in handy: even for a one liner, make use of a function. If you want to optimize the code as much as possible, use your compiler command line options to allow for as many optimizations to be used as possible. Actually, your compiler probably optimizes better this way than when you try to write more complex expressions. With modern compilers, the inline keyword is also pretty useless. In most case, that keyword is going to be ignored.

There are huge advantage of calling a function:

  1. It allows for small tweaks to your expressions without the risk of missing locations where it was copied.
  2. The function can be used as a point where you add debug (i.e. you can put a break point or add a print to your console or your log and you'll capture all the usage of that expression)
  3. When code is just repeated, we tend to skip on error checking, yet having checks for errors can improve your code security.
  4. The name of function comes as a label for the expression. In a way, you are documenting a piece of your expression.
  5. In some cases, it will allow you to write varying versions of the function. For example, you may be able to optimize a loop using SIMD (Single Instruction Multilpe Data). Or in case you are developing for different type of processors, specialized versions for little and big endian platforms.

One reason why we just copy/paste when using modern languages is because it's very easy to do. It's much less work to copy/paste the same line of code 3 times than writing a function for it. You should still consider doing so.

One language that really offers an easy to use way of doing so is Ruby. The fact is that calling functions does not even require parenthesis. So when you write an expression, you can write a label which is the name of a function which somehow returns a value.

Here is a simple to understand example:

def arc_length(angle, radius)
   sin(angle * pi / 180) * radius
end

def pi
   3.14159
end

# and somewhere else in your code:
length = arc_length(29.3, 11.4)

The pi function simply returns the circumference of a circle divided by 2 (which is very approximetly 3.14159). I think that such an example clearly shows how that parameter inside the expression is a function and is named appropriately to clearly describe what it is (you know, instead of naming your functions "a", "b", "c"...)