DEV Community

Cover image for AI Can Write the Code. But Can You Prove It’s Correct? — The Skill Every Developer Needs in 2026
Robert Adamson
Robert Adamson

Posted on

AI Can Write the Code. But Can You Prove It’s Correct? — The Skill Every Developer Needs in 2026

AI Can Write the Code. But Can You Prove It’s Correct? — The Skill Every Developer Needs in 2026

AI can now generate a feature before you finish explaining it.

You describe an API endpoint.

A few seconds later, you have the controller, service, database query, validation, tests, and maybe even the Docker config.

It compiles.

The tests are green.

The UI looks fine.

So the code is correct… right?

Not necessarily.

And this may be one of the biggest changes happening in software engineering right now:

Writing code is becoming cheaper. Proving that code is correct is becoming more valuable.

This isn't really a new engineering principle.

Professional software teams have always relied on review, testing, security analysis, CI/CD checks, monitoring, and other forms of verification before trusting software.

What AI changes is the amount of code we can produce before a human fully understands it.

That makes verification a much bigger part of the developer's job.


The AI Coding Paradox

Developers are adopting AI quickly.

The 2025 Stack Overflow Developer Survey reported that 84% of respondents were using or planning to use AI tools in development, and 51% of professional developers said they used them daily.

But something interesting happened at the same time.

Only 33% said they trusted the accuracy of AI output, while 46% actively distrusted it.

And the most common frustration wasn't:

"AI can't write code."

It was almost the opposite.

66% reported frustration with AI solutions that are almost correct but not quite. Another 45% said debugging AI-generated code could take more time.

That "almost correct" category is dangerous.

Obviously broken code is easy.

You see the error.

You fix it.

Almost-correct code is different.

It looks professional.

It uses sensible variable names.

It follows your framework conventions.

It may even pass the tests.

And somewhere inside it is one assumption that isn't true.

How Professional Software Teams Actually Prove Code

There is an important distinction here.

There is no single universal rule saying:

"Every American software company must follow exactly these seven steps."

Startups, banks, defense contractors, SaaS companies, healthcare organizations, and small agencies operate differently.

But mature engineering organizations tend to converge around the same idea:

Code is not trusted merely because somebody wrote it. Evidence has to support it.

In the United States, NIST's Secure Software Development Framework describes practices such as reviewing or analyzing human-readable code and testing executable code to identify vulnerabilities and verify security requirements.

NIST specifically discusses techniques including:

  • peer code review
  • static analysis
  • automated analysis
  • review checklists
  • recording discovered issues
  • executable testing

CISA's Secure by Design guidance similarly recommends practices such as peer review, SAST, DAST, unit testing, and integration testing as complementary techniques rather than treating one check as sufficient.

That's the mindset we should bring to AI-generated code.

Not:

AI → Merge

But:

AI → Understand → Verify → Attack → Review → Observe → Merge

Here's how.


Step 1: Verify the Requirement Before the Code

This sounds obvious.

It isn't.

Suppose you tell an AI agent:

Create an endpoint for deleting a user's account.
Enter fullscreen mode Exit fullscreen mode

It generates:

DELETE /users/:id
Enter fullscreen mode Exit fullscreen mode

The implementation might be technically perfect.

But what was the actual requirement?

Should users permanently disappear?

Should records be soft-deleted?

Do invoices have to remain for accounting?

What happens to shared workspaces?

What happens to API tokens?

Should the user receive an email?

Can an administrator restore the account?

Does deleting an account violate another data-retention requirement?

The AI can produce perfectly valid code for the wrong specification.

So before reviewing implementation details, ask:

What assumptions did the AI make?

I often find this question more useful than:

Is this code correct?
Enter fullscreen mode Exit fullscreen mode

Ask instead:

List every important assumption you made while implementing this feature.
Enter fullscreen mode Exit fullscreen mode

You may discover that the model assumed:

  • authentication already exists
  • IDs are globally unique
  • deleting related records is safe
  • the API is internal
  • transactions aren't required
  • the operation cannot race
  • the database schema is different from reality

That is your first verification layer.


Step 2: Understand the Diff

This is where AI coding becomes dangerous for inexperienced developers.

An agent changes 17 files.

You read the summary:

