KISS (Keep It Simple, Stupid) is one of the single best and most general pieces of advice you can give a developer. It seems that we’re genetically predisposed to overcomplicating things. From the C programmer trying to come up with best way to twiddle bits to the ASP.NET programmer coming up with a caching strategy, we over-optimize all of the time. We build solutions to problems that don’t exist and may never exist. (The best example I saw of this was an exercise in internationalising a web application which had a problem domain that only applied to the UK. Never has YAGNI been more appropriate.)
The problem is, many developers don’t really seem to understand the meaning of the phrase “Simple”. Like design patterns, I’ve too often seen KISS quoted to justify frankly bad designs.
“Simple” doesn’t mean quite the same thing as “a trained monkey could do it”. “Simple” is about expressing things in a direct fashion, which isn’t quite the same thing as being easy to understand. Programming is a fundamentally logical profession, and some people don’t really handle logical entailment very well. You will not be improving your code by expressing it in such a way that you try to accommodate them. Equally, some developers aren’t really up to speed with modern techniques, such as dependency injection and ORMs. If you thought that “simple” meant not using modern tools, you should probably be programming in COBOL (or C++, for that matter).
The objection that you often get when someone first encounters NHibernate or nServiceBus is that it all seems too complex. Davy wrote a series of articles on how to write your own ORM. Does that mean that NHibernate is overkill and you can junk it? Well, consider this: Davy is a project committer and cares deeply about its future.
The problem is, when you start with NHibernate, the requirement to override Equals and implement virtual methods seems like a royal waste of time. It’s only when you understand the problems it’s trying to solve that you start to regard these requirements as being natural. Now, I’m not here to re-open build versus buy yet again, I’m pointing out that “simple” is a function of your problem domain. And your problem domain is nearly always larger than you think it is when you start a new project.
Make Complexity Explicit
Okay, I’ve finally managed to edge up to my point. I’ve encountered a number of phenomenally complex systems over the years that were held together by pieces of string. Each of these was designed that way in an incremental fashion. A CSV export there, a URL rewrite rule, all slowly built up into a system that absolutely no-one understood. The worst of it was the decisions were made with good intentions. The desire for simplicity drove the design to purgatory.
The problem is, simplicity can’t be evaluated on a case by case basis, it has to be done holistically. Some things are hard, and some things are complex. Sometimes you can replace a hard problem with a simple one, but sometimes it’s essential complexity. In these cases, it’s better to recognize that and make it explicit in the design than to try to shove it away. When everyone does that, the complexity doesn’t disappear, it just becomes implicit in the interaction between your components. Any solution that involves the words “side-effect” or “magic” isn’t simple, it’s just deceptively complex. Keep it simple, but keep it smart as well.