Preferences

I currently have a big problem with AI-generated code and some of the junior devs on my team. Our execs keep pushing "vibe-coding" and agentic coding, but IMO these are just tools. And if you don't know how to use the tools effectively, you're still gonna generate bad code. One of the problems is that the devs don't realise why it's bad code.

As an example, I asked one of my devs to implement a batching process to reduce the number of database operations. He presented extremely robust, high-quality code and unit tests. The problem was that it was MASSIVE overkill.

AI generated a new service class, a background worker, several hundred lines of code in the main file. And entire unit test suites.

I rejected the PR and implemented the same functionality by adding two new methods and one extra field.

Now I often hear comments about AI can generate exactly what I want if I just use the correct prompts. OK, how do I explain that to a junior dev? How do they distinguish between "good" simple, and "bad" simple (or complex)? Furthermore, in my own experience, LLMs tend to pick up to pick up on key phrases or technologies, then builds it's own context about what it thinks you need (e.g. "Batching", "Kafka", "event-driven" etc). By the time you've refined your questions to the point where the LLM generate something that resembles what you've want, you realise that you've basically pseudo-coded the solution in your prompt - if you're lucky. More often than not the LLM responses just start degrading massively to the point where they become useless and you need to start over. This is also something that junior devs don't seem to understand.

I'm still bullish on AI-assisted coding (and AI in general), but I'm not a fan at all of the vibe/agentic coding push by IT execs.


It’s difficult to do the hard work of you haven’t done the easy work 10,000 times. And we tend to get paid for the hard work.

LLMs remove the easy work from the junior devs task pile. That will make it a lot more difficult for them to do the actual hard work required of a dev. They skipped the stepping stones and critical thinking phase of their careers.

Senior devs are senior because they’ve done the easy things so often it’s second nature.

Fantastic insight. Without doing the easy work, we cannot recognize when it is appropriate, which is more often than not, in my experience. There's also a certain humility to doing things as simply as possible. LLMs lack the self-reflective capability to see that maybe an incremental change to use batching for a write-heavy op shouldn't be 200 lines of code.

Tools can't replace human understanding of a problem, and that understanding is the foundation for effective growth and maintenance of code.

This is what my wife (a hospital pharmacist) thinks too. She has developed her medical intuition on thousands of patients, through education, rotations, residency, years of working, etc. And most patients are straightforward and easy. But it is those easy cases that build the judgement skills necessary to make her so fast and effective when she gets to the hard cases.

Maybe an AI would be better on the easy cases- slightly faster and cheaper. But it would mean that she would never develop the skills to tackle the problems that AI has no idea how to handle.

