As little as possible 🪶
When it comes to software development, I have a personal motto that I try to live by.1
Do as little as possible, as well as possible.
Just as the sentence has two parts, it connects two ideas. To create small solutions, but keep quality high. These ideas both complement and contradict each other, which makes for an interesting balance.
Create small solutions #
During my 20+ years as a software developer, I’ve never experienced a situation where we run out of work to do. Usually, the backlog is long and ever-growing.
Because there is much to do and time is limited, it makes sense to solve problems as quickly as possible. We should strive to solve problems, even big ones, with an as small solution as possible. Don’t buy a table saw, when a hand saw will suffice.2
Creating small solutions means both reducing the product scope, as well as choosing simple technical implementations. Not only will this produce a simpler solution, we also get to ship it earlier, get real user feedback faster, and react to changes quicker.3
Resist the temptation to make the solution “better” by adding features. Unless what you’re building is essential to solving the original problem, don’t do it. If you start building things speculatively, you will get it wrong more times than you will get it right.4
Writing small solutions also has the benefit that it produces less code to maintain. There are fewer places for bugs to hide, and you get more time to improve the product. This creates a compounding effect, much like interest on interest. Think of code as a liability – the less you have, the better!
Keep quality high #
What I have experienced too many times during my career, is that people cut corners in an attempt to save time, only for them to have it come back and bite them.
One of the most common ways to cut corners is to skip writing automated tests. Sometimes we do this because writing tests takes time, and sometimes because the code is hard to test. Both are likely to come back to haunt us, but especially the latter is a red flag, as it indicates that the design probably is not quite right.5
Another common, but less obvious, way to cut corners is to not think enough about the software design and architecture. When short on time, we often build the first idea that comes to our minds. That is likely not the best one. Our solution becomes a house of cards, and a fragile foundation for future changes.6
Better together #
The nice thing about the ideas above is how they complement each other.
By reducing the scope, we deliver features sooner and receive faster user feedback. With a smaller technical implementation, there is less code to write tests for, and we get more time to think of a proper design. By keeping solutions small, we are less likely to introduce complex tools that will dominate and constrain our technical solution.7
By keeping quality high, we make it easier to extend the product. The design is simpler and easier to modify, and greater test coverage allows you to make safer changes.
To sum it up, I believe smaller solutions lead to faster completion and higher quality. Sounds pretty nice, doesn’t it?
-
For a long time, I prioritized “as well as possible” over “as little as possible”. Truth to be told, I maybe even did not include “as little as possible” at all. But over time I’ve realized that smaller solutions have so many benefits. ↩︎
-
In both product and technical design, you may want to ask Does this scale down? ↩︎
-
Reducing scope and simplifying implementation is also similar to what I write about in Focused commits but on a higher level. ↩︎
-
I try to express my ideas on only building what you need right now in my earlier posts Design for today and Will it be harder tomorrow?. ↩︎
-
How tests can help us detect code that is not well designed is also discussed in Testable code is reusable code. ↩︎
-
It is still important to Plan for tomorrow, to know that you can build something small without working against your long-term plan. ↩︎
-
I write more on the value of keeping technical solutions simple in Use boring technology. The post Abstractions on communication also elaborates on the idea of avoiding premature generalization. ↩︎