Or: I Accidentally Invented a Way to Make Computers Program Themselves Because I Got Tired of Explaining Things Three Times
Look, I'm going to be honest with you. I built an entire campaign management system—email automation, AI filters, scheduled triggers, the whole nine yards—basically by myself. How? Well, I fired three contractors trying to build it before I realized I could do it myself. By "myself" I mean I got GPT to do it while I ate chips and occasionally typed "looks good, continue."
I haven't actually read the rest of this post yet but I'm pretty sure it's genius. Here you go.
You know what the worst part of programming is? Programming. You sit there, you type the things, you fix the bugs, you type more things, and then Dave from product comes in and says "actually can we make it send emails too?" and you have to type MORE things. It's exhausting.
I tried hiring people. The first contractor built something that worked great until you tried to use it. The second one wrote code so beautiful that no one, including him, could understand what it did. The third one just kept saying "that's not possible" to everything, which was weird because I'd already built a prototype in my head while he was explaining why it couldn't work.
Then I had a thought. A dangerous thought. The kind of thought that either makes you a genius or unemployed.
What if instead of writing code, I just... described what I wanted really well?
Here's what happened. My boss—let's call him Steve because that's his name—Steve says "the PRs are too big, I can't review 47 files at once." Fair point, Steve. So I need to break down this massive campaign system into tiny, reviewable pieces.
But here's the thing: I'd already built the whole system. Then I had to tear it down to make it smaller. Then I had to rebuild it piece by piece. Do you know how annoying it is to unbuild something just to rebuild it again? It's like unpacking your entire house just so you can pack it again but in smaller boxes.
So I'm sitting there with two git branches—one with everything, one with nothing—and I'm thinking: I need to document what each piece does so I can rebuild it properly.
And that's when it hit me.
Instead of writing code, I started writing specifications. But not boring specifications like "The system shall provide user authentication in accordance with RFC 2617." No, I wrote specifications like this:
Hey, we need email campaigns to work.
Look at commit 7506177cb where I deleted all the email stuff.
That was the working version. Build something like that.
But here's the thing:
- It needs to use Google OAuth (the professional has to connect their Gmail)
- It should generate personalized content using AI
- Don't make it weird
Success = emails get sent and no one complains
Then I fed this to Claude/GPT/whatever LLM wasn't rate-limiting me that day, and you know what? It just... built the thing.
After doing this about 50 times (because Steve wanted 50 small PRs apparently), I noticed a pattern:
- Describe what you want like you're explaining it to a smart but literal alien
- Point to examples of similar things that already exist
- Explain the weird constraints that only your system has
- Let the LLM figure out the boring parts
It's like having an extremely intelligent intern who never gets tired, never complains about the coffee, and never accidentally drops the production database (though they will absolutely create infinite loops if you're not specific enough).
You want to know the secret? LLMs are better at reading code than writing it, and they're better at writing code when they understand WHY they're writing it.
Traditional approach:
def authenticate_user(username, password):
# 47 lines of authentication logic
# that you copied from StackOverflow
# and don't really understand
Specification-driven approach:
We need to check if this person is who they say they are.
We store passwords as bcrypt hashes (cost factor 12).
If they fail 5 times, lock them out for 15 minutes.
Steve from security insists we log everything.
The LLM reads this and goes "Oh, you want secure authentication with rate limiting and audit logging" and then writes better code than I would have because it's actually read the bcrypt documentation.
Here's a fun story. I needed to add location-based filtering to the campaigns. You know, "send this email to everyone in ZIP code 90210" kind of thing.
So I write this specification:
Add location filtering using ZIP codes.
Users should be able to click on a map to select ZIPs.
Make it work with Google Maps because we already pay for that.
The LLM builds this entire system with:
- Interactive map component
- ZIP boundary service
- GeoJSON data pipeline
- Caching layer
- Search functionality
- Export feature
I didn't ask for half of that stuff, but apparently when you tell an LLM to "make it work with Google Maps," it assumes you want it to work WELL with Google Maps.
The kicker? It worked better than the version the third contractor said was impossible.
Let me put this in perspective. Before specification-driven development:
- Monday: Write authentication code
- Tuesday: Debug authentication code
- Wednesday: Rewrite authentication code
- Thursday: Meeting about authentication requirements
- Friday: Rewrite authentication code again
After specification-driven development:
- Monday morning: Write authentication specification
- Monday afternoon: Review and tweak LLM's implementation
- Rest of week: Build four other features
I'm not exaggerating. I built more features in one month than I had in the previous six. And the best part? When Steve asked for documentation, I just handed him the specifications. They WERE the documentation.
There's good lazy and bad lazy. Bad lazy is copy-pasting code you don't understand. Good lazy is building systems that do the work for you. Specification-driven development is galaxy-brain lazy.
Level 1 Lazy: Copy code from StackOverflow Level 2 Lazy: Write a script to generate boilerplate Level 3 Lazy: Use a framework that does most of the work Level 4 Lazy: Hire someone else to do it Level 5 Lazy: Describe what you want and have AI build it Level 6 Lazy: Have AI write the specifications too (I'm working on this)
Okay, I should probably mention the failures too. One time I wrote this specification:
Make the emails stop going to spam
The LLM's solution? It built an entire email reputation monitoring system, implemented SPF/DKIM/DMARC authentication, added engagement tracking, created a warmup sequence, and built a fallback system that would try different email providers if one got blocked.
Which would have been amazing except we were just testing locally and the emails were going to spam because I had "TEST TEST TEST" as the subject line.
Sometimes being too helpful is unhelpful.
Here's what I learned about writing specifications that actually work:
Be specific about the vague parts:
- Bad: "Make it fast"
- Good: "Response time under 200ms for 95th percentile"
Be vague about the specific parts:
- Bad: "Use a for loop with index variable i incrementing by 1"
- Good: "Iterate through the list efficiently"
Always include the why:
- Bad: "Add a 5-second delay"
- Good: "Add a 5-second delay because the API rate limits us to 12 requests per minute"
Point to examples:
- Bad: "Build authentication"
- Good: "Build authentication like we did in user_controller.rb but without the OAuth part"
You know what's funny? We spent decades trying to make programming languages more like human languages. COBOL literally tried to be English. Then we gave up and accepted that computers need precise, formal languages.
And then LLMs came along and suddenly we CAN program in English. We just needed computers that were smart enough to figure out what we actually meant when we said "make it work."
The irony is delicious. We've gone full circle. Programming is now just explaining what you want to someone who happens to be a computer.
When Steve asked me how I was suddenly so productive, I showed him the numbers:
- Before: 5 developers, 40 story points per sprint
- After: Me + GPT, 120 story points per sprint
Steve: "But what if the AI makes mistakes?" Me: "What if developers make mistakes?" Steve: "..." Me: "At least the AI's mistakes are consistent."
The real killer feature? When a new developer joins, instead of spending three weeks reading code to understand the system, they read specifications that actually explain what things do and why. Revolutionary, I know.
Look, at the end of the day, Specification-Driven Software Engineering isn't really about AI or automation or any of that buzzword stuff. It's about admitting something we've all known forever:
Writing code is the easy part. Knowing what code to write is the hard part.
We just finally have tools that can handle the easy part for us. So we can focus on the hard part: figuring out what we actually want to build.
And occasionally, we can focus on the really important things. Like eating chips.
Fine, here's how you actually do this:
- Write specifications like you're explaining to a smart friend who's never seen your codebase
- Include context about your weird technical decisions
- Point to existing code that does similar things
- Let the LLM write the first draft
- Review it like you would review a junior developer's code
- Iterate until it works
- Save the specification because it's now your documentation
That's it. That's the whole thing. You're welcome.
I started this journey trying to break down a big system into small PRs for Steve. I ended up discovering that if you're lazy enough, you can trick computers into doing most of your job for you.
Is this the future of programming? Probably. Will it put us all out of jobs? Nah, someone still needs to write the specifications. And more importantly, someone needs to explain to Steve why the AI decided to implement a distributed blockchain solution when all we needed was a database flag.
But here's the thing: I'm building more, faster, and better than ever before. And I'm doing it by being so lazy that I convinced a computer to be productive for me.
If that's not peak engineering, I don't know what is.
P.S. - I had GPT write most of this post too. I just specified what I wanted it to say. Meta? Maybe. Lazy? Definitely. Effective? You tell me, you just read the whole thing.
P.P.S. - Steve, if you're reading this, I was kidding about the chips. I was eating pizza.
Make the emails stop going to spam
Make the emails stop going to spam
def authenticate_user(username, password):
# 47 lines of authentication logic
# that you copied from StackOverflow
# and don't really understand
We need to check if this person is who they say they are.
We store passwords as bcrypt hashes (cost factor 12).
If they fail 5 times, lock them out for 15 minutes.
Steve from security insists we log everything.
Add location filtering using ZIP codes.
Users should be able to click on a map to select ZIPs.
Make it work with Google Maps because we already pay for that.
Hey, we need email campaigns to work.
Look at commit 7506177cb where I deleted all the email stuff.
That was the working version. Build something like that.
But here's the thing:
- It needs to use Google OAuth (the professional has to connect their Gmail)
- It should generate personalized content using AI
- Don't make it weird
Success = emails get sent and no one complains
def authenticate_user(username, password):
# 47 lines of authentication logic
# that you copied from StackOverflow
# and don't really understand
We need to check if this person is who they say they are.
We store passwords as bcrypt hashes (cost factor 12).
If they fail 5 times, lock them out for 15 minutes.
Steve from security insists we log everything.
Add location filtering using ZIP codes.
Users should be able to click on a map to select ZIPs.
Make it work with Google Maps because we already pay for that.
Make the emails stop going to spam