Lately, I’ve been working on a legacy codebase. Went from annotations to XML, nice CI/CD flows to manual deployments, and just a general sense of slowdown.
Honestly, it’s been frustrating. It feels like I’ve gone back in time. Productivity has dipped, and I’ve found myself constantly comparing everything to how things should be done.
But after some time in it, I’ve started seeing the value (maybe something is wrong with me). There are lessons here you don’t often find in greenfield projects.
You take your time, write beautiful code, architect things properly, test thoroughly, polish it all… and then users will come. Right?
Wrong.
Businesses don’t care about clean code (I’ve read this particular line a hundred times but it’s different to see in practice). They don’t want to hear about how elegant your architecture is. They want working software. Now.
Frameworks solve problems. That’s their job. But when learning to code, you might adopt a framework without questioning why it was done like this. We just get on with it. But now I get it. Without frameworks, you spend days debugging some config issue. Just use the boring, stable stuff that’s already solved this. You’re not here to reinvent how logging or configuration management works.
This isn’t a weekend side project where you’re the only person writing code and answering to no one. In real teams, multiple developers work on the same codebase, and when something breaks, the product needs to give clear answers. The tech we choose should be reliable, easy for the team to work with, and ready to scale with the product (and also resume worthy).
None of this means throwing best practices out the window. You will write messy code sometimes. You will adopt bad practices to meet deadlines. But push back when you can. Fight for code quality.
Bad code might help you ship faster today, but it’ll slow you down tomorrow. So strike the balance, ship fast, but ship right.
Set team guidelines. Enforce shared standards.
Make it easier to stay clean even when the pressure is high.
Before building any feature, make sure you’ve got the basics in place:
It sounds obvious, but when you skip this, everything gets messy later. And the later it gets, the harder it is to fix.
One thing I’ve started to believe strongly: a good developer also needs to think like a product owner. Not entirely, but enough to know why we’re building something and who it’s for.
Sometimes we go too deep chasing “developer happiness”, refactoring endlessly, over-engineering systems, polishing internals that users will never see or care.
But the job isn’t to write perfect code. The job is to solve the right problem for the product. To know when to stop coding and start shipping.
I still prefer clean code. I still care about structure and readability and tests. But I’ve stopped expecting everything to be perfect from day one.
Most of the bad code is because of business constraints.
It’s easy to dive into greenfield projects or well-architected codebases. But navigating legacy, messy code teaches you patience and the importance of meditation.
And one last thing, If you’re writing bad code because of business constraints, congratulations, your startup just hit product-market fit.