
AI generates code fast, but without structure it produces bloated PRs, unnecessary abstractions, and code nobody understands. I applied TDD as a framework for human-AI collaboration: one failing test, minimum code to pass, refactor, repeat. A guidelines file trains the AI to follow the cycle, and a set of context files give it project memory between sessions. The result: smaller PRs, faster reviews, real ownership, and predictable quality. The human thinks, the AI implements. At the end of the article you'll find an example of the guidelines I give the AI to work together doing TDD.
title: Red, Green, Refactor… and AI: How I Turned AI Into a Reliable Pair Programming Partner published: true description: AI generates code fast, but without structure it produces bloated PRs, unnecessary abstractions, and code nobody understands. I applied TDD as a framework for human-AI collaboration: one failing test, minimum code to pass, refactor, repeat. A guidelines file trains the AI to follow the cycle, and a set of context files give it project memory between sessions. The result: smaller PRs, faster reviews, real ownership, and predictable quality. The human thinks, the AI implements. At the end of the article you'll find an example of the guidelines I give the AI to work together doing TDD. tags: #TDD #AI #tui #bubbletea cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sjv97jp5kfj80p17kc8t.jpeg
AI generates code fast, but without structure it produces bloated PRs, unnecessary abstractions, and code nobody understands. I applied TDD as a framework for human-AI collaboration: one failing test, minimum code to pass, refactor, repeat. A guidelines file trains the AI to follow the cycle, and a set of context files give it project memory between sessions. The result: smaller PRs, faster reviews, real ownership, and predictable quality. The human thinks, the AI implements. At the end of the article you'll find an example of the guidelines I give the AI to work together doing TDD.
More and more teams are integrating AI into their development cycle. But since it's still a recent technology for many, we don't always know how to turn it into a reliable and reproducible working method.
This article comes from a talk I gave at work, which was well received by over 250 developers from different projects (The Walt Disney Company, FIFA, Verizon, ...). The feedback I got, that it has genuinely helped them in their day-to-day, motivated me to put it in writing so it can reach more people.
I'm sharing a method I use daily with Claude Sonnet 4.6 as my AI assistant, and that has become reliable: a combination of TDD and AI assistance that allows tackling complex tasks in an orderly way, with the well-known benefits of TDD: reliable code, behavior-driven design, early bug detection, fast feedback, and confidence to make safe changes.
Most teams that adopt AI go through an exploration phase. They experiment, get excited, but stay there. What sets apart the teams that truly transform how they work is that they manage to move from experimentation to building habits, and from there to lasting adoption. This method is what allowed me to make that leap.
I work with a team of over 50 developers. When we started using AI to generate code, the initial reaction was excitement. Features were delivered faster, PRs were flowing, and everyone felt productive. Until the code reviews and defects started piling up.
PRs were massive. Abstractions appeared that nobody asked for. Variable names were generic. And the most concerning pattern: developers stopped being able to explain their own code.
The AI generated it, I'm not sure what this part does
We had traded ownership for speed. And the codebase was paying the price.
There's a concept in software engineering that Fred Brooks introduced decades ago: essential complexity vs. accidental complexity.
Essential complexity is inherent to the problem. Business rules, domain logic. It can't be eliminated. Accidental complexity is everything else: boilerplate, unnecessary abstractions, over-engineered configurations. It's introduced by tools, decisions, and, as we discovered, AI.
AI doesn't get tired. It doesn't bear the maintenance burden of the code it generates. It doesn't know your business domain. It optimizes for probability, not context. And it will happily generate 200 lines of code when 20 would suffice.

