A few years ago I watched a teammate stare at a block of code and finally say, “I can see what it does. I have no idea what it means.” The variables were named after database columns. The methods were named after operations. Every line was legal, but the question the code was answering was buried under the mechanics of asking it. That moment stuck with me because it is the whole job in miniature. Elegant naming helps the reader; the compiler works in ones and zeros. The rest of us, human or machine, need to know what the author intended.
Write the question, not the query
I learned to program in an era when “working code” was the only standard. If the screen produced the right result, the code was good. Over time I noticed that the code I wrote in a hurry became the code I feared six months later. The reason was almost never the algorithm or the framework. It was that I had expressed the question in the language of the machine instead of the language of the problem.
Here is a small example that shows the difference.
if (customer.Invoices.All(invoice => invoice.Paid))
{
// Place customer order
}
That is a real question asked in the wrong dialect. It talks about invoices and the Paid flag because that is where the answer lives in the database. Compare it to this:
if (customerCanPlaceOrders)
{
// Place customer order
}
Same behavior, different message. The second version says what the code is deciding (based on the question a human asks to make the decision). The first version forces the reader to decode the decision. In a production system the condition is rarely that short. It becomes a chain of &&s, ||s, parentheses, and negations, and by the time you reach the end you have forgotten what the original question was.
The fix is to push the intent as far into the code as possible. Abstract the condition behind a name that matches what the business calls it. Then the surrounding code becomes a sentence: if the customer can place orders, place the order. A non-technical stakeholder can read that and disagree with the rule, which is exactly what you want. The conversation moves from “what does this do?” to “should this be true here?”
Tests are the shared language
One way I keep intent visible is to write every test in the same shape: given, when, then. It does not matter if the test is a unit test, an integration test, or an end-to-end test. The form stays the same because the form is a conversation.
When I switch between a back-end service and a front-end component, I do not have to relearn the feature. I read the spec, which is written in the language of the problem, and my mind is already looking for the right things when I open the code. The tests become a contract between the people in the room and the code in the repository. They narrow the gap between English, which is how we think about problems, and C#, TypeScript, Python, or whatever dialect the solution happens to use.
That shared language is especially useful when the team is not in the same specialty. A front-end developer, a back-end developer, and a product owner can stand in front of the same given/when/then statement and mean the same thing before anyone writes a curly brace.
If you cannot explain it in English
I have a hard rule for myself now: if I cannot explain the problem in plain English, I do not write code. I have sat with developers who can type a solution before they can say what problem the solution solves. Their hands move faster than their thoughts, and the result is code that explains itself only to itself.
Explaining first saves you from building the wrong thing. When the business stakeholder is in the room, the cheapest moment to fix a misunderstanding is before the database tables, stored procedures, APIs, and screens are built. A drawing on a whiteboard is faster than a deployed wrong feature. Once people see something concrete, the conversation shifts from “is this what you meant?” to “can we move this button?” That is the shortest path to useful feedback.
AI reads code too
The newest reason to write for clarity is that machines now read our code the way teammates do. While preparing this talk, I pointed an AI assistant at a Lot class in a warehouse system. The class tracks inventory quantities, receive dates, and allocations. There are no comments in the file. Instead, the team named properties and methods after what the business calls them: QuantityOnHand, AvailableToSell, Receive, Allocate. I asked the tool to find the tests for the Lot class and explain what features and scenarios it supports. It returned a clean list: receiving items, allocating stock, billing, adjusting quantities, handling snapshots, and tracking inventory history.
It could answer because the code was written as a description of the domain, not as a puzzle. If the names had been abbreviations or database-field echoes, the tool would have returned the same kind of shallow summary that a human would struggle with: “This class has some methods and properties.” The value of the answer came from the clarity of the source.
This is the same principle as the data-to-insight ladder. Raw data is not useful until someone names it, structures it, and turns it into meaning. Code works the same way. Clear, intent-revealing code is the interface that lets both humans and AI tools understand what you want and change the system without breaking the meaning.
Tools do not fix ambiguity
AI can explain code, refactor code, and suggest code. It cannot rescue intent that was never put there. If the names are vague and the tests are missing (or poorly written), the tool will mirror the confusion back to you (or hallucinate an explanation that looks reasonable). The developers who get the most out of AI are the ones who already take the time to name things after what they mean and to express the problem in the language of the people paying for (or benefiting from) the solution.
Clear code is a strategy that makes onboarding faster, maintenance cheaper, and AI collaboration useful instead of frustrating.
The point
Code is for humans, and now it is for AI too. The compiler will accept almost anything. The future maintainers of the system, human or AI, will not. Write the question first. Name the intent. Let the implementation hide behind that name. When the code reads like a conversation, humans can follow it and AI can help you change it without losing the meaning. That clarity is also what makes the next conversation, about the tools themselves, worth having.
Further reading
- From Conversation to Code
- Vibe Coding Is Just Bad Naming
- Most Developers speak with a thick technical accent
- Tests Are not for Computers They are for People





Leave a Reply