Medallia Blog

October 27, 2006

Building Cathedrals

Three people are working on laying down bricks. You ask the first what he is doing, and he answers 'I am laying down bricks'. You ask the second, which says 'I am building a wall'. Finally you ask the third who tells you 'I am building a cathedral'.

Great programs are created the same way as any other program, one brick at a time, but each brick has to be laid down in the knowledge that it will be part of something greater than the small piece currently being worked on. If it is not known what the final structure will look like it is even more important to make sure the individual pieces can be built upon and reused later, because most code will find itself used in situations where requirements change. Knowing how much to abstract a given piece of code is what separates a good from a great programmer.

All great programmers were at some point merely good, however, and there are many rules that can be used to get better (first you have to learn the rules, and then you learn when to break them). Here are a few I personally try to live by:

  • Duplicate code is the root of all evil. Duplicating any non-trivial piece of code (where trivial is e.g. calling the same function from different places) is a maintenance nightmare in addition to being a time bomb that blows up in the face of one of your customer when you forget to update one of the copies of the code.
  • Do defensive programming. Anticipate what can go wrong and try to detect it as early as possible. Use assertions liberally, but only for things which are the result of a programming error. If someone is using your API in the wrong way it is much better that the system explodes as compared to silently ignoring the error and then doing the wrong thing.
  • Write test cases and use them while developing the code. If you are working on a team this has the added benefit that if someone else makes a changes that breaks your code a test will fail and the burden of dealing with it falls on them instead of you having to spend time to track it down when it crashes in the field.
  • Validate all user input and give resonable error messages. Recognize what is good and throw away the rest; trying to list all that is bad is usually futile (imagine trying to list all the foods you do not like instead of the ones you know you like when telling someone what you want for dinner).
  • Avoid accessing list elements by index if there is no reason to; use an iterator (or the enhanced for-loop in Java 1.5) instead.
  • If you have two (or more!) lists/arrays where the elements at equal indices belong together, put then in the same object and use one list.
Much has been said both in favor and against strong typing, but, if you find yourself working in a language that has it, use it to your advantage as much as possible.
  • Avoid using strings as identifiers (TypeTags are your friends). If you have to use string identifiers (e.g. http request parameters) convert them into proper types as soon as possible. String identifiers have no type safety (e.g. you cannot use a refactoring tool to rename one) and are much slower.
  • Use a static type checking tool (many IDEs, like Eclipse, has one built in) as this can catch many errors as you are typing. Unused variables and using a reference which can be null are typical bugs that should be caught this way.
Most programmers often find themselves in situations where they are tempted to make a quick hack to get something done (a typical example is that a reference to a specific object is needed, but which is far away in the call graph; the quick hack is to add a direct reference, which adds an unnecessary dependency and brings the code one step closer to the infamous "spaghetti code" case where dependencies are going all over the place). It is that exact moment, when the decision is made, which determines what kind of programmer you are.

October 17, 2006

More puzzles

We recently sent out some recruiting brochures. It is customary to include a couple of puzzles, so we used a couple of our favorites. Two are old, two are (as far as we know) new. Feel free to leave a comment with your answers.

Fix this program

Find a way to make the following C program fragment print 42 dashes, by changing only one character. Then find two more!

int i, n = 42;
for (i = 0; i < n; i--)
  printf("-");

Bonus puzzle: 43.
Bonus puzzle 2: find ways to make it print exactly one dash.

Magic function

What does this function do, and why does it work?

int magic(int i) {
  int j = 1337, k = 0;
  do k -= i += (i<0) + i;
  while (j *= 42);
  return k;
}

Find the dupe

Given a read-only array of length n of positive integers less than n, find a duplicate element in linear time and constant memory usage.

CD-R recycling

A CD-R can only be written once. Well, actually that's not true; you can still burn more 1's, you just cannot turn the 1's back into 0's. You have a pile of discs where no more than half the bits have been set. Devise a coding scheme which will let you use as few discs as possible to carry as much information as a new disc (the scheme has to work no matter how the bits are distributed). How many disks do you need?