Monday 9 February 2009

Brute Force and Excellence: Using the simple solution to a coding problem

[caption id="" align="alignleft" width="240" caption="Photo by El Garza"]Photo by El Garza[/caption]

Sometimes, a problem in coding has a simplistic solution. It might be ugly. It's probably way slower than the smarter ways you can think of to solve the problem. It may even offend your sensibilities as clunky and unpleasant.

We think you should use it.

There are caveats to this, of course, but in this article we want to point out the merits of doing things in the simplest, most straightforward way you can think of. And there are more than you might think.

Fits well in your brain...
The simple solution (by definition of "simple"), will tend to be easy to understand. Obviously, this is a Good Thing. But it also implies that there will be fewer bugs in it (as it's easier to avoid/spot mistakes) and it will take less thinking on your part to feel sure you've implemented a correct solution. This also means that you will have more mental resources to devote to other areas of your code, so there's a knock-on effect. Why wipe yourself out on part of the code that has a simple solution, when that mental effort is better spent elsewhere.


It might already be fast enough!
The biggest problem with the simple solution is that it's often a lot slower than other, more clever approaches (see our article on order notation ). Sometimes, this is important, but a lot of the time (more than you might imagine), this part of the code won't be the bottleneck and in fact will never be the bottleneck (see our articles on optimisation for more discussion about this). In this case, you are gaining nothing by making this chunk of code faster and/or use less memory. So don't bother spending any extra time doing this, because it's effort that would be better spent elsewhere. So implement the simple solution and move along.


Simplicity => quick to get running
Another great advantage of the simple solution is that they tend to be quick (in terms of programmer-time) to get running. This can be very useful, because the sooner you have code that runs, the sooner you can test it, produce results and so on. Even if your code isn't as fast as you'd like (yet), getting it running beginning-to-end is a big step towards completing your project.


You can always replace it...
Okay, sometimes this approach won't work and you'll end up with code that's too slow. Not a problem. You can always refactor this chunk of code to use a cleverer approach, if you need to, as part of your optimisation. The key points here are that often this won't be the case, and even if it is, because the simple method didn't take long to implement, you've not lost much time.


In conclusion
Think of this as a hidden aspect of avoiding premature optimisation . Any time you spend implementing a "clever" solution, as opposed to the simple solution, you are kind of optimising. Now, we're not saying never do this. Sometimes, it's obvious that the simple solution is too simple (maybe you're done an order-of-magnitude calculation, or perhaps your prototype demonstrated it) and that's fine. But if there's any chance that the simple solution will work just fine, it might well be worth trying.

3 comments:

  1. Alexander Grünewald9 February 2009 at 18:19

    "You can always replace it…"

    there is another argument you could mention in this paragraph. Sometimes you can simply reuse the brute force implementation to validate the correctness of a cleverer (but complex) approach.

    ReplyDelete
  2. Good point. Actually, I think that's very important. Thanks for the input!

    ReplyDelete
  3. Microsoft use this technique in Excel. The simple, and very slow, implementation is used to test the optimized, and hideously complex, implementation. If they disagree an error is thrown.

    This idea is also used in critical systems (aircraft etc.) where different implementations of the same rules are tested against each other by a decider.

    ReplyDelete