✓ Added authentication
✓ Updated schema
✓ Added validation
✓ Added tests
✓ Fixed lint errors
Enter fullscreen mode Exit fullscreen mode

Looks good.

Merge.

No.

The summary is not the implementation.

If you're responsible for the pull request, you should understand the important changes.

You don't necessarily need to memorize every generated line.

But you should be able to explain:

What changed?

Why was it changed?

What data flows through it?

What can fail?

What permissions does it require?

What external systems does it touch?

What happens when it fails halfway through?

If you cannot explain those things, your confidence comes from the AI's writing style rather than engineering evidence.


Step 3: Compile and Type-Check Everything

Start with the cheap checks.

For a TypeScript project that might mean:

npm run typecheck
npm run lint
npm run build
Enter fullscreen mode Exit fullscreen mode

For another stack it could include:

dotnet build
Enter fullscreen mode Exit fullscreen mode
cargo check
Enter fullscreen mode Exit fullscreen mode
go vet ./...
Enter fullscreen mode Exit fullscreen mode
python -m mypy .
Enter fullscreen mode Exit fullscreen mode

AI often generates code that looks syntactically reasonable while misunderstanding:

  • library versions
  • interfaces
  • nullability
  • generics
  • framework APIs
  • configuration
  • imports

Compilation doesn't prove correctness.

But code that cannot compile has already failed one very inexpensive proof.

Automate this in CI.


Step 4: Don't Ask Only "Does It Work?"

Ask:

"How Can I Break It?"

Suppose AI writes:

async function transferMoney(
  fromAccount: string,
  toAccount: string,
  amount: number
) {
  await debit(fromAccount, amount);
  await credit(toAccount, amount);
}
Enter fullscreen mode Exit fullscreen mode

Happy path:

A → -$100
B → +$100
Enter fullscreen mode Exit fullscreen mode

Great.

Now ask:

What happens if credit() fails?

Your system could become:

A → -$100
B → +$0
Enter fullscreen mode Exit fullscreen mode

The function worked halfway.

And halfway is worse than completely failing.

Now you're thinking like a verifier.

You might need:

await db.transaction(async (tx) => {
  await debit(tx, fromAccount, amount);
  await credit(tx, toAccount, amount);
});
Enter fullscreen mode Exit fullscreen mode

This is why experienced developers constantly think about failure modes.


Step 5: Test the Boundaries

AI loves the happy path.

Production loves everything else.

For every important function, check at least:

Normal input
Empty input
Null / undefined
Minimum value
Maximum value
Incorrect type
Malformed input
Duplicate operation
Unauthorized request
Concurrent request
Network failure
Database failure
Timeout
Retry
Partial failure
Enter fullscreen mode Exit fullscreen mode

Imagine an AI-generated signup form.

It works with:

john@example.com
Enter fullscreen mode Exit fullscreen mode

But what about:

JOHN@example.com
john+test@example.com
""
5000-character input
Unicode
duplicate email
database timeout
two simultaneous signups
Enter fullscreen mode Exit fullscreen mode

Correctness lives at the edges.


Step 6: Test Invariants, Not Just Examples

This is an important engineering habit.

Instead of only testing:

10 + 20 = 30
Enter fullscreen mode Exit fullscreen mode

test the rule that should always remain true.

For example, in a payments system:

Money cannot disappear.

In an inventory system:

Stock cannot become negative.

In an authorization system:

A user cannot access another organization's private resources.

In a billing system:

Retrying the same webhook must not charge the customer twice.

These are invariants.

AI-generated implementation can change.

Your invariants should not.

When reviewing AI-generated systems, identifying invariants may be more valuable than reading hundreds of generated lines.


Step 7: Never Let the Same AI Be the Only Judge

Here's a subtle trap.

You ask AI:

Implement this feature.
Enter fullscreen mode Exit fullscreen mode

Then:

Write tests for it.
Enter fullscreen mode Exit fullscreen mode

The AI made assumption X while implementing the feature.

Now it writes tests based on… assumption X.

Implementation:

wrong assumption → code
Enter fullscreen mode Exit fullscreen mode

Tests:

same wrong assumption → test
Enter fullscreen mode Exit fullscreen mode

Result:

✅ 47 tests passed
Enter fullscreen mode Exit fullscreen mode

But the system can still be wrong.

Tests prove that the implementation satisfies the tests.

