O, complexity, the god of so many IT and R&D departments! Thou providest people job security, self-esteem, and sometimes very nice bonuses (that’s in the case of financial institutions).
Recently I’ve heard that a company I used to work for couple of years ago, conducted massive lay-off, closing whole departments which were working on “very complicated software”, with a whole “process” of SDLC and automated testing and a lot of other things… It wasn’t public company, all right, it had a private owner, and the owner just wondered at some point, what are all those people are doing, except of spending his money in a complicated economy like we have today.
I’ve been through projects with a lot of legacy code, and I’ve been starting projects from scratch, big and small projects, in companies big and small, on different platforms, OS’s, frameworks, etc. The same pattern persists everywhere: people just love to over-complicate technical problems.
People might have different motivation, of course: some just try to make their boss happy, others crave “universal” solutions, but the result is always the same: in couple of years, normal turn-over of human resources creates a situation when nobody really can understand what’s going on with a huge amount of code, databases, scripts, and so on.
Complexity is bad.
It’s very bad. It’s something that removes the substance and replaces it with a “process” of “figuring out” the substance (if any). Financial instruments called “derivatives”, all those CDOs and CMOs were way more more complex than stocks or commodities, and we all know what happened to banks which had built their businesses around those instruments. But reports those banks were presenting along the way were never bad. They were, well… complex.
There is another term for complexity in software world: we call some designs “over-engineered”. In many cases the over-engineering is caused by an attempt to make design more flexible, universal, and thus is becomes very configurable and flexible and customizable… but 90% of that customization is never used.
In other cases, excessive complexity comes to existence, when the original design wasn’t well thought through. This is actually the more “classic” scenario, described in all the smart software engineering books, and as such, it’s not seen too often in serious big projects.
And complexity is created by people. Same people also fail to figure out later on, what that complex solution is doing. Managing complexity has very little to do with computer science and even computer engineering. It’s 90% psychological problem.
Typically, engineers have good intentions. They want to get their job done really well. They are trying to foresee any scenario, anything that might go bad. That’s why they try to keep things flexible. And to keep it flexible, they need a dynamic object management, and some universal platform running their business logic, and some tools which are “industry standard” for that platform, and so on, and so forth… Sooner or later it leads to spaghetti code or spaghetti configuration, or (most likely) to both.
My bottom line is: first, the complexity is bad, and second, complexity is created by people.
Some Rules of Thumb
It’s probably not enough to proclaim the holy principles of DRY (Don’t Repeat Yourself), KISS (keep it simple, stupid!) and YAGNI (you ain’t gonna need it!). We are serious people, all right, engineers, programmers, we are educated and all this, so let’s take a look on some concrete recommendations:
1. Solve Only the Problem At Hand. Don’t try to solve the problems of the entire world. Don’t try to look too far in the future (well, unless this is part of your requirements, of course). Most businesses today are short-sighted, and so are their business needs. If you are late because of planning something for “tomorrow” — well, there might not be any “tomorrow” for your project.
2. Use Simple Programming Techniques. It’s quite simple, all right: it should be a good reason, to use complex over simple, custom over standard, and so on. If you want to use multi-threading, double-check whether you really need it. If you want to create additional interface or implementation, to derive another class, use another level of encapsulation — make sure it’s really necessary.
- avoid multithreading, unless the task at hand requires it
- avoid adding extra levels of indirection
- avoid adding classes
- avoid adding functionality, unless real business needs demand it
- avoid creating another table in your database
- avoid creating another field in your table
- avoid… just anything! be lazy! minimize the amount of your code!
3. Keep Your Design Simple, Your Components — As Detached As Possible. Meaning, while solving task at hand, don’t forget that it might change, if your clients change their mind. You won’t have a problem to “refactor” your code at any moment, if it may be easily decomposed to smaller components.
4. Neither DRY, KISS, or YAGNI are absolute principles. The Great Dao of Laziness is. If you can make something small, concise, serving its exact purpose – do it. Most complicated designs with “future needs” in mind end up so complicated that they don’t work for those future needs either, and then the whole thing requires some huge re-factoring to be performed. Remember: impossible to see the future is! (C) Yoda
And the last, but not the least:
5. Think twice before using 3rd party component. Use it only if its learning curve is minimal.
And of course, if you have on your agenda something which is not simple, elegant, easily maintainable design — feel free to print a hard copy of this article and toss it to garbage.