Events as Interfaces?

I believe there used to be documentation that explained why modelling events as interfaces was generally considered to be a good practice.

It’s possible it was a blog post that was referenced in the docs, or maybe just referenced from a posting on the mailing list. In any case, if anyone knows what I’m talking about, can you post the link?

Maybe a better question: is this still considered a best practice?

Quick Edit: to be clear, I am aware of this bit in the docs: https://docs.particular.net/nservicebus/messaging/messages-as-interfaces

Hi @Phil_Sandler,

unfortunately I don’t have any link to share. However I still consider it a best practice, mainly for the following reasons:

  • interfaces in .NET allow for a kind of multi-inheritance support making it easier to evolve existing messages/contracts as different subscribers can have different views of what is the same message from the publisher perspective
  • I like the fact that interfaces allow to express, in a simpler way, the fact that a message is immutable, like events should be. Take a look at the following sample I built to demonstrate that: https://github.com/mauroservienti/immutable-message-samples

.m

1 Like

I agree with Mauro that interface should be used when multiple inheritance is needed.

While I agree that the immutable angle that also was brought up is important I have personally been a bit restrictive on using interfaces “for all the things” based on the following reasons:

  • Not all serializers can handle them (xml is the only one that fully does, json.net can be hacked to do it)
  • Sagas doesn’t support handling more than one of the interfaces of the same message
  • They technically makes contract evolution break Semver since adding a property to an interface is a breaking change. While this doesn’t apply in this use case it opens up for discussions around what other things to “exclude from Semver” and make it harder to spot other breaking changes like changing type etc. The solution is to create new versions by having v2 inherit from the v1 interface but in my experience that’s not always an easy sell to the rest of the team.
  • I have seen them lead to bad naming when companies strictly apply the good ol "prefix interfaces with I" rule. IOrderPlaced :grimacing: (yes I’m old)
  • Harder to explain to the team since interfaces makes people assume that there are some implementation somewhere and you have to explain that it’s “NServiceBus magic”
  • I have seen them being confused with the IEvent marker interface leading to interesting bugs

TL;DR; Use interfaces with caution, my personal recommendation is to start with classes and introduce interfaces once the need arise.

2 Likes

Thanks Mauro and Andreas! Some great things to think about here on both sides.