"Done" is one of the most contested words in software development. Not because people disagree about what they want — but because they often haven't had the conversation about what done means before the work starts.
For a developer, done often means: the feature works as specified, the tests pass, the code is merged. For a client, done often means: I can use this in the way I expected, it handles the edge cases I care about, and it doesn't break anything else. Those aren't the same definition, and the gap between them is where a lot of project friction lives.
We've made it a habit to define done explicitly for every feature before we build it. Not in great technical detail — just clearly enough that when the work is complete, both sides can look at the same criteria and agree whether they've been met. What does the user see? What does the system do? What happens when the input is wrong? What counts as working?
This sounds obvious, and it is. It's also the kind of thing that gets skipped when a project is moving fast, and you tend to find out it was skipped at the worst possible moment — when something is almost finished and it turns out everyone had a slightly different picture of what almost finished meant.
The acceptance criteria we write into our specs aren't there to make the process more bureaucratic. They're there so that the conversation about whether something is done happens before the work starts, not after it ends. That shift — from arguing at delivery to agreeing upfront — changes the dynamic of the whole project.
The other thing we've learned is that clients are often better at defining done than they think they are. When you ask someone "how will you know this is working?" they usually have a clear answer. The feature we're building needs to let a logistics coordinator reassign a job in under thirty seconds. That's a definition of done. It tells us what to build and it tells both of us when we've built it.