AI Is Writing My Code — Now What?
Over the last few years, tools such as Anthropic's Claude Code, OpenAI's Codex, Cursor, and others have gained wide adoption. There has been much speculation about what this means for the software industry. I maintain that Software Engineers[1] continue to provide significant value. Two things have not changed:
- Your direction matters. The AI still needs direction.
- You are responsible for the output. The AI takes no responsibility. You supervise it.
The rest of this post is about what those two things look like in practice.
This Is an Inflection Point, Not a Fad
AI code generators are an inflection point in programming tools, and we've had these before. Assemblers were an inflection point relative to machine code. C, FORTRAN and COBOL were to assemblers. Interactive debuggers, object-oriented and functional programming, open library ecosystems like PyPI, interpreted versus compiled languages — all inflection points. If you use any of these today, you would strongly resist going back and doing without it. AI code generators are the same. There is no going back to the "old way".
Consider this: you (probably) never looked at the bytecode that Python produced, even though you were "writing" it via your Python source. You relied on the Python Virtual Machine to faithfully execute your intent. Now you may not have to look at your Python code much either.
Direction
Clear direction is paramount. The AI can be "smart" — it can even push back on an inconsistency on occasion — but it will usually take your instructions literally. Knowing your domain is important, and you must give clear instructions.
The direction you give matters whether you give it interactively or in files. This includes:
- Project files — the initial project requirements and specification.
- Context files — the standing instructions the tool reads on every session (e.g.
CLAUDE.mdfor Claude Code). This is where your coding rules live (see below). - Model selection — decide which model is appropriate for your project. Do you need the most capable model with per-token spend, is a more modest model in a cost-efficient subscription sufficient, or does it make sense to run a model locally? The tradeoffs are cost, support and operations, and security.
Your project needs someone who understands it — who understands the problem or opportunity you're trying to address. This is your value-add. You're the supervisor: giving direction, asking the hard questions, making the calls that require judgment. This is the difference between someone with a vague concept and someone who can execute on the project and deliver a reliable product or service.
The Software Engineer is responsible for the specification that is given to the AI.
Responsibility
You were — and still are — responsible for a certain functionality. It may be a fully capable system or a portion of one, but ultimately you deliver something that provides value and works. All AI can "make mistakes" and "hallucinate". If a mistake is made or a result is incorrect, the AI is not responsible, and neither is the AI vendor. You are.
This is probably the hardest part to wrap your head around compared to prior tools. Most other
tools were expected to be reliable, or at least to try to be. "Bad" output was a bug that
needed to be fixed, and there are extensive specifications for things like C compilers that
define their operation (some debatable corner cases notwithstanding). Bad code from an AI is
"just the way it is". Of course it's getting better, but there is no near-term expectation that
AI companies will accept bug reports or pay bug bounties when the AI made what you consider to
be a mistake. Imagine if Python didn't produce 3 when you wrote 1 + 2 and you were told it
was your problem. But in this case the AI might have written a thousand lines of code you didn't
have to. The tradeoff — that there might be a bug in there — is worth the overall time savings.
So:
- You are what makes the code production code.
- The code is now your code. You may not have to look at it, but you have to be prepared to.
- It doesn't matter whether you use AI or not. You're evaluated on your output, regardless of the tools (as long as you're not way over on tool spend).
Software Engineers are responsible for taking some sort of requirements — inputs, concepts, ideas — and delivering a working system: dealing with stakeholders, ensuring there is sufficient testing, robust deployment, and so on. None of that moved.
Rules
Code Constructs
Generally an AI has to be directed on these topics:
- Strongly avoid
try/except Exception. This is too wide and should not be used in production, but an AI will generate it unless told otherwise. - Code examples are not production code. Many AIs are trained on example code that is not proper for production deployment. This includes poor secrets management — examples tend to avoid managing credentials and just have the user put secrets in source-code literals.
- Use DRY. AI-generated code often doesn't follow DRY principles. It has to be told.
- Use libraries. Often the AI will write the code "from scratch". While this is good from a reduced-dependency perspective, it makes for bloated code. It's usually better to use a well-maintained library.
- Proper logging. Ensure logging is being done properly: structured logging as appropriate, sent to the right places, at the right log levels.
Supervision
Avoid the temptation to just let the AI run wild. Know when to tell the AI to review the code — including its own code — and when to tell it to review and refactor for good practices such as function reuse, performance, modularity and DRY. It won't do this on its own at the moments you would.
Not All Code Is Equal
One of the responsibilities of the Software Engineer is to understand and implement development with AI that is appropriate for the type of code being developed.
Some functionality is fairly easy to validate. There the purpose of the tests is for the AI to validate its assumptions and iterate, and to provide regression tests (for the AI or the human).
Other code is critical and nuanced. In these cases the Software Engineer must take care in:
- writing their own tests (e.g. spec-driven design)
- understanding what corner cases (numerical, data, etc.) can occur and how to handle them
- for numerical apps: what do you do with NaN (Not a Number) or missing data? Set it to 0.0? Fail? Interpolate?
- how to handle missing or corrupted data: fail entirely? Set to None/NULL? Set to 0?
- proper logging
- handling errors and exceptions
- functional criticality (will failures cause harm?)
- performance requirements
- test coverage metrics and requirements
- ... and whatever other aspects are important to that code
Code exists across a spectrum. The amount of up-front and external documentation will vary. The amount of testing created and executed by the Software Engineer will vary. Assessing this and implementing accordingly is a key responsibility of the Software Engineer.
Testing
The Software Engineer is responsible for the end product, and therefore for testing. This includes:
- Spec-driven testing
- Interpreting code coverage
- Regression testing
One rule I've found worth enforcing: every AI must label its own tests, and an AI must never delete or modify a test "owned" by a human or by any other AI. This way humans can write spec tests (spec-driven design) without the AI causing functional drift — the AI can make its own tests pass, but it can't make your tests go away.
Closing
All of this division of labor between the human and the AI is dynamic and will change over time. People worry about AI "taking over", but the more people who are adept at working with AI, the better off we are.
Footnotes
I'm using the term Software Engineer broadly here. Some people may say Programmer, Coder, Computer Scientist, Hacker, etc. For the purposes of this post I'm going with the "center" of the terminology and using Software Engineer. ↩︎