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. (09 Dec 2021) Why IndexedDB is slow and what to use instead
  2. (23 Jun 2021) The performance regression odyssey
  3. (27 Oct 2020) Investigating query performance issue in RavenDB
  4. (27 Dec 2019) Writing a very fast cache service with millions of entries
  5. (26 Dec 2019) Why databases use ordered indexes but programming uses hash tables
  6. (12 Nov 2019) Document-Level Optimistic Concurrency in MongoDB
  7. (25 Oct 2019) RavenDB. Two years of pain and joy
  8. (19 Aug 2019) The Order of the JSON, AKA–irresponsible assumptions and blind spots
  9. (10 Oct 2017) Entity Framework Core performance tuning–Part III
  10. (09 Oct 2017) Different I/O Access Methods for Linux
  11. (06 Oct 2017) Entity Framework Core performance tuning–Part II
  12. (04 Oct 2017) Entity Framework Core performance tuning–part I
  13. (26 Apr 2017) Writing a Time Series Database from Scratch
  14. (28 Jul 2016) Why Uber Engineering Switched from Postgres to MySQL
  15. (15 Jun 2016) Why you can't be a good .NET developer
  16. (12 Nov 2013) Why You Should Never Use MongoDB
  17. (21 Aug 2013) How memory mapped files, filesystems and cloud storage works
  18. (15 Apr 2012) Kiip’s MongoDB’s experience
  19. (18 Oct 2010) Diverse.NET
  20. (10 Apr 2010) NoSQL, meh
  21. (30 Sep 2009) Are you smart enough to do without TDD
  22. (17 Aug 2008) MVC Storefront Part 19
  23. (24 Mar 2008) How to create fully encapsulated Domain Models
  24. (21 Feb 2008) Versioning Issues With Abstract Base Classes and Interfaces
  25. (18 Aug 2007) Saving to Blob
  26. (27 Jul 2007) SSIS - 15 Faults Rebuttal
  27. (29 May 2007) The OR/M Smackdown
  28. (06 Mar 2007) IoC and Average Programmers
  29. (19 Sep 2005) DLinq Mapping