They do not automatically prove that the tests represent reality.

So use independent verification.

For example:

Agent A

Implement this feature.
Enter fullscreen mode Exit fullscreen mode

Agent B

Give it only the requirements and resulting diff:

Act as a hostile reviewer.

Find incorrect assumptions, security vulnerabilities,
race conditions, missing edge cases and ways this
implementation could fail in production.

Do not try to defend the implementation.
Enter fullscreen mode Exit fullscreen mode

Now AI is being used as an adversary rather than merely an author.

That is much more powerful.


Step 8: Verify Dependencies

AI-generated code frequently introduces packages.

For example:

npm install some-amazing-auth-helper
Enter fullscreen mode Exit fullscreen mode

Don't blindly run it.

Check:

  • Does the package actually exist?
  • Is it actively maintained?
  • Is the repository legitimate?
  • When was it last updated?
  • How many dependencies does it pull in?
  • Does your framework already provide this capability?
  • Does the package have known vulnerabilities?
  • Is the license acceptable?
  • Is the AI using a current API?

And most importantly:

Did we need another dependency at all?

Dependencies become part of your software supply chain.

Treat them accordingly.


Step 9: Verify Authentication and Authorization Separately

These are not the same thing.

Authentication asks:

Who are you?

Authorization asks:

Are you allowed to do this?

AI frequently handles authentication correctly while missing authorization.

Imagine:

GET /projects/:projectId
Enter fullscreen mode Exit fullscreen mode

The route checks:

if (!user) {
  return 401;
}
Enter fullscreen mode Exit fullscreen mode

Great.

But where is:

if (project.organizationId !== user.organizationId) {
  return 403;
}
Enter fullscreen mode Exit fullscreen mode

Without it, every authenticated user may be able to access every project by changing the ID.

That's not hypothetical "AI safety."

That's ordinary application security.

Which is exactly the point:

AI-generated code still has to survive ordinary engineering standards.


Step 10: Verify Data Destruction

AI agents can now:

modify files
run terminal commands
execute migrations
call APIs
create infrastructure
delete resources
push code
deploy
Enter fullscreen mode Exit fullscreen mode

That's a very different risk level from autocomplete.

Before allowing destructive operations, ask:

Can it delete production data?
Can it modify production?
Can it rotate credentials?
Can it change infrastructure?
Can it force-push?
Can it publish packages?
Enter fullscreen mode Exit fullscreen mode

A useful principle is:

Give AI the minimum permissions necessary for the task.

If an agent only needs to modify source files, it probably doesn't need production database credentials.

If it only needs to analyze logs, it probably doesn't need write access.

Capability should be earned, not assumed.


Step 11: Static Analysis

Tests execute known scenarios.

Static analysis looks for suspicious patterns without necessarily running the application.

Depending on the stack, this could include tools for:

linting
SAST
dependency scanning
secret scanning
type checking
code quality
license checks
Enter fullscreen mode Exit fullscreen mode

A CI pipeline might conceptually look like:

Pull Request
      ↓
Type Check
      ↓
Lint
      ↓
Unit Tests
      ↓
Integration Tests
      ↓
Security Scan
      ↓
Dependency Scan
      ↓
Human Review
      ↓
Merge
Enter fullscreen mode Exit fullscreen mode

Notice something important?

There is no:

Was generated by AI? → skip everything
Enter fullscreen mode Exit fullscreen mode

AI code should pass the same gates as human code.

Possibly stricter gates when the author didn't fully understand the generated implementation.


Step 12: Integration Tests Matter More Than Ever

A unit can be correct while the system is wrong.

Your payment service works.

Your database service works.

Your webhook handler works.

Then production does this:

Stripe webhook
      ↓
timeout
      ↓
Stripe retries
      ↓
your endpoint processes again
      ↓
duplicate transaction
Enter fullscreen mode Exit fullscreen mode

Nothing was wrong with the individual function.

The interaction was wrong.

AI agents are particularly good at generating locally reasonable components.

That makes integration testing extremely important.

NIST's current DevSecOps reference material also describes automated test suites spanning functional and non-functional requirements, including unit, integration, regression, smoke and acceptance testing before artifacts advance further through delivery.


Step 13: Test Against the Real Contract

Suppose your AI generates code based on:

