| Image by Nikita Vashchenko via Unsplash Copyright-free
As a WorldRemit Operator
I want to be able to enable/disable feature X on specific corridors
So that I can incrementally roll it out
And selectively disable it in case of any issues
Pretty simple requirement, huh? We'll simply maintain a list of enabling/disabling flags for each send-country, receive-country and a product. Or was it a send-country, receive-country, product and send-currency? Shouldn't there be a payment-method too? Or perhaps it's just a send- and receive-country? During my employment in WorldRemit, I've seen at least three different definitions of the corridor and, as probably most of you, I have my own that I tend to stick to. Nevertheless, I learned that I shouldn't assume that my interlocutor understands it in the same way.
Our workdays are filled with a variety of words that repeat over and over, corridor being one of them. But there is also sender and recipient, transaction, correspondent, transaction start or completion - to name a few. They are so ubiquitous that we treat them as our best friends that we know everything about. But do we? I think that their meaning has become so blurred over the years that there is hardly anything left. They are convenient - yes, but I would argue that mostly as a way of avoiding a thorough understanding of a matter at hand. They are often just bad abstractions for the things we are dealing with. As Edsger W. Dijkstra once put it:
The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise.
Let's imagine we want to give our users a money delivery guarantee - the time in which we promise to deliver their money. One of the use cases might look like this:
As a User
I want to receive a voucher
If the delivery guarantee for my transfer is not met
Again, it looks pretty simple again, right? Of course, we still need to refine it, agree on what the voucher should look like. Yet there is another problem that may not be that evident - we've just introduced new vocabulary.
- What are you talking about? - you may say - It's straightforward. If the transfer takes longer than the guaranteed time, we issue a voucher, and that's all.
Ok, we can run with that. Just tell me one more thing: how will you know how long the transfer takes?
- Well, we will measure the time from its start to completion.
When does the transfer start and when does it complete, then?
- Ok, I can see what you are doing here. So, let's say it starts when the user pays for it and completes when the transfer is received by the recipient.
Got you. Can we apply this definition to some particular cases? Let's say someone makes a transfer to a mobile money account. Would you say that the transfer is received by the recipient when the money becomes visible on his mobile money account?
- Yes, exactly.
How about cash pickup? Would it be the moment when the recipient picks the money up?
Right. Then if the recipient can't or won't pick the money quickly, the transfer will take longer, and we won't meet the guarantee. Is that correct?
- Well, not exactly. We don't want that, because someone could game the system and always get a voucher. It would be better to consider the transfer as completed when we authorise it, and the money is ready for pick up.
So, you mean to measure the time until the transfer is available to the recipient?
- Precisely. You could say that in the case of mobile money, in contrast to cash pickup, the transfer is available and received at the same time.
Looking at the conversation again, we notice that we went from an entirely new concept of not meeting the guarantee, though a bunch of vague terms, like:
- time taken by a transfer
- transfer start and completion
- transfer received by the recipient
The reason they are vague is simple: they have never been defined. Those terms are like the corridor - everyone has some idea what they mean and, usually, those meanings were assumed in a top-to-bottom or an a priori fashion. They are not rooted in the reality that the transfer attempts to abstract from. During the conversation, we were actually looking for their actual meaning.
In the end, we settled on a new term: transfer available to the recipient. But why is it better than the former names? Well, this time we've analysed specific cases, things that the transfer stands for, and found out that the qualifiers that we use with the transfer are not rich enough to express the complexity of the underlying reality. We had to add a new one, but this time it was defined bottom-up or a posteriori.
Coding is a method of building shared knowledge, and as any learning process is not linear. As we increase our experience, we often notice new relations and find new meanings. We should regularly exploit our improved understanding to simplify our systems. Firstly, by agreeing on new models, followed by necessary refactorings of our code. And that can only happen when we pay attention to any ambiguities or contradictions - they are always a sign of a new discovery.