Raw capture â raw/ddd-and-ai-coding.md
url: https://threedots.tech/post/ddd-and-ai-coding/ date_fetched: 2026-09-04
Whatever you think of AI coding, the way we build software is changing. Everyone wonders, âWhat will stay relevant?â All we have is opinions, so hereâs mine: most ideas behind Domain-Driven Design are now more relevant than ever, as DDD has never been strictly about code. As we do more coding with agents, we still need to understand the domain, model it well, and work as a team. Letâs see what DDD can still teach us and what AI canât replace.
The usual disclaimer: I write about complex projects maintained over months or years, where teams tend to struggle and where DDD shines. Thereâs no reason to use advanced patterns in pet projects or CRUDs.
Eric Evans published Domain-Driven Design more than two decades ago, but itâs still surprisingly fresh. The book covers many topics, but the main message is that the hard part of software engineering is understanding the problem domain and modeling it well in code. It calls on engineers not to get lost in the technical details and to focus on what theyâre solving, because itâs more difficult to get that part right.
Instead, the technical talent goes to work on elaborate frameworks, trying to solve domain problems with technology. Learning about and modeling the domain is left to others. Complexity in the heart of software has to be tackled head-on. To do otherwise is to risk irrelevance.
We now see that the implementation details become less relevant thanks to AI tools. To a degree, you can be productive without a deep knowledge of a programming language or a framework, and itâs easier to move to another tech stack. If youâve tried using the top coding agents, youâve probably seen them quickly generate decent code.
But knowing high-level software concepts is still essential to guide agents and to decide whether the output makes sense. Most of all, the domain complexity (the business problem youâre solving) is still the hard part. The good news is that coding is easier than ever, so we can focus on these complex problems instead of getting lost in the implementation details.
Except, instead of obsessing over building the frameworks (or adding more microservices, or whatever else is a cool trend), we now follow the model benchmarks and optimize our agentic setup to generate better code with less effort. As Evans noted back in 2003, we still try to solve the domain problems with technology. Funnily enough, this time the CEOs also believe it and push us toward it.
Thereâs just one small thing left to figure out: how the thing should work. If someone tells us, we can throw tokens at the implementation and call it a day. And if no one knows, well, maybe an agent could write the plan for us?
The foundation of DDD is model-driven design: distilling how the domain works into a model thatâs expressed in code. The domain model is an abstract concept, and thereâs no one way to represent it. You can use documents, diagrams, and code, but they are all simplifications of how the domain works. An accurate model comes from switching between design and implementation, and applying what youâve learned over and over.
DDD calls this knowledge crunching. You need domain experts (the people who know how the business works), and engineers who are experts at building software. They work together to understand what the software should do and how to implement it. (For example, in an Event Storming session, a workshop where developers and stakeholders map out how the business works with sticky notes.)
Figuring out the domain is a team effort and hard work, so itâs tempting to have someone else do it. For example, AI agents are brilliant at research and analysis, and can access your documents, chats, and code. It seems they could create the domain model for you, and then also implement it.
But this naive approach misses the point. The value of working on the model is that you (and your team) understand how the domain works. An AI-generated wall of text doesnât help you figure out the business problem. The agent will just create an impressive artifact no one reads.
The challenge has never been to write a long document on how something could possibly work. More often, software projects fail because of other issues:
Hereâs one trap Iâve fallen into many times. In engineering teams, itâs easy to feel like weâve got it all figured out: weâre programming experts, know our patterns, and follow best practices. We just need someone (a business stakeholder or a product manager) to tell us what to do.
But often, the domain experts donât have a clear plan either. They know the problem they have, but not what the solution is yet. Thereâs no complete document with all requirements. A developerâs first instinct may be to think, âLet me know once you come up with something, Iâll be around.â In other words, weâre here for the fun part of coding. (Note this is the part AI agents automate.)
At the other extreme, non-technical managers try to come up with the entire solution and hand it to the team to implement. Or, the most recent trend, someone uses AI to generate a full feature or product spec, doesnât even read it, and passes it along. So the plan sort of exists, but itâs nowhere near something ready for production. (If someone claims otherwise, check how complex the thing theyâre shipping really is.)
In all of these scenarios, no one has a clear idea what theyâre doing. No matter who writes the code or how fast, it has little value at this point.
In contrast, when you work on the model together, your team understands the problem domain and agrees on a solution. Developers implement it, and domain experts can jump in once something unexpected comes up or another iteration starts.
Even if you do most coding with AI, you need to get deeply familiar with the domain to guide the agent, just as you would a teammate. How you configure the agents and what LLM you use donât matter as much as a clear mental model of the solution. If I had to choose, Iâd rather never write any code myself than skip thinking about what needs to be done.
Writing code has always been easier than reading it. Itâs just more extreme now that an agent can single-shot a big feature for you. Even if it works, you have no idea whatâs going on under the hood.
We now get stuck on code review more often, but itâs also not a new problem. It even feels familiar, like working with a lone-wolf developer who prepares complete features and drops a massive PR on you. You know nothing about the design and there are often gaps that no one has considered. Reviewing the PR is painful.
Thereâs a way to avoid situations like this, and Iâve seen it work in many projects. You design and discuss the solution as a team before sitting down to code. First, the domain parts: what youâre solving and how itâs supposed to work (see knowledge crunching above). Then, the technical side. After you kick off the implementation, thereâs little chance of anything unexpected coming up.
You donât need to agree on every tiny detail, and donât need a complete written spec. Itâs enough to sketch a high-level plan that everyone is aware of. Some sticky notes and a whiteboard are good enough.
After sessions like this, reviewing PRs is smooth. Itâs easy to split the work into small chunks if you donât discuss the entire design in PR comments. And there are fewer gaps once the feature lands in production, because youâve already agreed on the details and everyone understands what theyâre building.
Skipping the design may seem like saving time. No one likes more meetings. But if your team first learns about the feature from the PR, it takes much longer to review, discuss, and fix all the issues. Since reviews are usually asynchronous, you end up with many rounds of comments. Code review should be a double-check that the implementation is correct, not the start of a discussion about whether the approach makes sense at all.
Working on design before code will also help you work better with AI agents. If you give the agent more high-quality context, its output will be more accurate and the coding part will be shorter. And the more your team knows about the solution, the easier the review, even if you generate all the code.
Recently, Iâve been trying to cut our cloud costs. Itâs the perfect task for AI, since thereâs an obvious metric to measure. I told the agent to find where our Go service uses the most memory and to cut it.
After a couple of runs, I saved us many megabytes of RAM. But then I realized memory is pretty cheap, and the updates reduced our costs by $1/month. Not surprising, right? I didnât explain to the agent that I was trying to cut costs. I just gave it the memory usage as the target.
It should sound familiar, because itâs exactly what happens between humans in teams. Good practices that help you communicate in a team are also relevant when you work with AI. (Who would have thought soft skills may help you deal with computers?)
DDD addresses this with a few ideas around the language you use.
The first is Ubiquitous Language: speaking the same language across teams and in code, so everyone knows what youâre talking about.
In many teams, messy names are the default. In code, engineers use technical terms that drift away from the names that the rest of the company uses. Even if you feed AI documents and decision records, the agent needs to make sense of whatever language you use there.
During knowledge crunching, consider what you call the concepts in the domain. Initially, itâs common to have more than one name for each. Choose a name you already use, or come up with a more accurate one. Then, use it in the documents, spoken language, and code.
You canât choose the names just once, because the language will keep evolving with the project. Itâs something you need to care about during the design sessions and discussions.
Another idea directly connected to the Ubiquitous Language is that in bigger systems, the names you choose wonât be universal in all areas. DDD calls each of these areas a Bounded Context. You can think of your customer as a profile in the support context, and as a user in the e-commerce context. You want to use consistent names within each context, not force them across the entire project.
This is especially important with bigger products, when you need to split the software between teams. If you focus too much on creating one model for all kinds of tasks, it becomes difficult to draw boundaries. With bounded contexts in mind, itâs easier to end up with a decoupled system.
Agents have access to your whole repository, and theyâll look for the names you give them. They may naively try to unify similar entities, so make it clear they are separate for a reason.
If you use well-known, precise concepts, itâs easier to express what you mean. Itâll work both with your teammates and in your prompts.
A vague prompt can make the agent spend a lot of effort on the wrong solution:
Add user to CRM and support after itâs created
Youâll make the goal more obvious by sticking to the precise names:
Once the user signs up on the website, asynchronously create: 1) a customer entry in the CRM, 2) a profile in the support system
You want the details about your domain language in your agentsâ context. Itâs yet another reason to keep the documentation up to date. Markdown files close to the code are a good starting point, since you donât need a custom integration to fetch the documents.
The models and agents keep getting better, but you canât fully trust them. They still make mistakes, and you need someone accountable in the end. How can you know if the outcome is correct?
Working in the domain is how you build trust that you know what youâre doing. People who design the system and understand how it works can tell you whether something is likely to go wrong.
Developers become experts in the subject theyâre working on. They learn skills beyond writing code, and for a curious engineer, even a complex business domain becomes intuitive with time. If you need help in that area, you know who to ask. You save yourself massive headaches by working with someone you can trust to get the job done without extremely detailed instructions.
There are two recent AI narratives. One is that anyone can now generate a clone of a well-known app. This was shocking at first, but isnât that interesting in the long run. We already have too many half-baked apps out there even without AI.
The more interesting story is how experienced engineers can build more complex applications now. For example, a team can replace expensive third-party software with an in-house solution. But how can they trust their version works well?
Because of the knowledge they already have thanks to working in that specific domain. They combine what they know with AI and build their own version so fast, itâs cheaper than paying for the license. On top of that, they can also add any custom features they need.
For employers, having product-minded engineers around who know the domain well is huge. They can figure out the obscure details and guide the discussions. Itâs always been naive to treat developers as people who code what you tell them, and now itâs even more so.
For engineers, learning to work with an unknown domain pays off more than focusing on technical skills alone. Itâs easier to work in a profit center if youâre good at solving business problems, rather than being an expert in one framework.
DDD shows how thereâs much more to software than writing code. If youâve worked with complex systems, Iâm sure youâve seen it many times.
This topic brings back memories from my first software job. I once worked on a tough problem, and spent hours doodling with pen and paper. I finally figured it out, even though I barely touched the keyboard. I had only recently started, so I was speechless: âWow, today I got paid to think.â
This felt wild at the time, but today it feels even wilder. Back then, my manager wouldnât blink an eye if I said I spent a day thinking about a problem. Today, we focus more on the output. Why not have the AI do the thinking instead?
For one, because the only reason I can judge whether the agentâs output makes sense is that Iâve spent long hours thinking about such problems in the past.
Thereâs the argument that you no longer need this experience, since AI will handle everything for you anyway. Relying on AI could eventually become the new normal, but thereâs one issue I canât ignore. You need to exercise your brain to work on complex problems, and you canât build new mental models without thinking.
The best analogy I have is reading a book versus a summary of it. Reading forces you to think about the topic for hours. You slowly build a complex model in your mind, and you connect it to other things you know. You understand the topic, instead of reading a few sentences that you forget ten seconds later when you close the browser tab.
No one knows the best practices yet, so itâs a good time to experiment and see what works. For now, Iâll mix old-school problem-solving with trying out new ways of working with code.
In this post I focused more on the philosophy behind DDD than individual patterns. I plan to write more, including about the tactical patterns closer to the code. I still find them useful, even if I donât type them by hand. Sign up below so you donât miss the next posts.