POST /v1/payments
Enter fullscreen mode Exit fullscreen mode

Maybe the actual provider changed it.

Maybe the response field is:

{
  "payment_status": "paid"
}
Enter fullscreen mode Exit fullscreen mode

while the AI assumed:

{
  "status": "success"
}
Enter fullscreen mode Exit fullscreen mode

This is why documentation matters.

The Stack Overflow survey still shows technical documentation as the most commonly used learning resource among developers.

For external integrations, verify against:

  • official docs
  • API schemas
  • OpenAPI specs
  • SDK types
  • provider examples
  • real sandbox responses

Not:

"The AI sounded confident."


Step 14: Review the Database Migration Like Production Depends on It

Because it does.

AI-generated migration:

ALTER TABLE users
DROP COLUMN legacy_id;
Enter fullscreen mode Exit fullscreen mode

Looks clean.

Did the AI check whether:

another service still reads it?
analytics depends on it?
a rollback requires it?
millions of rows need migration?
the operation locks the table?
Enter fullscreen mode Exit fullscreen mode

Schema changes deserve a different level of caution.

For dangerous migrations, think about:

expand
migrate
verify
contract
Enter fullscreen mode Exit fullscreen mode

instead of:

change everything immediately
Enter fullscreen mode Exit fullscreen mode

Step 15: Add Observability Before Calling the Feature Done

Here's another important distinction.

Tests answer:

Did it behave correctly in scenarios we predicted?

Monitoring answers:

What is happening in scenarios we didn't predict?

Production needs:

logs
metrics
traces
error reporting
alerts
audit events
Enter fullscreen mode Exit fullscreen mode

Imagine an AI feature passes every test but causes API latency to go from:

180 ms
Enter fullscreen mode Exit fullscreen mode

to:

2.8 seconds
Enter fullscreen mode Exit fullscreen mode

Technically correct.

Operationally terrible.

Correctness includes production behavior.


Step 16: Define the Proof Before Asking AI to Code

This may be the most useful technique in this article.

Before saying:

Build this feature.
Enter fullscreen mode Exit fullscreen mode

write:

Definition of Done

Example:

Feature: Password Reset

Requirements:

[ ] Token expires after 15 minutes
[ ] Token can only be used once
[ ] Existing sessions can be revoked
[ ] Email enumeration is prevented
[ ] Rate limiting exists
[ ] Password policy is enforced
[ ] Reset attempts are logged
[ ] Unit tests pass
[ ] Integration tests pass
[ ] Security scan passes
[ ] Another developer reviews the PR
Enter fullscreen mode Exit fullscreen mode

Now the conversation changes.

Instead of asking AI:

"Make password reset."

you're asking:

"Produce an implementation that satisfies these observable conditions."

That is much closer to engineering.


The AI-Era Verification Loop

Here's the workflow I'm increasingly convinced developers should learn:

            ┌───────────────┐
            │  REQUIREMENT  │
            └───────┬───────┘
                    ↓
            ┌───────────────┐
            │   GENERATE    │
            └───────┬───────┘
                    ↓
            ┌───────────────┐
            │  UNDERSTAND   │
            └───────┬───────┘
                    ↓
            ┌───────────────┐
            │     TEST      │
            └───────┬───────┘
                    ↓
            ┌───────────────┐
            │    ATTACK     │
            └───────┬───────┘
                    ↓
            ┌───────────────┐
            │    REVIEW     │
            └───────┬───────┘
                    ↓
            ┌───────────────┐
            │    OBSERVE    │
            └───────┬───────┘
                    ↓
            ┌───────────────┐
            │     SHIP      │
            └───────────────┘
Enter fullscreen mode Exit fullscreen mode

Notice how little of this is about typing code.

That's probably where software engineering is heading.


What Should Junior Developers Learn Now?

I sometimes see advice like:

"AI writes code now, so learning fundamentals doesn't matter."

I think the opposite is happening.

If AI gives you this:

const results = await Promise.all(
  users.map(user => processUser(user))
);
Enter fullscreen mode Exit fullscreen mode

you need enough engineering knowledge to ask:

  • What if there are 200,000 users?
  • What limits concurrency?
  • Will we exhaust database connections?
  • Is the operation idempotent?
  • How are failures retried?
  • What if only 40% complete?
  • Do we need batching?
  • Should this be a background job?

