I just had an internal discussion about it, and in the end I wrote this play, which, I think, is too good not to share. I copy it here (almost) unedited, but although it is part of a larger internal discussion, I think that most of it can stand alone.
The introduction of a user interface called IPurchaseReceiptService and whether it should be replaced using IObserver<T> .
Well, I can’t say that I have strong data on any of them - these are just some theories that I pursue ... However, my theory of cognitive overhead at the moment looks something like this: consider your special IPurchaseReceiptService :
public interface IPurchaseReceiptService { void SendReceipt(string transactionId, string userGuid); }
If we save it as a Header Interface , at the moment it has only one SendReceipt method. That's cool.
What is not so cool is that you had to come up with a name for the interface and a different name for this method. There is a little overlap between the two: the word Receipt appears twice. IME, sometimes this overlap can be even more pronounced.
In addition, the interface name is IPurchaseReceiptService , which is also not very useful. The service suffix, in fact, is the new Manager and is IMO, a designer scent.
In addition, you should not only name the interface and method, but also must specify the variable when using it:
public EvoNotifyController( ICreditCardService creditCardService, IPurchaseReceiptService purchaseReceiptService, EvoCipher cipher )
At that moment, you essentially said the same thing three times. This, according to my theory, is cognitive overhead, and the smell that design could and should be simpler.
Now compare this using a well-known interface such as IObserver<T> :
public EvoNotifyController( ICreditCardService creditCardService, IObserver<TransactionInfo> purchaseReceiptService, EvoCipher cipher )
This allows you to get rid of bureaucracy and reduce its essence. You still have an intention showing the names - you simply shift the design from the Type Role Type hint to the Name Argument Role Hint .
When it comes to discussing “incoherence,” I don't suspect that using IObserver<T> magically fix this problem, but I have a different theory about it.
My theory is that the reason many programmers find programming for interfaces so complex is because they are used in Visual Studio. Go to the definition function (by the way, this is another example of how a tool rots the mind ). These programmers are constantly in a state of mind, where they need to know what is "on the other side of the interface." Why is this? Maybe because abstraction is bad?
This is due to RAP , because if you confirm the opinion of programmers that there is one specific implementation for each interface, it is not surprising that they think that interfaces are only on the way.
However, if you use RAP, I hope that slowly, programmers will find out that there may be some implementation of this interface behind a particular interface, and their client code should be able to handle any implementation of this interface without changing the correctness of the system. If this theory is correct, we just added the “Liskov Substitution Principle” to the code base without scaring anyone with concepts with high eyebrows that they don’t understand :)