Speculative Optimisation
By Simon Harrisor pre-factoring as Dave likes to call it, is a common practice. It’s an easy trap to fall into. Take a look at any piece of code and I’m sure you will see a way to make it run faster. The problem is that performance bottlenecks are almost never where you would expect them to be. Sure, we might be able to double the speed of a piece of code but if it only accounts of <1% of the overall running time, then it doesn’t really matter. Just recently I had someone reccommend that we add in some caching of database results because “It will be a performance problem.” The question I had was, when compared with what?
Performance optimisation often (but not always) involves obfuscating the code in some way to achieve the desired performance. Maybe we need to inline some code or unroll a loop here or there. Whatever it is can lead to code that is hard to read and hard to understand and, as we have discussed before, therefore hard to maintain. Ironically, our so-called optimisations can potentially lead to worse performance. If the algorithm is diffuclt to understand or the code simply hard to follow, we might actually introduce unecessary overhead without even realising it. If we have no base-line, no benchmark with which to compare our results, we will never know if we are improving or degrading the performance.
For this we need a profiler. There are plenty around, some free and some you’d have to sell the kids to afford. Quest have a free version of JProbe for use with Linux and Windows that James and I have been using to profile Drools. It’s missing some features but certainly nothing we can’t live without (how many negatives can a man use in one sentence?). There really is no magic involved. Run it, see where the biggest slice of the pie is and start there. Keep doing that until you’ve knocked off all the big ticket items. Chances are that’ll get you most of the way. Anything beyond that probably requires a fundamental shift in the design. But hopefully, because you have a clean design, that shouldn’t be too much of a problem ;-)
Interestingly, one of the simplest things you can do with your design is to make things as close to immutable as possible. So, for example, rather than have lots of JavaBeans with setters, use constructors. Mark your fields final. Not so because that in itself is a performance enhancement (although it maybe?) but to ensure that the state of your objects is as stable as possible. It also makes it much easier to find out who’s messing with the state. To achieve this, you may find you need to de-compose those monolithic classes into smaller ones. I’ve found it helpful to introduce Builders to accumulate state before constructing your objects. You can think of mutable objects as having many moving parts and the more moving parts to a system, the harder it is to work out what’s happening and the harder it will be to re-factor when you finally perform your profiling.
Experience has taught me over and over again that correct code is much easier to optimise than clever code. This is why I’m a firm believer in Make It Work, Make It Right, Then Make It Fast.