I was handed a pile of vibe code. And you might be surprised to learn that it has a ton of bugs.
And tips on how to dissect it and break it up into something manageable?
Nature of the code? Library, CLI tool, cloud service, API, UI?
My first thought is test suite.
Of course! Vibe coding is a popular activity nowadays and *** thinking ***
For work, or for hobby?
Hobby: have AI document what it’s supposed to do, then work through it like the ship of theseus one function at a time replacing it with not bad code.
Work: use it, document the bugs, ninja in and clear them out one at a time until it works. Keep blinders on and ignore anything not directly related to each bug. Same strategy as legacy code.
For work. The code goes like 8 levels of abstraction. I’m trying to figure out how to unravel it.
Even a code flow/branching diagram would help I think
Depending on the language, there might exist an automated tool for generating those kinds of diagrams from code.
The problem with this approach is twofold.
- The AI doesn’t know what anything is either. It can annotate faster than you, but if it is all wrong, that doesn’t help.
- The primary reason the code is bad, and something the AI is particularly weak at without a human doing much of the thinking for it is architecture. Working your way through ship-of-theseus-style isn’t going to address the fundamental reason the code is difficult to work with. The architecture.
Handed to review, handed to maintain, handed to extend?
Primary maintainer …
The same as taking over any legacy project applies, really.
Start out with some expectation management - the current state of the solution prevents progress from going fast, and your stakeholders need to understand that.
Then get some tests going, such that you can try to defend whatever value the system has, if any.
Finally, start refactoring as much as you can get the space to do. Repeat until the system reaches your desired state.
Vibe code it a bit further, then pass it back. If they can hand you slop without second thought, why shouldn’t you?
I did this recently. Here’s how I made it sane:
- clone it to a branch
- concatenate every line of code and paste it into an LLM with a prompt asking for a summary of the issues with the code
- make a TODO list so you can work from that (a .md file of the LLM’s output)
- use that list to aggressively delete the dead code while compiling it with each change
- committing each change that keeps it working while also paring it down.
- keep starting a new LLM session with each change and the same “make a detailed analysis of the issues with this code” prompt with it along with the newly concatenated code (this helps a lot to keep hallucinations down)
- at some point, more cosmetic deletions/changes won’t be necessary and you can start carefull refactoring the code that is actually connected to something while also compiling then committing at every working change.
- then you can start using the LLM as an assistant but actually USING YOUR BRAIN to decide how to fix the architecture and flow of the code. Of course you can ask for advice but ALWAYS keep in mind that the LLM will give you stupid advice and tell you you’re a genius and blow smoke up your ass if you’re too shy to ask a real person (like I am).
- If it’s a language like Haskell or Rust or Purescript, you’re in for an easy time. If it’s something ubiquitous but dynamic and unsafe like JavaScript or Python, GOOD LUCK!!!
I think the biggest problem with vibe-coding is when someone doesn’t take the time to understand the WHY of the changes the code is making. This is why I can’t abide agentic access to my code. Every change must go through me. I won’t even let the AI give me files , preferring to get everything in front of me.
I guess despite how intimidating it seems, un-fucking vibe code can be approached just like every other complex programming problem: by breaking it down into smaller problems and solving them incrementally.
Definitely. Also once it starts to take actual logical shape, showing it to real people is also great if you have that luxury (which I don’t). :)
Yeah. I want to do something like this. I was hoping to run a proper dead code analysis first.
But this is a good idea. For how to reduce the code volume. I need to reduce the abstraction layers because there are a bunch of unneeded ones
LLM’s really helped me with this. I am now working with only code that is wired up and can ask for insight into my ideas while being highly skeptical and lucid about any advice.
I’ve found prompts that make sure to use words like “idiomatic” can prevent LLM’s from going off the reservation to some extent. It’ll try and reinvent the wheel or pull in hallucinated libraries if you’re not careful but it’ll probably also be aware of the idiomatic way to do things in each language.
Have fun and take a walk if you’re getting burnt out.
I’ll sometimes send my concatenated code in, ask for advice, then paste that advice into my phone to have it read aloud to me as I walk around. It can go into insane detail. So as long as you stay skeptical of it, it can be a really good tool for what you’re trying to do.
Start by separating the files by namespace and class. Then, by method. Delete the first method, then the next, and so on. Then rewrite the code by hand as God intended.
Cry in the bathroom
I just cry at my desk and tell them it’s because AI is so beautiful
Unironically get Opus to get you a base of a flow document based on the code so you can figure it out.
Then of course, you dig in yourself, understanding what Opus said, then fiflling in the gaps.
Edit: I don’t think you need to pay for Cursor to prompt Opus once for this. Just make sure to use Opus, Auto picks the dumbest model available on free tier.
Document the features and requirements, then rewrite it with proper architecture and without LLMs.
Depends on the size of the pile. If it’s huge, then you have to use LLM too, with some decent tooling like Claude Code. Let it analyse the code first, and put a summary for you. Then design the proper solution yourself, and either fix it manually, or if it’s too tedious, guide LLM to apply the changes for you. Ofc iteratively and don’t let it apply changesets without your approval. I had a similar task recently, did it like that
Fighting fire with fire. I like it.
You need the problem space to be restricted to a manageable bunch of classes. If that’s not the case, split the problem until you get there.
Make sure you have 100% test coverage on this piece of code and that the tests are actually understandable and documenting the functionality well. You might find that there is unreachable code which should be deleted. Mutation testing may also help find code paths which are untested (and so edge cases you might not have considered).
Until that is true, write tests and/or refactor existing ones. At this point you may find a ton of new bugs there. Better find this now than later and then wonder whether your own changes introduced them. Your new failing tests will document the presence of those bugs.
By now you should have full documentation of what the code is supposed to do via tests. This will be tremendously helpful in understanding the code.
Then go public method by public method, line by line, renaming variables, extracting private methods etc. Your basic run-of-the-mill refactoring of classes, until you fully understand what’s going on in the production code.
For every small refactor, run the tests and commit if they pass. If they fail, you only have a small amount of uncommitted code which you know is the culprit.
Finally, fix any bugs you documented in the test writing stage.
At this point you can add any new functionality to the code.
“Working Effectively with Legacy Code” by Michael C. Feathers
In my opinion, we treat it the same as any spaghetti code
An absolute must have for any software engineer. Whether they think they work wirh “Legacy Code” or not.
Ask AI to do this for you.
So that it fixes one bug but adds 5 more.
You could try the Mikado Method. It is good for disentangling code with a mess of complex interdependencies.





