Note: article for programmers
When dealing code that has side effects you need to consider the consequences of running your code twice with similar input parameters (i.e. lets call these quasi-idempotent operations). I had a piece of code where I did not consider the consequences and I had a resulting bug.
Example illustrating the bug:
Take this piece of code with a side effect (e.g., updating database):
await ConfirmationRequest
.update({
event: event.id,
user: user.id
}, {
status: is_accept_msg(body)
? 'accepted'
: is_reject_msg(body)
? 'rejected'
: 'unconfirmed'
})
Assume this code is called twice:
- First call: with body so that is_accept_msg(body) = true
- Second call: with body so that is_accept_msg(body) = false
Both calls with the same user and event.
After the first call the status is "accepted". After the second call the status is overwritten to "rejected" or "unconfirmed".
Assume your business logic is that once you accepted you cannot reject the confirmation request. Then you have a bug.
If you're writing functional code most of the time you never think about this issue because functional code is always idempotent (no side effects = idempotent).