Skip to main content

When Your AI Feels Like a Junior Dev: The Growing Pains of Vibe Coding Tools

· 6 min read
Kenneth Jiang
Founder, Hacker

When Your AI Feels Like a Junior Dev

When Your AI Feels Like a Junior Dev: The Growing Pains of Vibe Coding Tools

Introduction

Have you jumped on the "vibe coding" bandwagon yet? If you haven't heard, vibe coding is all about coding alongside AI assistants like Cursor and Claude. These tools promise to make your coding smoother, faster, and maybe even a bit more fun. Sounds great, right?

Well, mostly. The reality is, sometimes my AI sidekick feels less like an expert coder and more like that enthusiastic junior dev fresh out of bootcamp. They're eager, helpful, and… prone to rookie mistakes.

Let me dive into some entertaining real-world examples showing how my vibe coding tools sometimes patch symptoms instead of truly solving problems.

Why Junior-Level Fixes Are a Big Deal

Every engineer knows the drill—junior devs have a knack for band-aid solutions. The code might "work," but lurking underneath are hidden tech debts, sneaky bugs, and the dreaded surprise outage at 2 AM. Unfortunately, many AI code assistants today behave exactly this way, fixing superficial symptoms without touching the root cause.

Example 1: The Mysterious Trailing Slash Bug

I encountered a production issue caused by an extra / at the end of a GET parameter. Here's the prompt I initially gave to Claude:

"A GET call to the prod server with URL http://app.obico.io/unsubscribe_email/?list=account_notification%2F&unsub_token=%5BFiltered%5D results in a KeyError: 'notify_on_account_notification/'."

Claude's initial diagnosis seemed straightforward:

Based on my analysis, I understand the issue. Here's what's happening:

  1. The unsubscribe URL contains list=account_notification%2F, where %2F is a URL-encoded forward slash (/).

  2. In the unsubscribe_email function in web_views.py, line 210, it's trying to access a field named notify_on_account_notification/ which doesn't exist in the NotificationSetting model.

  3. This exception occurs because the forward slash in account_notification/ is being treated as part of the field name.

Claude immediately proposed this band-aid solution:

# Strip any trailing slashes from email_list to prevent field lookup errors
email_list = email_list.rstrip('/')

It seemed decent, but something bothered me. I thought the real issue might be elsewhere, so I asked Claude:

"This URL should be generated by our own code. Can you check if the root cause is with the code generating this list=account_notification/?" Upon further investigation, Claude found the real culprit:

Now I found the source of the problem. Let's look at the code in __init__.py line 136-138 where the unsubscribe URL is created:

...

The issue is right there. The mailing_list variable used in this URL is created at line 95:

...

For account notifications, the value of mailing_list becomes account_notification/ with a trailing slash.

Claude then provided the proper fix:

# Strip any trailing slashes from mailing_list to prevent URL parsing issues
clean_mailing_list = mailing_list.rstrip('/')
unsub_url = syndicate.build_full_url_for_syndicate(
f'/unsubscribe_email/?unsub_token={user.unsub_token}&list={clean_mailing_list}',
user.syndicate_name)
ctx['unsub_url'] = unsub_url

headers = {
'List-Unsubscribe': f'<{unsub_url}>, <mailto:support@obico.io?subject=Unsubscribe_{clean_mailing_list}>'
}

🚨 Pro Tip: Always trace bugs back to their source; don't just patch the surface.

Example 2: The Case of the "Undeleted" Printer

Here's another fun one I faced—a deleted printer inexplicably returned from the grave whenever a print job finished. Here's my initial prompt to Claude:

I run into a mysterious issue in production: a deleted printer will be undeleted. I was able to reproduce it and found out that this happens when a print from the deleted printer finishes. I suspect this is caused by a bug in a code that is triggered at the time when a print finishes. help me figure out the bug.

The related server log is:

...

Claude responded confidently:

The bug is in the unset_current_print method of the Printer class, which is called when a print finishes.

In the server logs, I found that when a print from a deleted printer finishes, the code was setting deleted = NULL in the printer record, effectively undeleting it. The issue is that the unset_current_print method didn't check if the printer was already deleted before saving it.

...

The fix I implemented checks if the printer's deleted field is set before saving it. If the printer has been marked as deleted, the method returns early, skipping the save() call and subsequent operations. This prevents the deleted printer from being unintentionally restored when a print finishes.

Claude initially proposed this quick fix:

# Don't save and trigger printer events if this printer has been deleted
if self.deleted:
return

However, something felt off. I replied:

I don't think your fix works, because "self.deleted" must have been "null" and that was why "self.save()" caused the "deleted" field to be set to null. I suspect this is because "self" is a stale object with "delted" still being null

Claude quickly realized the mistake and revised the solution:

You're absolutely right. My initial fix wouldn't work properly because the self object could be stale, with its deleted field still being null even though the printer has been deleted in the database.

The issue is that when we call self.save(), it overwrites all fields in the database with the current values in the object, which would include setting the deleted field back to null - effectively un-deleting the printer.

I've improved the fix by adding self.refresh_from_db() before checking the deleted status. This ensures we're working with the most current database state of the printer, including its accurate deletion status.

Here's Claude's corrected fix:

# Correct fix: refresh from DB first
self.refresh_from_db()
if self.deleted:
return

😊 Pro Tip: Always double-check your object's state before hitting save.

Light-Hearted Best Practices for Working With Your Junior AI

So, my vibe coding assistant has some growing pains. No worries! Here are some friendly best practices I've found helpful for navigating these quirks:

  • Always trace bugs to their source. Superficial patches mean future headaches.
  • Refresh from the database. Keep your objects current before modifying them.
  • Test first, fix second. Writing a test that reliably fails and then passes with your fix ensures real solutions.

Remember, your AI assistant is a teammate—enthusiastic but occasionally overconfident. Like a good senior dev, your oversight helps your digital junior dev avoid rookie mistakes.

Conclusion: Rookie Moves and Human Smarts

So there we have it—a humorous yet cautionary tale about today's vibe coding tools. While AI coding assistants are brilliant at handling many tasks, their occasional slip-ups remind us why human oversight remains essential.

As I've seen firsthand:

  • Symptom-only fixes scream "junior dev!"
  • Real debugging means going back to the root cause.
  • AI can speed up your workflow, but you're still the brains behind the operation.

Have a hilarious or cringe-worthy AI coding fail to share? Drop your best "AI did what?!" moments in the comments! Let's laugh, learn, and commiserate together.