ReVersioning Issues With Abstract Base Classes and Interfaces

time to read 4 min | 686 words

Phil Haack is talking about why the MS MVC team changed IHttpContext to HttpContextBase. I follow the argument, but at some point, I just lost it. This, in particular, had me scratching my head in confusion:

Adding this method doesn’t break older clients. Newer clients who might need to call this method can recompile and now call this new method if they wish. This is where we get the versioning benefits.

How on earth does adding a new method to an interface would break an existing client? How on earth does adding a new method to an interface require a compilation from client code. Now, to be clear, when I am talking about changing the interface I am talking solely about adding new methods (or overloads), not about changing a method signature or removing a method. Those are hard breaking changes no matter what approach you take. By adding a method to an interface? That is mostly harmless.

The only thing that require that is if you are implementing this interface, not if you are using it. It is possible that Phil is using the term clients in a far wider meaning than I would put on this, but this is not the general use of the term as I see it.

Prefer abstract classes to interfaces, use internals and no virtual by defaults are three of the main issues that I have with the framework design guidelines. I have major issues with them because they are actively harming the users of the framework. Sure, it might make my work as a framework developer harder, but guess what, that is my job as a framework developer, to give the best experience that I can to my users. [Framework Design Guidelines rant over]

Now, I do believe that I have some little experience in shipping large frameworks and versioning them through multiply releases and through a long period of time. I also believe that some of those frameworks are significantly larger and more complex than what the MS MVC is going to be. (Hint, if MS MVC even seems, by an illiterate drunken sailor on a rainy day, to approach NHibernate's complexity, it is time to hit the drawing board again).

And those frameworks are using frameworks to do pretty much everything. And I cannot recall off hand any breaking change that resulted from that. In some cases, where the interface is an extension point into the framework, we have gone with interface + base class with default functionality. If you use the base class, you are guaranteed no breaking change. The reasoning for an interface is that it is giving the user more choice, you aren't limiting the options that the user have when it comes to use this (by taking out the single inheritance slot, for example).

Now, if we analyze the expected usage of IHttpContext for a moment, who is going to be affected by changing this interface? Only implementers. Who is going to implement IHttpHandler? I can think of only two scenarios. Hand rolled test fakes and extending the Http Context in some interesting ways, perhaps by adding proxies or decorators to it.

In the first case, that is no something that I would worry about. The second is far rarer but also the much more interesting case, but those are generally not done by hand (I wouldn't want to type all the methods of IHttpContext, that is for sure). Even if it was, I still have no issue with it. New framework version, add a method. It is not a significant change. A significant change would require me to rework large swathes of my application.

Now, why do I care for that?

The reason is very simple. It is a pain to me, personally, when I end up running into those warts. It is annoying, frustrating and aggravating. I like to be happy, because otherwise I am not happy, so I try to minimize my exposure to the afore mentioned warts. Hopefully, I can make them go away entirely. And not just by pulling the blanket over my head.

More posts in "Re" series:

  1. (19 Aug 2019) The Order of the JSON, AKA–irresponsible assumptions and blind spots
  2. (10 Oct 2017) Entity Framework Core performance tuning–Part III
  3. (09 Oct 2017) Different I/O Access Methods for Linux
  4. (06 Oct 2017) Entity Framework Core performance tuning–Part II
  5. (04 Oct 2017) Entity Framework Core performance tuning–part I
  6. (26 Apr 2017) Writing a Time Series Database from Scratch
  7. (28 Jul 2016) Why Uber Engineering Switched from Postgres to MySQL
  8. (15 Jun 2016) Why you can't be a good .NET developer
  9. (12 Nov 2013) Why You Should Never Use MongoDB
  10. (21 Aug 2013) How memory mapped files, filesystems and cloud storage works
  11. (15 Apr 2012) Kiip’s MongoDB’s experience
  12. (18 Oct 2010) Diverse.NET
  13. (10 Apr 2010) NoSQL, meh
  14. (30 Sep 2009) Are you smart enough to do without TDD
  15. (17 Aug 2008) MVC Storefront Part 19
  16. (24 Mar 2008) How to create fully encapsulated Domain Models
  17. (21 Feb 2008) Versioning Issues With Abstract Base Classes and Interfaces
  18. (18 Aug 2007) Saving to Blob
  19. (27 Jul 2007) SSIS - 15 Faults Rebuttal
  20. (29 May 2007) The OR/M Smackdown
  21. (06 Mar 2007) IoC and Average Programmers
  22. (19 Sep 2005) DLinq Mapping