Good Enough Sometimes Is Not Good Enough
Tolerance for Bad Code Has Gone Too Far
Recently, the tolerance for bad code has gone too far.
There are four origins of this attitude.
The first one is a pure fact of laziness/apathy.
Developers often take shortcuts, opting for quick fixes rather than investing time in creating robust solutions.
Most of the time, it is not even about the complexity, but because of the additional steps to make the code truly maintainable.
Maybe you have to create another branch, document it, create a ticket, write tests, or even refactor existing code. There is always something in a way.
The second, more recent reason is the introduction of AI into the development process.
While AI can enhance productivity, it can also encourage a mindset of complacency, where developers rely on AI-generated solutions without fully understanding or refining the underlying code.
This way you are getting AI slop into the codebase, which can cause problems in future and furthermore potentially dangerous vulnerabilities.
The third reason is the pressure to deliver results quickly.
When you are pushed to deliver, there is often a strong emphasis on speed and meeting deadlines. This can lead to a culture where taking shortcuts is not only accepted but expected.
It must work, no matter the cost.
The fourth reason is the lack of knowledge
Sometimes, you are locked in an environment where you don’t have all the information or resources you need to make the best decision. This can lead to a suboptimal solution, which is good enough for engineers building the solution, but would not be accepted in general.
The team lives in echo chambers, reinforcing their own beliefs and approaches without considering alternative perspectives. Or maybe, they just do not know better.
The Hidden Cost
You can take the shortcut and move to another item on the list. But what is the cost of that decision?
The hidden cost of taking shortcuts is often paid in the form of technical debt. This debt accumulates over time, making the codebase harder and harder to work with.
Let’s do small math. Hypothetically, if you take one shortcut per week, that is 52 shortcuts a year.
Not every shortcut will cause you problems, but let’s be generous and say 10% of them will.
That means you are introducing 5.2 issues/workloads into your codebase every year without accounting for the time spent making honest mistakes along the way.
Some issues can take you hours to fix, while others might take days or even weeks. Let’s say on average, each issue takes you 2 days to resolve.
In the end, you are wasting every year 10.4 days just to fix problems you could have avoided in the first place.
You can multiply it by the number of developers on your team to get a sense of the overall impact.
This is purely hypothetical, but it illustrates the point that shortcuts can lead to significant long-term costs.
The project pays the price later on by worsening performance, rising technical debt, and potentially introducing security vulnerabilities.
AI Can Boost Your Productivity at a Cost
Please do not take me wrong, I use IDE coding assists all the time now.
However, many people do not take into consideration their own skills when generating the code.
If the code is generated, it does not mean the code should be exempted from the code quality rules.
All the generated code should be refined and assessed by you to make it to the codebase.
Usually, after one or two more queries, you can get to the result which you desire.
A couple of tips to improve the generation:
- define the rules, which the code assistant should abide by
- give it similar files as templates, which should be used
- define the expected result in the query
None of the above is that hard to do, and it can instantly create better code.
The Morale Long-Term Costs
The impact of shortcuts extends beyond just time and resources. It can also affect team morale.
A crumbling codebase suddenly becomes a nightmare to work with.
Developers love to tinker and improve the code, but when they are constantly fighting against a messy codebase, it can lead to frustration and burnout.
It does not bring any novelty or excitement to the work at all. The joy of problem-solving is replaced with the repeated task of cleaning up messes or dealing with the fallout from shortcuts taken earlier when building new features.
Other Domains Suffer Too
The good enough approach compounds in other domains.
Here are examples:
- every layout is a tiny bit off (UX)
- unaligned UI components (UI)
- unclear or missing documentation (Knowledge)
- reliance on outdated libraries or frameworks (Tech)
- lack of automated tests (QA)
It is not only about code quality, but also about the overall health of the project.
When different domains suffer from the good enough approach, it can lead to a decline in the project’s overall quality and maintainability.
What Can You Do About It?
I apply the “Good Boy Scout Rule” - always leave the codebase cleaner than you found it.
Even if the changes are not directly related to the task at hand, I take the time to address any technical debt I encounter along the way.
See the issue? Fix it. Do not ignore it. Do not wait for someone else to take action.
You are the professional, it is your duty to do the right thing. No one else will do it for you.
I doubt that the reviewer will be against fixing the issue. They might even appreciate the effort.
Mainly, do not apologize for fixing the issue or taking the time to do it right.
If you have good reasons to believe that fixing the issue will benefit the project in the long run, then go ahead and make the change.
This falls into other aspects of the project. During the planning phase, be vocal about the importance of doing things right from the start.
You will be surprised how many people will agree with you. Usually, they did not have the will to speak up or thought it was not worth the effort.
When Good Enough is Actually Enough?
You could get the feeling that everything must be perfect. Quite the contrary, sometimes “good enough” is all you need.
The key is to recognize when “good enough” is truly sufficient. This often depends on the context and the specific requirements of the project.
Here are a couple of examples:
- You are building a prototype and need to validate an idea quickly - glue it together, show it off and iterate.
- You want to build side hustle projects. Do not over-engineer them - they will probably not see the light of the day.
- You build something for yourself or a small audience, where the stakes are lower.
- When a tinderbox solution is advantageous in comparison with a flamethrower approach - over-engineering is not worth it.
- Or you have millions of dollars at stake.
The truth is that “good enough” can be a valid approach in many situations. However, if the project lifts off and gains traction, it may require a shift in mindset and a commitment to quality.
There is nothing wrong with starting from scratch and building a solid foundation if the current one is not sustainable.
The needs of the project shifted, and maybe the initial approach is no longer sufficient.
All the frameworks lead to Rome.
At the beginning, take your go-to framework and stick with it. When success is achieved, you will get resources to improve it.
Socials
Thanks for reading this article!
For more content like this, follow me here or on X or LinkedIn.