@bmused, I know your pain all too well. Much of it for me stems from stunning WTF code I've had to deal with in various places. It's professionally embarrassing to foist crap on others. There are even 2 times I recall begging the team lead to refuse to allow some code into the system. Oh well; ultimately delivery trumps quality even when code is acknowledged as bad. The code we all have to deal with proves it.
Motivations
- A good Scout always leaves his camp site better than he found it. Amen.
- It's still better than the existing horror.
- Fun. Good design makes coding easier and more fun.
- Avoiding pain, both self and boss inflicted. I simply learned to let good enough be. That was hard, and I must always be on my guard on this.
- A "continuous improvement attitude" allowed me to not worry so much up front.
Good, thoughtful, complete, design up front is extremely important. Don't try to be too smart for your (and our) own good. I'm not saying "elegant", "brilliant", "slick implementation of obscure language features", etc. I'm saying complete, straight forward, Object Oriented. Fight for the time to make a decent design prior to coding.
A good design naturally lends itself to "good enough" coding that lets you sleep at night. You Code Complete (a play on a must have book title) so you simply don't worry so much about inventing places for future extension. And being "complete" there's less urge to keep fussing with it.
I had 2 very different experiences w/ the same code base. The well designed one more than anything completely defined business domain classes to cover the requirements; it was criticized by PEBCAK OO-ignorant co-workers for "too much", "too busy" - but it coded easier and faster (you may be surprised how much time you seem to have for improvements during coding!), and sailed through testing in days. Compared to the other time where design was incompetent at best and we were stuck in a 3 month test-fail-hack cycle of hell. Imagine how you might feel about getting it absolutely perfect next time given these two experiences.
Continuous improvement is a happier place. Get your new code good enough and as opportunities present themselves make improvements.
- One's code base is either getting worse or getting better; continuous improvement or bust.
- Making improvements later, in the face of known changing requirements, or just time to have thought about it is much preferable to second guessing every potential future change up front.
- Consciously prevents over engineering in anticipation of changes that never come - my pet peeve is the interface implemented by only one class. An innocent thing you'd think but I see it way too many times and IMHO in a large code base every pointless, unhelpful bit is painful.
Good refactoring practices along with unit tests is the way to implement continuous improvement. I very highly recommend Refactoring by Martin Fowler.