We are all familiar with the KISS (Keep It Simple, Stupid) and YAGNI (You Ain’t Gonna Need It) principles. And yet, overly complicated software is everywhere.
Let’s use an application server. Definitely. We can’t go without distributed transactions. And a message queue – for the sake of decoupling. Oh, our business logic is likely to include a lot of business rules, let’s go for a rule engine. And an ESB, definitely an ESB – how else will we distribute our multiple modules without making them interdependent? Database? Oracle, of course. But also CouchDB and Cassandra, because relational databases are not good at some things and we will need very high performance. And we need a couple of additional layers. Some facades here and there. And modules – we just shouldn’t have a monolithic application, how else will we be able to reuse our components? You know, let’s try OSGi, it will suit us. Did I forget web services? SOA is so important. And the ESB requires it anyway.
Even if you don’t have designated architects, this is the sort of thing that happens. And each of the things has some seemingly legit reason to be there.
No. YAGNI. You are most probably building business software that will be used by not more than a few hundred users simultaneously. It is probably going to include some business logic and a lot of requirements for reports and statistics. And you don’t need any of the above in order to make a functional, easy to maintain piece of software.
Am I contradicting myslef when saying you should leave technologies and frameworks out, when I previously insisted that frameworks are there for your good and decrease the complexity of software? There’s nothing contradictory. And here’s why: if written properly, software can easily change.
If at some point it turns out you really need a message queue – add it, and replace the synchronous calls in the code with sending a message. If your postgresql/mysql does not perform well with the amounts of data, switch to Oracle. If you start having millions of users, consider Cassandra. Then simply rewrite a couple of DAO classes and you are done. If it happens that you need to integrate with many 3rd party software within the same system, research ESBs. If you realize you copy-paste functionality across projects, extract the common pieces into reusable components.
But not before the need arises. Because this architectural complexity makes it harder and slower to iterate, especially if not everyone on the team is familiar with all the technologies.
Am I advocating for laziness in planning? Isn’t our previous experience enough to let us decide in advance what will be needed? Yes, but only given enough data. And in the beginning of a project you almost never have it.
There are two types of “things” we know we will need. Firstly, utilities. Tools that simplify a task we know we will be doing. An ORM, for example, can often (but not always) simplify our data access. A dependency injection framework can simplify the way our pieces of code interact. And secondly, subsystems. A message queue, a NoSQL database, an ESB are subsystems in a way. They are not intrinsic part of the application, they aren’t tools. They add complexity to the development, configuration, deployment, and it’s our job to estimate whether they will really be beneficial and whether the tradeoff is worth it.
There’s a fine line between the “do-everything-yourself” framework denial attitude and the YAGNI principle. And it is common sense. That’s where our experience comes into play – deciding what are the best tools for the job, and not what tools are cool to use or “probably could help at some point”.
When someone comes to me and says “Let’s use X for Y”, I say: “No. Let’s keep it simple for now. Our existing stack can cover that”. The result is – simpler software. Easier to maintain, easier to introduce new people to. And yet functional.