Weightlessness and Statelessness in Programming, Part I
Posted by David Chandler on May 19, 2006
“It is easier to optimize correct code than it is to correct optimized code.” — unknown
A good businessman knows to let his accountant tell him when to change his ad, not his ad agency. Similarly, a good programmer knows to let the code profiler tell him when to optimize, not his inner compulsion for perfection.
During my senior year in Electrical Engineering at KU (Rock Chalk, Jayhawks!), we had to build a model traffic light controller using the MC68-whatever. We could program in any language of our choice. Most teams chose elegant, instantaneous, and very hard-to-debug interrupt-driven coding in C. My team was blessed with a student who had been an electronics technician for 2 years and happened to know that a certain Radio Shack pocket computer had a BASIC compiler for the MC68-whatever. We wrote a 100-line BASIC program in a day or two that polled the inputs (ooh, ick, old-fashioned, “stale” data) every 10ms in an infinite loop (to this day, the only infinite loop I’ve written on purpose). Our system met all the requirements and we added back many weeks to our lives.
Nowadays, I do UI coding in JSF. I keep finding myself tempted to implement various forms of caching and “push” mechanisms in the managed beans, and every time I do I end up with a pile of bugs involving hitting UI controls in funky combinations. From an elegance point of view, I love code that makes no intermediate copies of data anywhere. Every time you need something, chain those methods and go straight to the source. At times, I’m hung up by performance worries, but I’m learning to let go. As the quote at the top of this post says, it’s much easier to optimize once you’ve got correct code. Many times, the act of writing unoptimized, correct code has pointed out unwanted dependencies that would have been much harder to discover otherwise. So now I always write function first, optimization later. It may not satisfy the inner guru, but it certainly optimizes the most expensive computing commodity: engineering time.
So how can we write correct, unoptimized code?
- Keep it weightless. Optimization, particularly caching, adds weight to code. More weight = more bugs = less time. Is the code to convert an array to a Map for faster access even worth it? Certainly not if you’re just indexing 10 items in a drop-down box!
- Keep it stateless. Optimization, again thinking particularly of caching, often creates multiple representations of object state. Without caching, all data access goes to the source of record (typically, a database). Add in caching, and there are now multiple representations of object state to keep track of. Or forget the database for a minute: when you store the result of a method call in a bean and then store the bean in an HTTP session, you’ve now got multiple representations of the underlying data/state. This is easy enough for read-only data, but when the source data can change, then you’ve got to be thinking about keeping the representations in sync. Skip the fun. Just call the method fresh every time and optimize it when your profiler tells you to.
As always, YMMV.