I want to comment in this post on my position in favor of simplicity in software development. If I have learned anything in this century, it is that simplicity really is beneficial for what we program.
Many times in the past few decades, I have come across systems that have been encoded in complicated ways. At first, I thought that maybe it was necessary to do it this way: over the years, I have realized that this is not always the case.
By some inclination that we programmers have, we tend to complicate a solution more than we should. There are projects that end up being a Rude Goldberg machine
When the same use cases could be covered using a simpler way:
Benefits of Simplicity
Simplicity can be easily understood: A two-gear machine is simple, and so it’s easy to understand. Instead, a 67-gear machine can be challenging to understand.
Simplicity can be change: if a system has few components, and the relations between them are clear, then it could be changed with low effort.
Simplicity could evolve: as a consequence, the evolution of the system is easy. We could add more functionality in “baby steps”, preserving the previous behavior, and adding new ones.
Simplicity could be adapted: if the business changes, if there are new objectives and new use cases, a simple solution could be adapted to the new environment easily. And this is aligned with one the agile movement motto: embrace the change.
Departing from Simplicity
There are many decisions that could generate the abandon of simplicity in a solution. Some of them:
Trying to be fast: one the sins of software development. Ie adopting a framework to increase the velocity of development, without having enough context about its defectiveness for the problem at hands.
Early adoption of technology: like adding a library to solve the next use case. And this decision has the additional appealing of feed our egos: now we are using the library L, a popular one, every other project is using it. What can go wrong? A concrete example: solving a use case, a team adopted a relational database with tree capabilities (keep a tree of relations between rows). Everything went well, the first weeks. But when they received new requirements, they started to realize that they need a GRAPH of relations between entities instead of a TREE. But now, they have a lot of logic adapted to manage a tree of entities. They never had the courage to switch to a solution more oriented to a graph (easily obtainable using simple relations, like in any relational database9 instead of a tree, and they started to add myriad of trick to adapt the existing tree to act as an arbitrary graph.
Pursue a “pie in the sky” solution: having to solve the use cases, a fanciful solution is adopted, but it is not simple: it tries to solve the present problems, but also the coronavirus pandemic and the peace of the world, all in one. Abandoning the “baby step” way of doing things, the proposal add so many complications that the project is doomed.
Aversion to simple solution: do you need to invert a matrix? Why to code? They are a plethora of math libraries that solve the problem. And then, you add a library which solves the use case, including calculus and quaternions, instead of a “baby step”: code an initial solution, few lines of code, to invert the matrix involved in the current use case. Then, in the future, if the use case evolves, maybe you can change that decision. But taking the decision of adding the library NOW maybe is not the best path. A concrete example: given geoposition data, a team should resolve the position of the user. It could be solved in 40 lines of python. But they took another path: use a relational database that have geoposition operations. But in these days, the chosen database had that features as experimental, so you need to recompile the database management software. And it should be compiled in a controlled environment, so to comply with all these issues, the team adopted a docker distribution to have all the required software in place. Remember: the simple alternative was to write 40 lines of python. After a year, all the development was tied to use a docker, to comply with this use case, that at the end, IT WAS NOT USED, because the original use case was replaced by other, and the geo positional data was not important at all.
Give me a dollar for each solution that went complicated without a compelling reason, only due to bad decisions, and I would be rich.
Recommended lecture: Worse is Better.
Angel “Java” Lopez