It happens a lot. You spend hours and hours planning, scoping out, and eventually building a feature or product, only to realize you never really needed it in the first place.
I recently vibe-coded a "product" that I called PingPanther (clever, I know). I told myself it would be a better SmokePing. For those not familiar, SmokePing is a self-hosted DNS performance analyzer.
I like DNS, and I like knowing my latency is low. I like telling people that "…my Starlink connection is around 20 ms ping!" only for them to ask me what ping is and why I cared.
So naturally, I convinced myself that SmokePing wasn't good enough. The UI was dated (it was), the configuration was annoying (YAML would be better, obviously), and it didn't have the fancy real-time charts I wanted. Classic engineer move: "I can build this better."
I jumped into Cursor and started small. My first prompt was something like:
I want to build an alternative to SmokePing. I want to use Kubernetes to deploy the workload. I want to visualize the data with Grafana. I want to use Prometheus to serve up the data to Grafana.
After a few seconds of "thinking," the Cursor agent said "no problem, let's go," and it proceeded to spit out a lot of files.
Right away, I realized that in mentioning Kubernetes, Grafana, Prometheus, etc., I had put the cart before the horse. I needed to work backwards and give it the actual language I wanted.
After a few hours of battling with the Cursor agent, I decided that it was looking pretty good and I needed to have another Cursor agent check my work so far (agents get biased over time, and sometimes it takes a hard stop and restart for them to find holes). The second agent scanned over the code, made some suggestions, and I let it cook.
Finally, I started a third agent. This time, the instruction was to make sure everything adhered to best practices and security standards. Newsflash: it did not adhere. REFACTOR TIME!
After round three, I decided that the app was "good enough" to deploy to my production environment. I asked the agent to give me a summary of what the app did:
PingPanther is a modern network latency monitoring tool, inspired by SmokePing, built with Go for efficiency and designed to run natively on Kubernetes. It regularly pings specified network targets (using ICMP, HTTP, or TCP), collects latency metrics, and exposes them in Prometheus format for monitoring and visualization in Grafana. It is highly configurable, supports production/development/HA deployments via Helm charts, and comes with pre-configured Grafana dashboards. The tool is intended for easy integration into Kubernetes environments and is suitable for both simple and advanced network monitoring use cases.
Actually pretty cool! I love Kubernetes, so I developed this along with the agents to be annoyingly Kubernetes-native.
The Go application, more specifically:
Starts up
Parses command-line flags for config file and metrics address
Loads YAML config (targets, intervals, ping type, etc.)
Initializes Prometheus metrics and the pinger service
Starts an HTTP server exposing
/metrics
for Prometheus scraping
On a timer (interval from config), for each target:
Pings using the specified method (ICMP, HTTP, or TCP)
Collects latency, packet loss, and success/failure data
Updates Prometheus metrics
Logs results
In my humble opinion, it's actually pretty logical. Time to package it up into a container and deploy to Kubernetes!
You deploy PingPanther to Kubernetes using Helm, configure your monitoring targets in a values file, and integrate with Prometheus and Grafana for visualization.
Easy enough. So first, I installed the kube-prometheus-stack. Next, I manually added the Grafana dashboard that was auto-generated. And finally, I was ready to deploy this thing with Helm.
And that's when I realized there were no actual Kubernetes Helm charts or manifests. The directories had been created, but there were no files in them.
Not to worry—I chided the agent and pointed out the missing files. After searching the repo thoroughly for a few seconds, the agent realized I was right and spat out a bunch of manifests, Helm charts, and README files.
Okay, let's deploy this thing.
Deployment failed. The GHCR repo is private and requires a secret to access it (my fault for not realizing it). Fixed.
Okay, let's deploy this thing.
Deployment failed. The pod is crash-looping. Let's look at the logs. Some dependency issues, it seems. Let's add Dependabot. Dependabot added. Dependabot opens 10 PRs for out-of-date dependencies. PRs merged. Actions failed. More troubleshooting. Actions succeeded and image is pushed to GHCR. We are ready.
Okay, let's deploy this thing.
The deployment succeeds, kind of. Pods are running. Logs look good. Service is there. But Grafana is empty. No worries, let's wait a few minutes.
10 minutes later (runs are every minute), Grafana is empty. Let's troubleshoot. Troubleshooting done. Helm upgrade.
Helm upgrade failed. Let's troubleshoot. The PVC is ReadWriteOnce, so a rolling upgrade won't work. Fix some manifests. Helm upgrade succeeds.
The app is live. Finally.
So is vibe coding simpler/better than regular coding and will it take over?
I really think at the core it's a time-based argument:
Time to scope out the project and spit out the files: about 1 hour
Time to troubleshoot the issues with the application: about 2 hours
Time to troubleshoot the issues with the deployment: about 1 hour
Total Time Creating: 1 hour
Total Time Troubleshooting the Creation: 3 hours
So let's talk about that 1:3 ratio. One hour to create, three hours to fix. That doesn’t sound very productive to me.
You spend an hour with an AI agent and boom; full Go application, Kubernetes manifests, Helm charts, Grafana dashboards, the works. In your mind you are now a 10x Dev.
But this apparent simplicity is hiding complexity underneath. You haven't actually solved any real problems; you've just pushed them all into the future.
In the real world, you write a function, you test it, it works (or doesn't), you move on. Linear progress. But with AI generation, you get this dopamine hit upfront, then reality sucker-punches you for the next three hours (or days).
Does that mean I am against vibe coding. Absolutely not. I was able to create a Go application without knowing Go that well. That’s pretty cool.
The core of the problem is, after all this, you end up with an application you didn't really design. Sure, it works, but it's full of patterns and decisions that aren't yours. The simple prompt you started with has spawned a complex system you don't fully understand.
And all this brings me to a great quote that I relate to engineering:
"Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away."
~ Antoine de Saint-Exupéry
Maybe I should have just written a 10-line bash script and run on a kube cron job.
Cheers,
Joe