The Button That Means Four Things
Every product that stores things eventually ships a delete button, and it is almost always the least-designed control on the screen. It gets a confirmation dialog — usually one written in a hurry, usually saying “Are you sure? This cannot be undone” whether or not that happens to be true — and then it is considered finished.
The trouble is that “delete” is not one behavior. It is at least four, and which one a given button performs is usually an accident of how the feature was built rather than a decision anyone made.
The first is hide: the row stays exactly where it was, with a flag set, and every list query grows an extra condition. The second is detach: the thing is removed from where you were looking at it but continues to exist somewhere else, still counted, still billed, still turning up in an export. The third is cascade: the thing goes and takes with it a set of other things whose relationship to it the user may never have been shown. The fourth is erase: the bytes are actually gone, from the database and eventually from the backups, and nobody can get them back.
These are wildly different promises. A user pressing the button has one of them in mind, and no way to tell which one they are getting.
The mismatch runs in both directions, and both directions hurt. Someone who believes they erased a record — because the dialog said it could not be undone — later discovers it in a report, or an audit log, or a monthly invoice. That is not a minor surprise. For a person deleting something for a reason, being told it is gone when it is not is the product lying to them about the one thing they cared about. Meanwhile someone who assumed delete meant hide, because that is what it meant in the last tool they used, presses it on something important and finds that this time it meant erase, and there is no version of “sorry” that fixes that.
What makes it worse is that the four behaviors tend to coexist inside the same product. Deleting a comment hides it. Deleting a file detaches it from a folder but leaves it in storage. Deleting a project cascades through everything under it. Deleting an integration erases its credentials immediately, because that one had a security review. Each of these decisions was reasonable in isolation and made by a different person in a different quarter, and the user is expected to hold a mental model of all four.
The fix is not a clever mechanism. It is deciding, once, at the product level, what the word means — and then making the exceptions visible instead of implicit. If deleting a project takes twelve other things with it, the confirmation should say so, and should say what the twelve are, because “Delete project?” and “Delete project, 4 dashboards, and 8 saved views?” are not the same question and only one of them can be answered honestly.
There is a second, quieter reason to care, which is that everything downstream inherits this ambiguity. Exports have to decide whether deleted things are included. Analytics have to decide whether they are counted. Sync has to decide whether a delete on one side propagates to the other, which it usually does not, because propagating an unrecoverable operation across a system boundary is exactly the sort of thing nobody wants to be responsible for. Every one of those decisions gets made by whoever happens to be writing that code, and the result is a product where “how many do I have” has four different answers depending on which screen you ask.
The version that works is boring. Pick soft deletion as the default, because reversible operations are cheaper to get wrong. Say plainly, in the interface and not just in the docs, that deleted things are recoverable and for how long. Reserve genuine erasure for the cases that require it — credentials, personal data on request, anything where retaining it is the liability — and make those cases look different from the ordinary ones, because they are different.
And when the dialog says it cannot be undone, that should be a fact about the system, not a phrase inherited from a template. The confirmation dialog is where a product makes its most consequential promise to a user, in the smallest amount of text, at the moment they are least inclined to read carefully. It is worth getting the sentence right.