Engineering for Vibe Coders - Ask five basic questions to dramatically improve maintainability
Ask five simple questions with every change to avoid the inevitable, progress-destroying vibe-code sprawl.
If you’re vibe-coding, you’ve probably reached a point where the AI is just terrible at progressing: making tons of mistakes, creating bugs with every change. It really stalls your progress.
What if I told you that with some simple questions, you can slow down getting to that point?
You don’t need to be an engineer to guide the AI (though, I’d recommend it). You can just ask the question and make sure the AI answers.
The key questions:
Why is this named the way it is?
Should this live here?
What if there’s more than one?
Is this the one place this ‘fact’ exists?
Should this know about that?
Why is this named the way it is?
This is the most important thing.
What is something called?
Why is it called that?
The name of the file should impart what it does, scoped exactly to what it does. It should be consistent across the application and be both exactly precise and generic enough.
If you find yourself unable to describe what it does without using the word “and”, it probably does too much and should be in a separate file.
For example:
Sidebar - shows the sidebar navigation links and handles login state
You probably need to move login state somewhere else.
Sidebar - shows the sidebar navigation for admins
You probably need to name this AdminSidebar for precision.
TransactionChart - a bar chart
You probably need to name this BarChart or at least TransactionBarChart.
OverviewPage - shows a set of charts and contains help navigation
You probably need to move the help navigation into its own component
Naming is so critical that I never allow the LLM to name things. I always pick the name.
Ask the LLM:
Why did you name it that, and can you think of a more consistent / cohesive name?
What if there’s more than one?
Suppose you’re making a chart. You prompt your LLM:
“make me a bar chart that shows transaction amounts”
Your LLM dutifully creates you a TransactionBarChart.js.
This is a use-case tied to a specific mechanism: the use case of ‘transactions’ tied to the mechanism of ‘show a bar chart’.
This is a key moment to ask:
What if there’s more than one?
What if you want another bar chart in the future?
This is a signal - you should extract the concept of a bar chart so that one file can serve multiple use cases.
Instead of having TransactionBarChart, UserCountBarChart, all with their own independent logic, you should have a BarChart that you pass in parameters to:
<BarChart title="User counts" data="{seriesLabels: ['Account A', 'Account B', 'Account C'], seriesData: [21,24,31]}" />
<BarChart title="Payments" data="{seriesLabels: ['2024/01/01', '2024/01/02', '2024/01/03'], seriesData: [1000,2333,1284]}" />Pros:
You reduce variability - if you fix a bug in BarChart or add a feature, it’s available for every place that BarChart is used.
You have a consistent interface that you can use for any bar chart - you (and the LLM) does not need to re-create it.
These are called re-usable components. The more you have, the easier it is to maintain your system.
Prompt your LLM:
“What if I need to have another of this in a different use case?”
Should this live here?
You want to achieve cohesion - files should be located close to the things it works with.
eg. a PaymentBarChart should show a chart for payments. It should live a folder called /payments so you can easily find it.
If you had a BarChart, it should live in a /shared/charts folder alongside PieChart and LineChart.
Ask the LLM:
Why did you place this logic in this folder/file?
Is this the one place this ‘fact’ exists?
A big cause of bugs is duplication of facts in a codebase - parts of the code that assert how something behaves, but in different places.
Suppose you had a “Delete note'“ button on a NoteShowPage.js that contains the logic to call an endpoint to delete a note.
Let’s suppose you also add a “Delete note” button on NoteListPage.js that contains the logic to call an endpoint to delete a note.
These are two duplicative sources of truth for the front-end logic of deleting notes. What if the endpoint changes? What if you want to add a confirmation modal to delete a note? What if you add front-end visibility adjustments so only certain users can delete a note? Now, you might have a missed spot. Worse yet - LLMs are prone to repeating the back-end logic too! Now you have four duplications for the same exact logic.
It’s better to have a single “Delete note” button file (eg. DeleteNoteButton.js) that contains the logic, or at least a single “Delete note” service that makes a request to the server.
Ask the LLM:
Is this the only place this kind of logic exists, and should it be centralized?
Should this know about that?
LLMs often optimize for getting the thing done, not for overall system maintainability. That means it takes shortcuts.
As a practical example - an LLM will tie your toilet water plumbing to your kitchen sink because it’s faster than creating a separate set of pipes. The end result - your toilet will flush and your sink will have water - but you probably want them separate.
Likewise, in code, there’s certain things that should just never interact or know about each other. You want to ensure that your code knows the bare minimum about any other code in the system.
If you have an Export record, you don’t want it knowing about Payment records - it’s irrelevant. If you have a BarChart, why should it know about Navigation?
The more you can carve out, the more maintainable your system will be.
Ask the LLM:
Does this really need to be aware of that?
Just five questions will dramatically improve your vibe coding longevity. It’ll also help you sniff out the issues that your AI is creating, long before they start to block progress.