We didn't ban AI. That would be absurd. Instead, we changed how we work with it.
The answer was Test-Driven Development, applied in a way Kent Beck's original intent didn't cover: as a framework for human-AI collaboration.
TDD forces you to think before you implement. You define the expected behavior first, in a test. Then, and only then, you write the minimum code to make it pass. Then you clean up.
Red. Green. Refactor.
When you apply this cycle with AI, instead of asking it to "build a session manager," you ask it to write one failing test for one behavior. Then you ask it to make that test pass with the minimum code possible. Then you review, refactor, and move on.
You're giving AI a problem the size of a bite, not the whole plate. You don't try to transform everything at once. You stabilize one cycle and repeat it. And that's exactly what turns experimentation into a habit.
AI assistants have no memory between sessions. Every new conversation starts from zero. So I needed a way to make the workflow reproducible.
I created a TDD_GUIDELINES.md file, a set of rules I feed to the AI at the start of every session:
This file evolved during our sessions. Every time the AI did something I didn't like (forgot to ask about refactoring, used syntax I find unreadable, hardcoded a magic number in a test) I'd say "add this to the guidelines." The file grew organically from real friction points.
Some examples of rules that emerged from practice:
x = !x). Use explicit if/else instead."config.MaxRetries instead of 3) so tests remain valid when defaults change."That last one is my favorite. I trained the AI to keep me disciplined.
What this file does isn't spectacular: it simply makes explicit what works. But that's exactly what allows the method to be adopted. Any developer can take these guidelines, start a session with AI, and get consistent results.

Guidelines alone aren't enough. The AI also needs to understand what you're building. I maintain a set of markdown files that serve as the project's memory:
When I start a new session, I point the AI to these files. In seconds, it knows the project structure, the patterns we follow, the conventions we've established, and what to work on next.
No ramp-up time. No "let me explain the project again." Just: "Read the context, let's continue."
A typical cycle:
Me: "What's the next item on the TODO?"
AI: "Implement email field validation in the CSV files."
Me: "OK, let's start there."
AI: Writes a failing test (RED)
Me: "It fails. Good."
AI: Writes the minimum code to make it pass (GREEN, of course you can also write the code yourself)
Me: "Tests pass."
AI: "Anything to refactor?"
Me: "Yes, extract that validation into its own function" / "No, next behavior."
And we repeat. Feature by feature, test by test. Each cycle takes 2 to 5 minutes. In a single session, we can implement a complete feature with full test coverage, clean architecture, and proper documentation.
But here's the key: I'm always in control. I decide what to test. I decide when the design needs to change. I decide when the AI is overcomplicating things. The AI is fast, but I'm the one steering.

After adopting this approach:
TDD turns AI from a wild, unrestrained code cannon into a precise instrument. The investment is small: a markdown file with rules, a few context documents, and the discipline to follow the cycle. The return is significant: consistent quality, real productivity, and code you actually understand.
Red. Green. Refactor. And AI.
var ErrEmpty = errors.New("...")) instead of inline error strings.errors.Is against sentinel errors.wantErr field in table-driven tests must be of type error, not string.TestNewSession), not the behavior. The behavior is described in each table-driven test case's name field.x = !x). Use explicit if/else instead._ to ignore it.config.MaxRetries instead of 3) so tests remain valid when defaults change.1. Human defines the next behavior to test (from the TODO list)
2. AI (or human) writes a failing test → RED
3. Run test → confirm it fails
4. AI implements minimum code to pass → GREEN
5. Run tests → confirm all pass
6. AI must always ask about refactoring → REFACTOR
7. Run tests → confirm all still pass
8. Repeat
TODO.md file in the .tdd/ folder.
gemmaI ported the whole Gemma-4 family — E2B, E4B, 12B, 31B, and the 26B-A4B MoE — to run on...
communityHey DEV, I'm Tobore. Let's actually connect. I've been on here for a while now, mostly writing and...
ai(yep, kinda clickbait, just for the funsies 😊) At the beginning of the year, I relaunched my...
aiMy laptop was sitting idle with the fan at full tilt. Nothing was running that I knew of. The culprit...
githubactionsI Built a Thing! TL;DR — Google Gemini-based Pull Request reviews and Issue Triaging for...
aiI've been hearing the word "harness" thrown around a lot lately. I assumed it just meant "the IDE" or...
Workflows from the Neura Market marketplace related to this DeepSeek resource