AI makes syntax less valuable.

It makes judgment more valuable.

Learn:

databases
networking
HTTP
authentication
authorization
transactions
concurrency
caching
queues
distributed systems
testing
security
observability
system design
Enter fullscreen mode Exit fullscreen mode

Not because AI can't generate code involving them.

Because you need those concepts to determine whether the generated code makes sense.


What This Means for Senior Developers

Senior engineering may also change.

A senior developer's leverage used to be partly:

"I can write this implementation much faster than a junior."

Now AI may generate both implementations quickly.

The senior developer's advantage becomes:

"I know which implementation will survive production."

They recognize:

  • architectural consequences
  • hidden coupling
  • migration risk
  • security boundaries
  • scaling problems
  • ambiguous requirements
  • bad abstractions
  • operational failure modes

Those skills become more important when implementation becomes cheap.


A Practical AI Code Review Checklist

Before merging a significant AI-generated PR, I want to be able to answer these questions:

Requirement

  • Do I know exactly what this feature is supposed to do?
  • Did I identify AI assumptions?
  • Are acceptance criteria defined?

Code

  • Do I understand the important changes?
  • Is the architecture appropriate?
  • Did the AI introduce unnecessary complexity?

Data

  • Can data be corrupted?
  • Are writes transactional where necessary?
  • Are destructive operations safe?
  • Is retry behavior idempotent?

Security

  • Authentication correct?
  • Authorization correct?
  • Input validated?
  • Secrets protected?
  • Dependencies checked?
  • Injection risks considered?

Testing

  • Happy path tested?
  • Failure path tested?
  • Boundary cases tested?
  • Integration tested?
  • Regression tested?

Operations

  • Logs available?
  • Errors observable?
  • Metrics available?
  • Rollback possible?
  • Migration safe?

Evidence

  • CI passed?
  • Static analysis passed?
  • Security checks passed?
  • Human review completed?

If I cannot answer important questions on that list, I'm not ready to say:

"The code is correct."


AI Should Produce Evidence, Not Just Code

This is the mindset shift I think matters most.

Instead of prompting:

Build authentication.
Enter fullscreen mode Exit fullscreen mode

try:

Implement authentication.

Then provide:

1. assumptions you made
2. threat scenarios
3. tests covering happy and failure paths
4. authorization checks
5. dependency changes
6. migration implications
7. commands I can run to verify everything
8. unresolved risks
Enter fullscreen mode Exit fullscreen mode

Now you're not merely asking AI for code.

You're asking AI to help produce evidence.

And you independently verify that evidence.


The Developer's Job Isn't Disappearing. The Job Is Moving Up a Layer.

AI is rapidly reducing the effort required to turn an idea into source code.

But companies don't really pay engineers for producing characters in a .ts, .py, .go, .rs, or .java file.

They pay engineers to make systems work.

Reliably.

Securely.

At scale.

With real users.

With real money.

With real data.

And with somebody accountable when something goes wrong.

AI can generate:

10,000 lines
Enter fullscreen mode Exit fullscreen mode

before lunch.

Production doesn't care.

Production asks:

Does it work?

Will it keep working?

Is it secure?

Can it fail safely?

Can we monitor it?

Can we recover?

Can another engineer maintain it?

Can you prove those things?
Enter fullscreen mode Exit fullscreen mode

That is software engineering.


The Skill I Would Invest in for 2026

Learn AI coding.

Use Copilot.

Use Claude.

Use ChatGPT.

Use coding agents.

Automate repetitive work.

Generate tests.

Generate migrations.

Generate documentation.

Generate prototypes.

Move faster.

But don't make:

"AI generated it successfully"

your definition of done.

Make this your definition:

"I have enough evidence to trust this in production."

Because as code becomes easier to generate, one developer skill becomes harder to automate:

Knowing what evidence is sufficient to say: "Ship it."


One question for developers working with AI every day:

If AI generated 80% of a production pull request, how much of that implementation would you personally need to understand before pressing Merge?

A) Every important line
B) Architecture + critical paths
C) I mainly need strong tests and CI evidence
D) If the agent can prove the behavior, I'll merge it
E) I genuinely don't know yet

I'm especially curious how this differs between startups, enterprise teams, solo developers, and regulated industries.

What is your standard?

Top comments (0)