Exactly this. If a junior dev is never exposed to the task of reasoning about code themselves, they never will know what the difference between good and bad code is. Code based will be littered with code that doe the job functionally, but is not good code, and technical debt will accumulate. Surely this can't be good for the junior Devs or the code bases long term?
To be fair, most startups already trade "works today" for "easier to add stuff in the future", even before LLMs. I'm sure we'll see a much harder turn to the "works today" direction (which current vibe-coding epidemic already seem to signal we're in), until the effects of that turn really starts to be felt (maybe 1-3 years), then we'll finally start to steer to maintainable and simple software again.
I’m not so sure. In the short term, yes, we hear about disasters caused by developers choosing “works today” and the AI almost instantly making a mess…

But that’s the point. The feedback loop is faster; AI is much worse at coping with poor code than humans are, so you quickly learn to keep the codebase in top shape so the AI will keep working. Since you saved a lot of time while coding, you’re able to do that.

That doesn’t work for developers who don’t know what good code is, of course.

> then we'll finally start to steer to maintainable and simple software again.

I disagree. I expect that companies will try to overcome AI-generated technical debt by throwing more AI at the problem.

Already starting to see this attitude online among Pro-AI people

"If the code doesn't work just throw it away and vibe code new code to replace it"

It's something that is... Sort of possible I guess but it feels so shortsighted to me

Maybe I just need to try and adjust to a shortsighted world

> OK, how do I explain that to a junior dev?

They could iterate with their LLM and ask it to be more concise, to give alternative solutions, and use their judgement to choose the one they end up sending to you for review. Assuming of course that the LLM can come up with a solution similar to yours.

Still, in this case, it sounds like you were able to tell within 20s that their solution was too verbose. Declining the PR and mentioning this extra field, and leaving it up to them to implement the two functions (or equivalent) that you implemented yourself would have been fine maybe? Meaning that it was not really such a big waste of time? And in the process, your dev might have learned to use this tool better.

These tools are still new and keep evolving such that we don't have best practices yet in how to use them, but I'm sure we'll get there.

They'll improve, but current LLMs (o3, Gemini 2.5 Pro, lesser ones) are also terrible at suggesting non-obvious alternative solutions on their own. You can sometimes squeeze them, adding each obvious but poor approach to a list of "here are things I don't want you to propose" in turn, but often even then they won't get to the answer they should be able to find. The part that is wildly irritating is that once you tell them about the non-obvious simple solution, they act like it's the most natural thing in the world and they knew it the entire time.

Assuming of course that the LLM can come up with a solution similar to yours.

I have idle speculations as to why these things happen, but I think in many cases they can't actually. They also can't tell the junior devs that such a solution might exist if they just dig further. Both of these seem solvable, but it seems like "more, bigger models, probed more deeply" is the solution, and that's an expensive solution that dings the margins of LLM providers. I think LLM providers will keep their margins, providing models with notable gaps and flaws, and let software companies and junior devs sort it out on their own.

I think this is where functional style and strong types come in handy: they make it harder to write bad code that looks innocent.

In part this is because the process of development leans less hard on the discipline of devs; humans. Code becomes more formal.

I regularly I have a piece of vibe-coded code in a strongly typed language, and it does not compile! (would that count as a hallucination?) I have thought many times: in Python/JS/Ruby this would just run, and only produce a runtime error in some weird case that likely only our customers on production will find...

> I think this is where functional style and strong types come in handy: they make it harder to write bad code that looks innocent.

I'm a proponent of functional programming in general, but I don't think neither types (of any "strength") nor functional programming makes it easier or harder to write bad code. Sure, types might help avoid easy syntax errors, but can also give the developer false confidence with "if it compiles it works :shrug:". Instruct the LLM to figure out the solution until it compiles, and you'll get the same false confidence, if there is nothing else asserting the correct behavior, not just the syntax.

> in Python/JS/Ruby this would just run

I'm not sure how well versed with dynamic languages you are, especially when writing code for others, but you'll in 99% cases cover at the very least all the happy paths with unit tests, and if you're planning on putting it in a production environment, you'll also do the "sad" paths. Using LLMs or not shouldn't change that very basic requirement.

> Our execs keep pushing "vibe-coding"

Imagine if wat (https://www.destroyallsoftware.com/talks/wat) appeared on the internet, and execs took it serious and suddenly asked people to actually explicitly make everything into JS.

This is how it sounds when I hear executives pushing for things like "vibe-coding".

> More often than not the LLM responses just start degrading massively to the point where they become useless and you need to start over

Yeah, this is true. The trick is to never go beyond one response from the LLM. If they get it wrong, start over immediately with a rewritten prompt so they get it right on the first try. I'm treating "the LLM got it wrong" as "I didn't make the initial user/system prompt good enough", not as in "now I'm gonna add extra context to try to steer it right".

This is the same catch-22 LLMs have had since their inception. They're only useful for domain experts who can review their output. Any non-experts using them will never become experts, because they're expecting the LLM to do the job for them. Unless they use the tool as an assistant that explains the underlying concepts, which can also be wrong, and they do the bulk of the work themselves, their skills will stagnate or deteriorate.
I see an analogy to the discussions from my youth about compilers vs. assembly language programmers. It is still true that assembly is required to write high performance primitives, and that a competent assembly programmer will always beat a good compiler on a small function---but a compiler will consistently turn out decent and correct code for the entire project. So, basically, the compilers won, and assembly is relegated to be an important but niche skill.
the word “consistently” in your anecdote is doing a lot of heavy lifting. Generative AI is anything but consistent. A compiler _is_, hence its immense value. Furthermore, even a junior programmer can compile their program and generate robust assembly code, not the case with generative AI.

It’s hard to predict how this plays out IMO. Especially since this industry (broadly speaking) doesn’t believe in training juniors anymore.

It would be kinda cool if we could write pseudocode on a whiteboard or a notebook and have the computer spit out a real program.
Easy, just use one AI to write the pseudocode, and another AI to change it into a real program.

And a third AI to review the pseudocode, I guess.

More seriously, I think that this is generally the correct approach: create a script that the AIs can follow one step at a time; update the script when necessary.

wait a couple of years, the junior will still not know how to code and companies will need someone with experience to fix all the mess $$$

This item has no comments currently.

Keyboard Shortcuts

Story Lists

j
Next story
k
Previous story
Shift+j
Last story
Shift+k
First story
o Enter
Go to story URL
c
Go to comments
u
Go to author

Navigation

Shift+t
Go to top stories
Shift+n
Go to new stories
Shift+b
Go to best stories
Shift+a
Go to Ask HN
Shift+s
Go to Show HN

Miscellaneous

?
Show this modal