Deleting The Non-Existent
I overheard an interesting question from one software developer to another the other day:
“When we delete a non-existent customer, should we throw an exception?”
Good question—what should the system do?
Firstly, how does the system respond when we are deleting an existing customer?
An action like Delete is a Command Function and thus would typically not return a value. Say, maybe we would define it as
public void Delete(int id);
If we want to delete the
Customer with an Id of 17, we will invoke
Delete like this:
What should happen when
Customer 17 exists? The system ought to remove or deactivate the Customer record. Delete() is a command function, so the calling code will not receive a return value. It’s assumed to get done unless there is an exception. Command functions communicate problems with exceptions.
So far, so good.
Now, what if we have just deleted Customer 17 and try to delete it again?
Delete(17); Delete(17); // <-- Exception??
Should we throw an exception for the second delete? Why or why not?
The Customer does not exist. We are trying to delete a non-existent Customer. Is this a problem? Are we justified in notifying our caller via an exception?
Well, let’s look at the expected outcome: We want the Customer to be gone, deleted. If the Customer wasn’t there to start with and we try to delete it, did we not succeed? It’s not there. Does it matter whether it existed before the delete action? The outcome is the desired result – no Customer. Interrupting the program flow with an exception would be a disruptive, somewhat unexpected action for the calling code. It seems a bit of an overreaction.
Command functions should behave like a butler—do the job with minimal fuss and communication.
“Can you please delete this Customer, Jeeves?”
“Consider it done, Sir.”
When the Customer does not exist, Jeeves won’t annoy or bother the master of the house with a report of this fact – it’s excessive and unnecessary. Similarly, with our systems.
In this way, we should be able to call our Delete() function any number of times for the same customer id:
Delete(17); Delete(17); Delete(17); // ...
When a function’s response is identical for each subsequent call for the same argument values, it is said to be idempotent.
Idempotency makes systems more deterministic and safe—we can always retry the operation and not worry about whether a subsequent call will fail.