There comes a time when your projects are delivered, your schedule is free, and you’re unburdened. Life rewards you for the work you put in your last project, and then your manager assigns you a project, a project not to be developed but to be finished and delivered because the developer of that project just quit. Ah, f —
This is not just a one-off story; it’s a tale of my experience with inheriting software, and all of those times, the circumstances were not exactly favorable; less than desirable to be honest, but here is how I overcame those obstacles and took ownership of software which was envisioned beyond my knowledge or understanding. These pieces of software were both backend projects, both monoliths, but with wildly different frameworks (Laravel Vs Node + Express), different languages ($PHP vs TypeScript: language), different opinions (MVC vs API), different databases (SQL vs NoSQL), and different legacies (legacy software vs MVP). I received almost no KT for these projects and was thrown into a deadline I was unsure of myself, but I commenced.
1. Okay, so what is all this then?
A crucial part of developing software is to understand it. So I commenced, bravely into the codebase, where the battle awaited me. I could see it through the files, sense it through the syntax, that I was in trouble.
Signs of trouble:
Verbose comments —> BOT
Poor indentation —> ?? Why, also 4 tab spaces is the right indentation
Deeply nested code
500-line functions
Code Identity crisis —> Functional OR OOPS, PICK ONE
Functional programming —> can work, just a nightmare to inherit
Comments describe the code better than the code itself
ONE BLOCK ONE STOP METHODS —> Everything, Everywhere, All at once
The list could go on, but at that point, I felt like I couldn’t. But there was more, the database mess.
2. How does this even work?
The local SQL DB has a table, which I was primarily working with, which had about 200+ columns. No normalization, no foreign keys, no relational storage, just one raw, unfettered data.
But you know what though? I will still take that over NoSQL databases. To build one your own is one thing, to see the JSON and incoherent objects just casually somehow co-exist is mentally scarring.
3. We need a new feature by tomorrow.
You scramble for understanding, you scramble to fix, you scramble to implement, but ultimately what there is, is all there is for you. I won’t shy away and say I did the job perfectly, no, I stumbled, I fell and I lifted myself back up. I was able to set up some basic features and scaffold them but what I lacked in infrastructure knowledge of the codebase, I couldn’t make up for it with integrity, so I relied on AI to help me understand features and implement things faster. It wasn’t something I was proud of but clients don’t care for your developer integrity and deadlines don’t wait.
I faced two different problems in those softwares.
The legacy software was bugged with verbose methods, incorrectly implemented logic, one-stop-everything methods which blocked the whole operation. I had to optimize the code and refactor a lot of bad logic.
And, in the MVP, when I did start understanding the software better and read through the actual code. I noticed a lot of flaws and cognitive dissonance of the software from its requirements, the AI in that system was never properly implemented and even critical responses were hard-coded. I had to refactor entire systems which as wrong as they were, were the backbone of the whole project and risk a lot of backwards compatibility with a failing system. I’d stay up late, cursing my predecessor for my inheritance.
I was thrown in these situations unprepared but I knew, what wouldn’t kill would make me stronger. So I moved forward.
4. Refactoring Hell
For the legacy, I threaded through each method, abstracted the functionalities away, and implemented new logic to fix the broken system. I inverted nested loops, reduced inflated code, made reusable functions, implemented new methods of mapping over inbound data, and optimized the overall system. Even with new features, I ended up reducing the total number of lines of code. I also configured prettier into the project, which saved my life.
And for the MVP, I went through every code block, abstracted my way through those 500-line methods, redesigned the entire system. I reimagined my predecessor’s (mostly Claude Code, I think) design to fit better to the requirements. I experimented with new logic, shifted development from a bare machine instance to a Docker instance to have a reliable development and deployment pipeline.
5. Post-refactoring hell
After all that it took, I made it out, sanity intact, and projects working as expected. I looked back. Sometimes when I was in need of a new feature to support the system, I could find its implementation in the old code. It wasn’t perfect, but it was there, and I would be lying to say I did and made everything. Maybe the devs before me had their reasons, I don’t know, but they did contribute to a project which I finished.
What I learned:
1. Be Un-opinionated: Don’t let your presumptions color your opinion; focus on building your own understanding of the system.
2. Understand what there was before you decide to tear it apart:
Especially in the early stages, you will want to rebuild the system in your image; don’t; you’re not there for that; sometimes that can end up complicating things more.
3. Adapt to your environment: Just because it’s not your style or preferred method of doing things, doesn’t mean you shouldn’t adapt to it; the system was built in a certain way by your predecessors; understand why and continue to maintain a consistent system. Several other people in your team rely on it, and unpredictability can cause chaos.
4. Before you implement something, understand how it will affect the rest of the system: Sometimes you will find an incomplete implementation of it or a different implementation of it in the system, and there can be other components or systems which rely on it, and an abrupt change can cause backwards compatibility issues.
5. Don’t judge your predecessor: Hypocrite for me to say this after the whole article complains about the systems, but it really just goes on to color your opinion of the system itself, and that causes you to underestimate the system, which can eventually cause unnecessary work and refactoring.
6. Don’t rush, let it happen: I think it is critical for you to not panic and take your time with getting comfortable with the software and the dev environment. This is eventually better for the long term; panic is the biggest enemy of productivity.
We are Software Engineers, we live, grow, and learn. Challenges make us who we are, and I think Succession of Software ends up teaching us much more than we give it credit.
Top comments (2)
Love it!
You sound like a pro
Thank you!!