A note on the importance of not anticipating future.
During code reviews, I’m extremely rarely under impression that the solution is too simple. Quite the opposite. I usually feel that the code is overcomplicated. Your feel as a reviewer (and potentially future maintainer) is extremely important. This is actually the final test if the author, who spent more time on the problem, was able to express their thoughts clear enough for those who spent less time. Remember accidental complexity and essential complexity? The complexity of the code should come from the complexity of the problem it solves.
- For simple problems – a simple solution that feels simple.
- For complex problems – a more complex solution. And more complex solutions usually don’t feel simple.
So if you think that the code doesn’t feel simple, you’re likely right. Something went wrong. Maybe the author thought that they gonna need something for later.
*Sighs* – they aren’t. This is a slap for YAGNI.
I like when smart people go against this trend (after all, maybe they are called smart for a reason?) For example, see Dan Abramov’s input on the structure of React projects. Don’t start complicated. React could be used in too many cases to have a silver bullet for every project before even starting it.
The same goes for every architectural discussion. Actually, the same goes for every decision in programming. There’s too many variables and moving parts to make a right decision without actually starting coding. Thousands of times I had to recalibrate the initial assumptions after discovering in the code that something doesn’t fit – I bet you can relate.
If you overthink the architecture before writing code, you’re doing it wrong. Architecture is not only what, but (more importantly) – why. Good architecture solves problems. You won’t solve problems if they don’t exist yet. Focusing too much on the architectural analysis, you’d probably make a blind guess. Instead, start simple and iterate.
My observation is – too many programmers don’t really start simple. Why is that? Let’s talk about it. I have three hypothesis.
They want to show off
They don’t want to write simple code, rather they need to create something big and show the world they can do it. They want to grow. Maybe they would feel stupid if spent a day on a solution that is 1 line of code long.
But I would insist – if this is what it takes to solve the problem, go for it. Personally, I have nothing against writing simple solutions, I could do that for the whole career. I feel the obligation to deliver a solution as simple as currently possible. Actually, this is very rewarding for me, if I understand the problem well enough to prove that only one line of code could solve it. I will even go further and praise developers who know which code is safe to delete. The less code, the better.
They have some other goals in mind
We live in a noisy world. There is plenty of advice for developers. We’re supposed to always write elastic code, never repeat ourselves, use the design patterns and whatnot. The Pragmatic Programmer, which I’m just reading, suggests to always write code with concurrency in mind. Every conference speaker has a few pieces of advice for you. I can see why people keep saying such advice. I’m not against any of those rules. Bear with me, but seriously – YAGNI is the one most important principle among them principles. Trading YAGNI for other traits (DRY, clean code, SOLID, consistency, you name it) feels always a bad choice. I elaborated on this topic here.
This is not justification for sloppiness. This is the YAGNI shield for those who demand your code to be complex.
Simplicity is hard
Think TDD. Red -> green -> refactor. Repeat little by little. Taking baby steps is a core of the TDD approach. They will lead you to a better, simpler design. The thing is, taking baby steps is extremely hard. Decomposing the current problem to the next tiny test case, and then solving that test case in the simplest possible way – that feels sick at first. Developers are thought to solve complex problems. When I already have some solution I mind, couldn’t I just write some more down, then write some test to test it? No, you couldn’t. This is against the rules of TDD. You should expend that natural temptation to take advantage of TDD. That laser focus only on a little chunk of the whole problems helps you in rejecting needless, likely false assumptions.
The same mechanism works for everyday programming. The more assumptions you can dispose of, the cleaner, better and still functional code you will deliver.
As a summary, let’s recall about why YAGNI is king:
- People are bad at prediction, especially when business is involved. Are programmers particularly good or bad at that? I don’t know but think about your estimations.
- The effort of implementing something now can become unjustified in the future.
- No elastic solution is ultimately elastic. There’s always something to improve. It’s a never-ending road.
Ladies and gentlemen, I have my little appeal. Stay simple. Like really, really simple. Like in the university, when you didn’t know the design patterns. You will know when you need them (or will get reminded in the code review).