The app should tell you why
A refusal with no reason, an empty screen with no cause, a score with no basis. Each teaches that the software is arbitrary, and arbitrary things get routed around.
There is a category of software behaviour that is technically correct and practically useless: the system does the right thing and does not say why.
A page refuses access. A list is empty. A field will not accept a value. A number appears with a colour. In each case the software knows the reason exactly, and in each case it has chosen not to share it.
The cost is not confusion in the moment. It is that people learn the system is arbitrary, and arbitrary systems get worked around.
The four places it happens#
A refusal. Somebody is not allowed to do something. The screen says so and stops. We had a refusal that landed people on a blank form with no indication of why they had got there. They had done nothing wrong and there was nothing for them to do differently; they simply learned that the thing sometimes does not work.
An empty state. A list with nothing in it looks identical whether it is empty because there is nothing to show, empty because a filter is excluding everything, empty because the data has not loaded, or empty because something upstream is broken. Four completely different situations with one appearance. A layer that is switched on and holding nothing should say so rather than looking indistinguishable from one that was never switched on.
A computed judgement. A risk score, a suggested match, a flag. Without its basis, the number is either believed blindly or ignored entirely. Neither is use.
A thing that happened by itself. A calendar entry that appeared, a message that was sent, a task that moved. If the system does something on a person's behalf and does not say what caused it, the person's reasonable conclusion is that the software is unpredictable.
None of the four appears in a sales demonstration unless somebody asks to see one, which is why how to run a software demo is largely a list of things to insist on.
Why it goes missing#
Not because anybody decided against it.
The reason exists at the point of the decision, deep in some function that knows exactly which condition failed. Then the result travels outward as a boolean — allowed or not, matched or not, valid or not — and by the time it reaches the screen the reason has been thrown away several layers earlier.
Recovering it is not a design task, it is a plumbing task, and plumbing tasks lose to features in every prioritisation meeting ever held. That is the actual mechanism, and knowing it is useful because it tells you where to fix it: the reason has to be carried, not reconstructed at the end.
What a good "why" contains#
Three parts, and most implementations stop after the first.
What happened. This is refused.
Why, specifically. Not a category. The actual condition: because this order is closed, because your account does not hold the export key, because the material has not been received against this payment.
What to do about it. The part that turns an explanation into help. Who to ask, which button, what has to happen first. A refusal that names the person who can grant the thing removes an entire support conversation.
We rewrote a set of failure notices in our own system that had all three parts wrong. When a message failed to send, the notice told people to create an approved template in a service we had retired months earlier — so it was sending people to fix a problem that could not exist. Its sibling was worse: when a handset stopped answering, the notice said messages were being routed via the other provider. There is no other provider. They were not being sent at all.
Both now describe the system that is actually running and name the real cause — the handset needs re-pairing, the secret no longer matches, nothing is answering, or the service was too busy to reply — each with the one action that fixes it.
Explanations in the reader's language#
An explanation in a language the reader does not use is not an explanation.
This matters more than it sounds on an Indian construction site, where the person receiving a refusal may read Hindi and not English, or may read neither comfortably. Our approach is one plain line in the reader's own language, with the original text kept beside it rather than replaced — because the original is what somebody technical will need if the plain line turns out to be wrong.
And the register matters as much as the language. In Hindi, the respectful form throughout, never bare imperatives. A system that instructs people curtly in their own language is worse than one that does it in a foreign one, because the rudeness lands.
Explaining without being noisy#
The obvious objection is that explanations clutter the screen, and it is a fair one.
Three rules keep it manageable.
Explain the unexpected, not the ordinary. A successful save needs no justification. A refusal always does.
Put the reason where the effect is, not in a separate log or a tooltip nobody hovers. If a payment is held, the reason belongs on the payment.
Keep it to one sentence in the interface, with the detail one tap away. Most people need to know why; a few need to know precisely why.
The pin that explains itself#
A small example we are fond of, because it shows the idea working at a scale where it clearly costs nothing.
A public portal existed with no explanation of what it was for, so it looked arbitrary to anybody who came across it. Adding one line — what this is and why it exists — turned an unexplained thing into an understood one, permanently, for the price of a sentence.
Almost every "why" in a system is that cheap. The expensive part is noticing which questions people are silently asking.
Where it connects#
An unexplained judgement is the failure mode of every predictive feature. A slip warning without its basis is a number people stop reading, which is why work slips before it is late insists on the sentence rather than the score.
An unexplained proposal is the failure mode of every suggestion system, which is why every match in our own tools carries its reasoning — the machine proposes, a person decides.
And an unexplained routing decision is how a signature request ends up delivered as chatter, in filed as chatter.
The short version#
The system always knows why. It just discards the reason on the way out.
Carry it. Say what happened, why specifically, and what to do next. Say it where the effect is, in the reader's language, in a respectful register, once.
An unexplained refusal is not a small usability flaw. It is the thing that teaches people the software is arbitrary, and everything they do after learning that is a workaround.