Back

Growing Pains

One of the things I avoided early on in my internship was using AI coding agents, because I didn't want to be labelled as a vibe coder.1

vibe coding

/vɑɪb ˈkəʊdɪŋ/

noun (informal)

The practice of building software by describing what you want in natural language to AI and iterating on the output based on feel — trusting the AI-generated result without necessarily reading or fully understanding the underlying code.

But building VOIS Connect with a team of six meant I had no choice but to start using them. I went from tab-completing single lines to handing an agent entire tasks pretty quickly. There was no going back after that.

I was getting through authentication flows and tenant provisioning in an afternoon when either one would've taken me a couple of days on my own. Agents felt like a superpower.

With Great Power

Then, I started looking at all the pull requests. We were all on different editors, using different models, and none of us had agreed on any conventions.

I remember opening a PR where every function and variable followed a different naming convention from the rest of the codebase. Everyone's agent had its own way of doing things.

The code worked. It just didn't look like it came from the same team.

lib/api/user-service.ts+4 -4
18 unmodified lines
19 const session = await validateSession();
20
21- const userProfile = await fetch_user_profile(session.user_id);
21+ const userProfile = await fetchUserProfile(session.userId);
22 return userProfile;
51 unmodified lines
74 const payload = await collectUsagePayload();
75
76- const requestBody = BuildUserPayload(config, payload);
76+ const requestBody = buildUserPayload(config, payload);
77 return requestBody;
41 unmodified lines
119 // Retry logic for flaky upstream
120
121- const retry_limit = 3;
121+ const RETRY_LIMIT = 3;
122- return fetchWithRetry("/api/user", { retries: retry_limit });
122+ return fetchWithRetry("/api/user", { retries: RETRY_LIMIT });
28 unmodified lines
Examples of some naming inconsistencies and their fixes.

It took a few weeks of this before I started to change how I worked. The tools stayed the same, but I started spending a lot more time talking to the agent.2 Going back and forth until I actually understood the problem, not just the solution.

Osman's Law

As Osman would constantly say:

“What you put in,is what you get out.”

Osman Mah, Director of Optik Consultancy

He was talking about effort, but it applies just as well to agents. Every time I got a bad result, I could trace it back to what I asked for. I'd say “fix this bug” and the agent would change something unrelated, leaving the original problem untouched.

Before I even open the chat now, I try to think about what I'm actually asking for. It doesn't have to be perfect, but the clearer I am, the less time I spend going back and forth.

Even the best prompt only gets you so far, though. The tooling around the agent matters just as much.3

Staying in the Loop

The other thing that became clear pretty quickly is that you can't just review the output at the end. You have to be paying attention while it works. Reading the agent's reasoning, watching the decisions it makes in real time, and catching it early when it starts heading somewhere wrong.

Here's what this looks like in practice:

Press send to queue the message. Then press steer to redirect the agent!

It's easy to let the agent run and just check the result at the end, especially when you're moving fast and everything looks fine.

For smaller things, that's usually okay. But for anything with real complexity, I found it worked better to break the task into smaller pieces and check in between each one rather than reviewing one big chunk at the end. You catch problems earlier, and you spend less time untangling something that went wrong three steps ago.

If you can't explain what was implemented, you were just approving code not engineering it.

Of course, none of this matters if you don't understand what you're building in the first place.

Full Circle

A few weeks in, we had to stop development and rethink our architecture from scratch. We'd skipped the part where we actually understood what we were building, and the code showed it.

There were seven steps between a sensor reading and it showing up on a dashboard, and we'd only really thought about the first and last.

The thing is, I'd already been taught how to avoid this: requirements gathering, specification documents, system design. It's the engineering process they teach you at uni, and I didn't take most of it seriously.

Everyone wanted to start building. Me, my teammates, the client. Sitting down to understand what we were building and why felt like it was slowing us down. But, the code was never the hard part.

I spent the first few weeks worried about being called a vibe coder.
I spent the rest learning what it actually meant to be an engineer.

engineering

/ˌɛndʒɪˈnɪərɪŋ/

noun

The practice of using natural science, mathematics, and the engineering design process to solve problems within technology, increase efficiency and productivity, and improve systems.

Acknowledgements

I learnt more in my time at Optik than I ever expected to. Having the chance to work with an actual client on a single, difficult project for three months was something I'm really grateful for.

Shoutout to my team — Rami, Khaled, Samer, Yazan, and Yeakin. Watching us go from a group of strangers to a team that could deliver what we did is something I'm really proud of.

Special thanks to our client, Nathan of VEPRM, who trusted a team of interns with such an important project. Hearing that we exceeded his expectations at the end meant a lot.

To the Optik management team — Osman, Jasmine, Johnny, Mikey, and others, whose ongoing support allowed us to thrive.

To the friends I made along the way. Team Valorica — Rahma, Nathan, Dylan, James, Julia, Nam, Steven, Yash. Team Alliga — Rim, Riddhima, Dan, Erin, Helen, Kevin, Randi, Varun. Kaung of Team Cochlear, Kristy of Team 365 and Ryu of Team MidCoast 2. Thanks for letting me annoy you when I was bored and needed a break.

And to everyone else at Optik I crossed paths with, even briefly. Even the small moments stuck with me.

Thanks to Adil for proof-reading and providing feedback.

The visual style of this article was inspired by the works of Benji Taylor, Emil Kowalski, and Shu Ding - Design Engineers who I admire greatly.

Footnotes

1There's nothing wrong with vibe coding. It's genuinely exciting that anyone can build tools they never could have before. But I think there's a difference between building something for yourself and building something meant to serve thousands of people.

2Literally. I would argue with the agent using Wispr Flow.

3Plan mode, custom instructions, skills files, MCP servers, etc.