Designs by Duhart All writing

·5 min read·softwareengineering · vibecoding · ai · coding · programming · webdevelopment · learntocode · developer · tech

Software engineers vs vibe coders: an honest comparison

What AI-assisted building is great at, what software engineering adds around the code, and how to go from one to the other.

Cover slide: Software engineers vs vibe coders. No snobbery, just the gap. An honest comparison from an engineer who uses AI every single day. Two boxes: AI-assisted building gets you to it works fast; software engineering keeps it working after that.

Software engineers vs vibe coders

I use AI to write code every day. It's made me faster, and some days it's made me lazier, which I'll get to. So when people ask whether vibe coding is "real" programming, I don't have a sneer ready. I have a more useful answer: it's real, it's great at some things, and there's a gap between it and software engineering that's worth knowing about.

The gap isn't the typing. Writing the code was never most of the job.

Cover slide: Software engineers vs vibe coders. An honest comparison from an engineer who uses AI every single day.
The carousel version of this post.

The 40 second version

Monday it works on my machine. Friday at 4:59 PM it meets production.
Cover slide: Software engineers vs vibe coders. No snobbery, just the gap. An honest comparison from an engineer who uses AI every single day. Two boxes: AI-assisted building gets you to it works fast; software engineering keeps it working after that.
Monday it works on my machine. Friday at 4:59 PM it meets production. Watch the video: https://designsbyduhart.org/blog/software-engineers-vs-vibe-coders/

What vibe coding is genuinely good at

Credit first, because it's earned.

  • A working prototype in an afternoon instead of a week.
  • Trying three ideas before lunch and keeping the best one.
  • Boilerplate, glue code, config files, and the regex nobody remembers.
  • Learning by building, with a tutor that never gets tired of your questions.
  • People who have never coded shipping real tools for their own work.

That last one matters. If you built something that runs and it helps somebody, you built something. Plenty of engineers started exactly there, copying code they didn't fully understand until one day they did.

Where the gap actually is

Here's what software engineering adds around the code, as I see it.

  • Requirements. Building what was asked for is the start. Engineering asks who it's for, what done means, and what happens at a hundred times the users.
  • Design. The first answer an assistant gives is a design decision, whether you made it or not. Engineering chooses where data lives and what's allowed to change later.
  • Testing. "I clicked it and it worked" checks one path on one day. A test writes down what must stay true, so the next change can't quietly break it.
  • Security. Assume every input is hostile, keep secrets out of the code, and check who is allowed to do a thing, not just who is logged in.
  • Operations. Logs, alerts, backups and a way to roll back at 3 a.m.
  • Maintenance. Code that someone else can read and change in a year.

None of this needs a computer science degree. It needs reps, and it needs someone to point at it, which is the point of this post.

Testing: the demo is the happy path

Ask an assistant for a function that averages some scores and you'll often get something like this. It's correct for every input you'll try in the demo.

Looks done

python
def average(scores):
    return sum(scores) / len(scores)

Then a new user signs up with no scores yet, and average([]) raises ZeroDivisionError. Nothing was wrong with the AI's code for the question it was asked. The question was incomplete. An engineer writes the uncomfortable case down first, then makes it pass.

The test that would have caught it

python
def average(scores):
    if not scores:
        return None
    return sum(scores) / len(scores)


def test_average_of_nothing():
    assert average([]) is None


def test_average():
    assert average([2, 4]) == 3

Security: the AI writes what it has seen

Models learn from a lot of public code, and a lot of public code is insecure. This one works perfectly, and it lets anyone who types a quote into your form read or wreck your database.

Works. Also SQL injection.

python
q = f"SELECT * FROM users WHERE email = '{email}'"
db.execute(q)

Parameterised: the database never runs input as SQL

python
db.execute("SELECT * FROM users WHERE email = ?", (email,))

The assistant will usually write the safe version if you ask for it. The engineering habit is knowing to ask, and noticing when you didn't.

Operations and maintenance: shipping is day one

Most of the life of software happens after the launch post. Before I call something done I ask a few boring questions. When it breaks, can I tell what happened without guessing? Do I find out before my users do? Can I undo a bad deploy in one step? Have I ever actually restored a backup? Who updates the dependencies, and how will I know nothing broke?

The test I use is simple: could a stranger fix this at 3 a.m. with what I left behind?

Debugging when the AI is wrong

The AI is confident, and it's sometimes wrong. Pasting the error back in works until it doesn't, and then you're in a loop where each fix creates the next bug. This is where I've caught myself being lazy. What gets me out is a method, not another prompt:

  1. Reproduce it. If you can't make it fail on purpose, you can't prove you fixed it.
  2. Read the whole error. The line number and the last frame of the stack trace usually tell you where.
  3. Shrink it. Cut the case down until removing anything makes the bug go away.
  4. Check one assumption at a time. Print the value you're sure about. It's often the wrong one.
  5. Then ask the AI, with evidence. Give it the smallest failing case and what you've ruled out. It's a great second pair of eyes and a risky first one.

From vibe coding to engineering

Keep the AI. Add these habits, one at a time.

  1. Read every line before you commit it. If you can't explain it, ask until you can.
  2. Learn git properly. Small commits, clear messages, branches. It's your undo button.
  3. Write one test for the thing that scares you. Then one more every week.
  4. Ask what happens when it fails. No network, bad input, two users at once.
  5. Learn one layer down. HTTP, SQL, how your host actually runs your code.
  6. Keep one project running for a month. Maintenance teaches what tutorials don't.

If you want a structured way to build the fundamentals, I put together a free practice repo with 15 problem-solving patterns, tests and solutions: 15 patterns to make SWE & DSA easier.

Use both

AI is a power tool. Engineering is knowing where to cut. The best people I work with use both: they let the AI type, and they stay responsible for what ships.

If you vibe code, keep going and pick one habit from the list this week. If you're an engineer, teach the habits. Nobody ever learned them by being sneered at.

Which of these habits did you pick up the hard way?

More: LinkedIn · Instagram. Portfolio and case studies: designsbyduhart.org.

If any of this saved you an afternoon, Buy me a coffee.