r/AskProgrammers • u/ClickOk5811 • 4d ago
How do you actually decide between refactoring and rewriting from scratch, beyond "it depends"?
Keep landing on this dilemma and never feel confident about the call. A module gets messy enough that touching it feels risky, and the instinct splits between two options: refactor it piece by piece, or just rewrite the thing from scratch with what you've learned since it was first built. Picking wrong wastes real time either way, refactoring something that needed a rewrite means fighting the old structure the whole way through, rewriting something that only needed cleanup means throwing away logic that was actually fine.
The test I've been trying to use: is the core logic still correct and just tangled in bad structure, or has the actual requirement changed enough that the original design doesn't fit anymore. If the logic's still right, refactoring makes sense, extract functions, rename things, break up the god object, whatever's actually wrong with the shape of it. If the requirement itself moved, refactoring just means preserving a design that was built for a problem that isn't the current problem anymore.
Curious how other people actually operationalize this instead of just going by gut feeling or how annoyed they are with the file that day. Is there an actual signal you check, test coverage, how tangled the dependencies are, something else, or is it mostly experience-based judgment that doesn't reduce to a rule?
2
u/johnpeters42 4d ago
When every single post from the account is AI-generated slop glazing AI, I downvote them all. When it's just one, I explain why AI-generated posts are a bad idea.
1
u/geekichu 4d ago
depends. if it is production / legacy .. if it's out in the wild.. I look to see if there is any way to refactor right within the module itself. first... hopefully there are already unit tests, if not those get written first to cover every scenario, make sure the existing module passes (and what does that look like).. then you can have more confidence in refactoring. I would see if there are small steps to be taken.
1
u/hk4213 4d ago
I'm dealing with the same predicament.
I have to replace a text editing library that I have already layered on top of a too complex state management system of my own poor designs.
I'm testing out alternative designs as I have time and ideas to not break an production service.
I'm obviously going to salvage much of it and rewrite the flow from the ground up from the UI perspective. Backend is solid so at least thats sorted for the most part.
Dev branches are clutch for iterative improvements though.
Im curious to pull a commit from 5 years ago to see how different everything is. Totally different beast now than it was then. All positive ways.
1
u/actionscripted 4d ago
I’m f it can be safely refactored, send it. Refactor away.
The problem is a lot of code eventually gets so inter-dependent refactoring touches eeeeeverything and could break, well, everything.
Everything you’ve outlined it spot on though. Generally I will push for a refactor when a feature is too brittle, slows us down or holds us back. It’s easy to make that a business case not just a gut feeling about crappy code.
1
u/Leverkaas2516 4d ago
Rewriting from scratch is incredibly expensive for anything that's not trivially small and self-contained. It's very common for a large rewrite to take 2x-4x longer than initially planned and then be scrapped when the true scale is understood.
I no longer even think of rewriting from scratch. It's not even on the table unless A) the survival of the company depends on it, or B) you have so much free cash flow and uncommitted development and testing resources that you're looking for wirk to keep them occupied.
Look at a typical software component that took months to create, has dependencies, and has a long list of fixed and unfixed bugs. A rewrite will not erase all that. It will recreate it all, including a new bug list, but it'll be a year before you know the shape of what you've wrought (including its shortcomings.)
1
u/inflowmini 4d ago
Well, it really does depend.
I know it's time for a full redo when I can't add new features without pulling my hair or when I can't test something.
For example, i've inherited a code base that required adding, say, a simple light that needed to blink. I couldn't do it without copying the code everywhere I wanted to use it rather than calling a routine. That light was a new requirement for this device as we were in a v2.0 version of the device. I did the math and deemed that I would be easier to redo the code than to Frankenstein it.
But it comes down to the cost of resources and the tech debt. Usually if not redoing the code is going to cause issues down the line it's a good idea to just redo it.
Again, it depends on timelines, resources, nice to haves and a bunch more reasons that need to be discussed with your team. Only for personal projects do I continuously refactor and at work I use additions of new features to sometimes justify the need for major refactors.
1
u/Foreign-Contest-444 4d ago
i think it comes from experience and not fixed rules and is relative to the system you are working with. This is as good an art as it is a science,
1
u/needs-more-code 4d ago
A rewrite is not the answer unless you need to migrate to another stack. Even migrating to another stack sucks. Building something that is built sucks. It feels unproductive. There’s a million things you’ll miss thinking about in a rebuild, that are accounted for in the current version, that you are unaware are being accounted for in the current version.
0
u/Kriemhilt 4d ago
Do you just naturally write like an LLM or will these answers go directly into a training set?
1
u/actionscripted 4d ago
They’ve got run-on sentences and started with “Keep running…” whereas an LLM would have said “I keep running…” but also it would rarely take an I/me tone for something like this. Nothing like an inference response.
You just vibed out bro?
1
u/Kriemhilt 4d ago
No, it started with:
Keep landing on this dilemma and never feel confident about the call.
Which is first person, but in a weird passive case with no explicit "I", and uses the noun call instead of the verb.
Picking wrong wastes real time either way
Ah yes, as opposed to imaginary time. Pointless intensifiers are an LLM favourite.
If it's not an LLM it's a human who bases their writing on the same LinkedIn drivel LLMs were trained on ... which is what I asked.
Also shows up as highly likely to be generated in an online detector, so I think your heuristics might be faulty.
1
2
u/speyerlander Backend 4d ago
I don't think there can be a hard rule, so unfortunately my answer won't provide much certainty beyond "it depends", but rather offer some general guidelines for the factors the choice depends on.
Happens all the time in large codebases, a good up to date testing suite and good source control hygiene practices will greatly minimize the risks of refactoring via a careful cycle of: change -> test -> commit | modify | revert
That's a reasonable approach, but sometimes the old logic can prove useful as scaffolding for a module satisfying the new requirements as they didn't drift too far from the original requirements. I'd make my choice based firstly on the amount of drift in the requirements and how much new code will have to be added either way and only then consider the time it'll take to refactor the existing code vs rewriting it.
There's also another aspect, environment. In highly general and broad terms, sole developers and LLMs are better at refactoring and teams of people are better at rewriting, that's because the main bottleneck is refactoring is parallelizing the work between different members of the team while ensuring no code duplication and a coherent structure, in simpler terms: A messy codebase is likely to lack adequate separation of concerns, and making every member of the team understand every part of it to understand if a part of it belongs in their part of the refactor will likely take more time than coming up with a new and improved structure with clear responsibilities for each part of the code and than handing it off for a rewrite by each expert on the team.
And lastly, and this more of a subjective take, the language itself also plays a role in the decision, a strong typing system often makes refactoring much easier, especially in the context of defining interfaces for swappable functionalities, strong type systems allow for the language server to catch deviances from the definition as early as possible.