Versioning Issues With Abstract Base Classes and Interfaces

dotnet code versioning 0 comments suggest edit

Eilon Lipton recently wrote a bit about context objects in ASP.NET MVC and in an “Oh by the way” moment, tossed out the fact that we changed the IHttpContext interface to the HttpContextBase abstract base class (ABC for short).

Not long after, this spurred debate among the Twitterati. Why did you choose an Abstract Base Class in this case? The full detailed answer would probably break my keyboard in length, so I thought I would try to address it in a series of posts.

In the end, I hope to convince the critiques that the real point of contention is about maintaining backwards compatibility, not about choosing an abstract base class in this one instance.

Our Constraints

All engineering problems are about optimizing for constraints. As I’ve written before, there is no perfect design, partly because we’re all optimizing for different constraints. The constraints you have in your job are probably different than the constraints that I have in my job.

For better or worse, these are the constraints my team is dealing with in the long run. You may disagree with these constraints, so be it. We can have that discussion later. I only ask that for the time being, you evaluate this discussion in light of these constraints. In logical terms, these are the premises on which my argument rests.

  • Avoid Breaking Changes at all costs
  • Allow for future changes

Specifically I mean breaking changes in our public API once we RTM. We can make breaking changes while we’re in the CTP/Beta phase.

You Can’t Change An Interface

The first problem we run into is that you cannot change an interface.

Now some might state, “Of course you can change an interface. Watch me! Changing an interface only means some clients will break, but I still changed it.

The misunderstanding here is that after you ship an assembly with an interface, any changes to that interface result in a new interface. Eric Lippert points this out in this old Joel On Software forum thread

The key thing to understand regarding “changing interfaces” is that an interface is a _type_.  A type is logically bound to an assembly, and an assembly can have a strong name.

This means that if you correctly version and strong-name your assemblies, there is no “you can’t change this interface” problem.  An interface updated in a new version of an assembly is a _different_ interface from the old one.

(This is of course yet another good reason to get in the habit of strong-naming assemblies.)

Thus trying to make even one tiny change to an interface violates our first constraint. It is a breaking change. You can however add a new virtual method to an abstract base class without breaking existing clients of the class. Hey, it’s not pretty, but it works.

Why Not Use An Interface And an Abstract Base Class?

Why not have a corresponding interface for every abstract base class? This assumes that the purpose of the ABC is simply to provide the default implementation of an interface. This isn’t always the case. Sometimes we may want to use an ABC in the same way we use an interface (all methods are abstract…revised versions of the class may add virtual methods which throw a NotImplementedException).

The reason that having a corresponding interface doesn’t necessarily buy us anything in terms of versioning, is that you can’t expose the interface. Let me explain with a totally contrived example.

Suppose you have an abstract base class we’ll randomly call HttpContextBase. Let’s also suppose that HttpContextBase implements an IHttpContext interface. Now we want to expose an instance of HttpContextBase via a property of another class, say RequestContext. The question is, what is the type of that property?

Is it…

public IHttpContext HttpContext {get; set;}

? Or is it…

public HttpContextBase HttpContext {get; set;}

If you choose the first option, then we’re back to square one with the versioning issue. If you choose the second option, we don’t gain much by having the interface.

What Is This Versioning Issue You Speak Of?

The versioning issue I speak of relates to clients of the property. Suppose we wish to add a new method or property to IHttpContext. We’ve effectively created a new interface and now all clients need to recompile. Not only that, but any components you might be using that refer to IHttpContext need to be recompiled. This can get ugly.

You could decide to add the new method to the ABC and not change the interface. What this means is that new clients of this class need to perform an interface check when they want to call this method every time.

public void SomeMethod(IHttpContext context)
{
  HttpContextBase contextAbs = context as HttpContextBase;
  if(contextAbs != null)
  {
    contextAbs.NewMethod();
  }
    
  context.Response.Write("Score!");
}

In the second case with the ABC, you can add the method as a virtual method and throw NotImplementedException. You don’t get compile time checking with this approach when implementing this ABC, but hey, thems the breaks. Remember, no perfect design.

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.

So Why Not Keep Interfaces Small?

It’s not being small that makes an interface resilient to change. What you really want is an interface that is small and cohesivewith very little reason to change. This is probably the best strategy with interfaces and versioning, but even this can run into problems. I’ll address this in more detail in an upcoming post, but for now will provide just one brief argument.

Many times, you want to divide a wide API surface into a group of distinct smaller interfaces. The problem arises when a method needs functionality of several of those interfaces. Now, a change in any one of those interfaces would break the client. In fact, all you’ve really done is spread out one large interface with many reasons to change into many interfaces each with few reasons to change. Overall, it adds up to the same thing in terms of risk of change.

Alternative Approaches

These issues are one of the trade-offs of using statically typed languages. One reason you don’t hear much about this in the Ruby community, for example, is there really aren’t interfaces in Ruby, though some have proposed approaches to provide something similar. Dynamic typing is really great for resilience to versioning.

One thing I̻’d love to hear more feedback from others is why, in .NET land, are we so tied to interfaces? If the general rule of thumb is to keep interfaces small (I’ve even heard some suggest interfaces should only have one method), why aren’t we using delegates more instead of interfaces? That would provide for even looser coupling than interfaces.

The proposed dynamic keyword and duck-typing features in future versions of C# might provide more resilience. As with dynamically typed languages such as Ruby, the trade-off in these cases is that you forego compile time checking for run-time checking. Personally, I think the evidence is mounting that this may be a worthwhile tradeoff in many cases.

For More On This

The Framework Design Guidelines highlights the issues I covered here well in chapter 4 (starting on page 11). You can read chapter 4 from here. In particular, I found this quote quite interesting as it is based on the experience from other Framework developers.

Over the course of the three versions of the .NET Framework, I have talked about this guideline with quite a few developers on our team. Many of them, including those who initially disagreed with the guideline, have said that they regret having shipped some API as an interface. I have not heard of even one case in which somebody regretted that they shipped a class.

Again, these guidelines are specific to Framework development (for statically typed languages), and not to other types of software development.

What’s Next?

###

If I’ve done my job well, you by now agree with the conclusions I put forth in this post, given the constraints I laid out. Unless of course there is something I missed, which I would love to hear about.

My gut feeling is that most disagreements will focus on the premise, the constraint, of avoiding breaking changes at all costs. This is where you might find me in some agreement. After all, before I joined Microsoft, I wrote a blog post asking, Is Backward Compatibility Holding Microsoft Back? Now that I am on the inside, I realize the answer requires more nuance than a simple yes or no answer. So I will touch on this topic in an upcoming post.

Other topics I hope to cover:

  • On backwards compatibility and breaking changes.
  • Different criteria for choosing interfaces and abstract base classes.
  • Facts and Fallacies regarding small interfaces.
  • Whatever else crosses my mind.

My last word on this is to keep the feedback coming. It may well turn out that based on experience, HttpContextBase should be an interface while HttpRequest should remain an abstract base class. Who knows?! Frameworks are best extracted from real applications, not simply from guidelines. The guidelines are simply that, a guide based on past experiences. So keep building applications on top of ASP.NET MVC and let us know what needs improvement (and also what you like about it).

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

39 responses

  1. Avatar for Damien Guard
    Damien Guard February 20th, 2008

    I'd love C# to gain the ability to autowire an interface to an instance object so you could in your above example do something like;
    public class HttpContext : IHttpContext goto BaseHttpContext
    {
    private BaseHttpContext internalHttpContext;
    }
    Which would mean you could extend IHttpContext because you'd update the default behaviour for new methods in BaseHttpContext.
    It would also make composition at lot easier http://damieng.com/blog/200...
    [)amien

  2. Avatar for Shawn Oster
    Shawn Oster February 20th, 2008

    Interfaces are the devil and I think they should be avoided at all costs.
    I used to think they were great, that they provided powerful flexibility and made everything easier but after dealing with just one round of needing to add a single property or method to an interface I discovered their horror. I've spent months going through systems removing all the interfaces like pulling weeds.
    The versioning issue is a nightmare and I cringed when you said "...this means is that new clients of this class need to perform an interface check when they want to call this method every time...". I've discovered that developers almost never check, they just grab the new methods and assume the system has the latest and greatest thus causing themselves and their clients no end of frustration. I can completely see why other framework developers came to the same conclusion, it puts burden on everyone and doesn't make anyone's life easier.
    Hate interfaces... :)
    Off-topicish feedback, the ASP.NET MVC framework needs some conventions set down now because already I'm seeing MVC projects that put assets in different locations, that are using various folder names for the same types of things, some are calling things "helpers" others call the same "utilities". One of the major things that makes Rails so powerful as a framework isn't just MVC or ActiveRecord, it's *convention*. A Rails developer can walk up to any Rails project and know instantly where everything is, knows exactly what is contained in that vendor folder, how the database columns are named and what type of code the helpers contain.
    A lot of ASP.NET devs are sort of wandering around stuffing things wherever, sorta lost and making it up as they go which just wastes time and prevents the real work from happening. There needs to be a Code Tzar inside the MVC camp that says, This Is How It Is, similar to how David Heinemeier Hansson is for the Rails camp.
    Just a wee bit of feedback :)

  3. Avatar for Chad Lee
    Chad Lee February 20th, 2008

    "Suppose we wish to add a new method or property to IHttpContext. We’ve effectively created a new interface and now all clients need to recompile."
    Who doesn't expect to have to recompile their application with a new version of the .Net Framework? The whole premise of that argument seems ridiculous to me.
    Fight the man, Phil - instead of explaining to us why the koolaid tastes so good...
    :)

  4. Avatar for Kristof Verbiest
    Kristof Verbiest February 20th, 2008

    I've always seen ABC as the acronym for an abstract base class. It makes much more sense than this ABS that you use.

  5. Avatar for Ian Cooper
    Ian Cooper February 20th, 2008

    I disagree with the constraints you have. How do you get them changed?
    Changing an interface should be a breaking change. I guess that Chad might be saying the same thing. A contract, which is an interface, should be enforceable by both parties. You should not be able to change the contract without my knowing about it. Either, negotiate a new contract i.e. add another interface, or negotiate an amendment to that contract i.e. ship a breaking change.
    If your constraints are your problem, solve the problem. If you can't at least just come out and say that your constraints prevent you doing the right thing.
    That remark from the Framework Design Guidelines is bunkum. We experience pain because you don't ship interfaces. You may not, but we do.

  6. Avatar for Chad Myers
    Chad Myers February 20th, 2008

    Converting HttpContext to either IHttpContext or HttpContextBase doesn't solve much. If you're going to do that, then just use HttpContextBase, but for the love of God, please make everything public virtual and have an empty constructor (or at least a public one that we can fully satisfy).
    HttpContext is a huge separation of responsibilities principle violator... it has error handling, profile binding, HTTP stuff (request/response), session, etc.
    HttpContext is both a hub class (static service locater essentially) and a main functionality class. This is not good.
    That's why you're so afraid to go with an interface. Solve that problem and this wouldn't be that big of a deal.
    Separate the AddError/GetError stuff out. Separate the HTTP stuff out (request/response), separate the session stuff out.
    We were howling for IHttpContext because it was the best we hoped to get, but now that you guys are talking honestly and openly about re-architecting some of this (AWESOME!) let's have a full-on architecture discussion.
    Have you considered using DI and IoC (Unity?) to compose the current request context situation? Why not allow us to change and compose how the request context looks so that we can avoid some of these versioning issues altogether?
    You can keep adding functionality in the form of new interfaces and ABS' without breaking existing functionality. The HttpRequest interface hasn't changed much since ASP 3.0, really. Same for HttpResponse, same for SessionState, etc.
    What I'm sure you're really concerned about is when something new like Profile or Membership comes along, how do you do that without breaking all those custom IHttpContext impls, right? Well, think about what I said above and it wouldn't matter in the first place.

  7. Avatar for Pawel Pabich
    Pawel Pabich February 20th, 2008

    Why not to follow Eric Lippert hint? If an app is working fine on .NET 3.0 and needs to be ported to let's say .NET 4.0 then it should be recompiled against that version of the framework and all new methods on a given interface should be implemented. Why do you have to insist that 10 years old app that was originally developed for .NET 1.0 needs to be able to run on .NET 4.0 with no changes? This approach constraints your velocity and in a few years you won't be able to innovate. Sure, abstract class would help but only if all public methods/properties were virtual. Are you going to do this?

  8. Avatar for Bill Pierce
    Bill Pierce February 20th, 2008

    In what situation will I NOT have to re-compile my code when a new version of System.Web.Extensions is released? Are you saying there is a way that my code will automatically start using 3.7.0.0 instead of 3.6.0.0?
    How does adding a new virtual method that throws NotImplementedExcpetion not break my code? If I do not recompile then anytime that new method is called I get an unhanded exception?
    Your rationale has not convinced me that I am any better off with an abstract base class instead of an interface. At least with an Interface I know right away that the contract has changed.

  9. Avatar for Kevin Dente
    Kevin Dente February 20th, 2008

    >Who doesn't expect to have to recompile their
    >application with a new version of the .Net
    >Framework?
    Uh, yeah, that would be me. I was quite happy to not have to recompile our apps when 3.5 came out. I'm quite happy that I only need one version of Reflector, not one per framework version. Same with SQL Server. Windows Live Writer. etc, etc, etc

  10. Avatar for Ian Rae
    Ian Rae February 20th, 2008

    More of this please! Versioning is an important and under-discussed problem.
    I like the fact that interfaces ensure (at compile time) I've implemented all the methods. Giving this up would be like going back to VB or Fortran where declaring variables was optional, so a mispelt var would be silently accepted. Some sort of C# lint tool could detect unimplemented ABS methods.

  11. Avatar for Jacob
    Jacob February 20th, 2008
    One thing I'd love to hear more feedback from others is why, in .NET land, are we so tied to interfaces?


    I think a major driver of this is IoC and DI frameworks. Most of the DI frameworks utilize interfaces heavily. They could as easily use base classes, but all the examples and "best practice" assumptions I've seen are built around interfaces. This reinforces the impression that an interface is the way to go if you want a compiler-enforced contract that defers implementation.

  12. Avatar for Chad Myers
    Chad Myers February 20th, 2008

    We're tied to interfaces because the whole original point of interfaces: To define a simple contract of interaction, but allow wildly differing implementations of that contract.
    This has nothing to do with IoC/DI, even though, IMHO, IoC/DI are a good reason in and of themselves.
    I was doing interface-based API's before doing interface-based API's in .NET were cool :) (before I ever heard of IoC/DI).
    And it worked very well and allowed tons of flexibility for my customers and opened up a lot of options for us to deliver very different functionality for different circumstances without breaking customer applications written to our APIs

  13. Avatar for Scott
    Scott February 20th, 2008

    So I guess my question is, why do you need HttpContext at all?
    Is it just for interoperability with WebForms?

  14. Avatar for Haacked
    Haacked February 20th, 2008

    @Chadmyers I agree, HttpContext is a bit of a mess. If we had to start from scratch, I'd do it differently. Keep in mind, we're not changing the core HttpContext class. The best we can do is wrap it? Now theoretically we could wrap it with a set of classes that then compose together to provide the set of functionality that HttpContext does, but that's a bit of a nightmare as well.
    Instead, we've chosen to wrap the "real" HttpContext with an HttpContextWrapper that implements HttpContextBase. HttpContextBase, for all intents and purposes, is an interface because it doesn't contain any implementation. At this point it is pure contract, so it meets the goal you mentioned...


    We're tied to interfaces because the whole original point of interfaces: To define a simple contract of interaction, but allow wildly differing implementations of that contract.


    HttpContextBase allows for that. Of course, it has the limitation that you can't inherit from it and another class because it's really an ABC. Like I said, no perfect design.
    As for whether HttpContext changes, I can't remember if it's HttpContext or HttpRequest, but I know there are upcoming changes in ASP.NET 3.5 SP1 to one of the intrinsic classes. That's what raised this issue because MVC needs to work without taking that dependency.

  15. Avatar for Haacked
    Haacked February 20th, 2008

    @ChadLee
    When .NET 3.5 SP1 comes out, you're fine with recompiling all your apps and all the components/libraries that your app uses? Seems like a reasonable thing to expect that you won't have to. Assembly redirects are very useful in this case.
    And the remark about Kool-Aid, seriously. Please point out the flaws in my argument given the premises. I'm happy to listen. You mentioned you disagree with the premises. Great! I said I'll address that in an upcoming post, and I even posted a link in which I questioned those premises. Let's leave flippant attacks on my character out of this. I'm not peddling kool-aid.

  16. Avatar for Haacked
    Haacked February 20th, 2008

    @ChadMyers I've thought about IoC and Unity, but man, do I really want to take the beating that the Unity guys are taking from various members of the community? ;)
    I brought this up and there were certain issues internally with doing such a thing for this Framework. I need to refresh my memory on what they were. The thing is, at this point, there may not be much hope for the http intrinsics.
    We kept close to the http intrinsics current impl. We couldn't rewrite them, etc. Not enough time and resources.

  17. Avatar for Haacked
    Haacked February 20th, 2008

    re: Constraints
    I never said I love these constraints. I'm just saying they're there. I've done my part to question them and in hearing the answers, realize it's not black or white.
    No matter what I think, changing them is not so easy. Think of your own workplace. I'm sure you have constraints you wish you could change, but can't. So you optimize for the constraints.
    Again, I'll write about that in an upcoming post, and *then* you can skewer me for peddling Kool-Aid. ;)

  18. Avatar for Haacked
    Haacked February 20th, 2008

    @chadmyers I forgot to finish my thought... ;)
    However, MVC itself does have its own context objects (ControllerContext) and I'm investigating some interesting refactorings (based on community feedback as well as my own unit testing problems) that I think will really improve the extensibility, composition, etc... story for MVC. Although you won't see those particular changes at Mix. Maybe the next release if this pans out.

  19. Avatar for Mark Pflug
    Mark Pflug February 20th, 2008

    The Ado.net team went with ABCs in designing the provider model with 2.0. Each of these ABCs in turn implemented a corresponding interface that existed in 1.1. Since the DbProviderFactory returns ABCs from each of its CreateXXX methods, the interfaces were rendered useless for the same reasons you pointed out. For the most part it works well.
    However, take the DbCommandBuilder ABC as an example of what not to do when implementing ABCs. Its three main public methods, Create(Insert/Update/Delete)Command(), are non-virtual which means that derived classes are extremely limited in what they can do to alter the behavior, and are effectively tied to an implementation that may not work for what they are trying to accomplish (as was the case for me...).

  20. Avatar for Evan
    Evan February 20th, 2008

    "One thing I’d love to hear more feedback from others is why, in .NET land, are we so tied to interfaces? If the general rule of thumb is to keep interfaces small (I’ve even heard some suggest interfaces should only have one method), why aren’t we using delegates more instead of interfaces? That would provide for even looser coupling than interfaces"
    Because much of what's happening on the .NET side (design-wise) is catch-up to Javaland and 20 year old techniques from C++. Unless it's changed recently (I'm not a java guy), they don't even have delegates in Java. If you look at the big picture, you will see where their design material has bled into and influenced the .NET world.
    Wiring with delegates and wiring with interfaces require different tooling and different thought processes. Given the resistance of people to adapt to building with interfaces (the easiest to grasp), I hold out little hope for the community to fully leverage an event-driven solution like what you would have with delegate wiring. At least not for several years anyway. It's a greater paradigm shift than classic interface-based design school of thought.
    It's not unheard of though. I can recommend the following book:
    http://www.amazon.com/Event...
    HTH,
    Evan

  21. Avatar for Justin Rudd
    Justin Rudd February 20th, 2008

    My only concern in the interface vs. abstract base class war is C# only allows for a single base class. Now in this case, maybe it isn't a big deal because really how often are we (users of ASP.NET MVC) going to be deriving from HttpContextBase? Unit tests only? Are you guys really implementing IHttpContext in your applications?
    Which brings up, if I'm using IHttpContext and not implementing, if a new method is added, aren't I insulated from the change? It would seem the design advice about interface vs. abc is really only applicable if the interface is meant to be implemented by an end user.

  22. Avatar for John Lopez
    John Lopez February 20th, 2008

    Concealing a change behind smoke and mirrors really seems to miss the point of interfaces. Especially concealing the change with a potential for run time errors (and no "them's the breaks" really isn't reassuring). An interface is a promise; new features should really be a *new promise* and thus behind a new interface.
    In our systems old interfaces remain in place but are obsoleted over time. Do we expect to recompile for 3.5 SP1? Of course not, but I am not surprised if a new interface for old functionality becomes available. Nor am I surprised if the old interface is marked obsolete and in the next major version we are expected to compile against the new interface and even make code changes over time.
    I love static typing *because* it makes such things explicit at compile time and avoids the kinds of nonsense you see in DotNetNuke with "unable to load assembly" runtime errors being a favorite pastime. What am I missing here?

  23. Avatar for Jay R. Wren
    Jay R. Wren February 20th, 2008

    "You don’t get compile time checking with this approach when implementing this ABC, but hey, thems the breaks."
    Yes, them is the breaks. If I wanted this situation I would write in Ruby or Python or some place which doesn't give me compile time checking.
    Worse yet, your behavior is now dependent on the type of IHttpContext that I send the method. This STINKS(as in code smell). It sounds like a violation of SRP.
    Please don't behave differently just because my implementation of IHttpConext isn't your Base impl. You are treat me like a jerk. I'm not a jerk. I swear. If you want HttpContextBase behavior, then put the behavior IN HttpContextBase!

  24. Avatar for Jeff Atwood
    Jeff Atwood February 20th, 2008
    The constraints you have in your job are probably different than the constraints that I have in my job.


    And if you don't like those constraints, it's time to quit your job. Most people don't have the wherewithal to make this deep of a change in their lives.

  25. Avatar for Rob Conery
    Rob Conery February 21st, 2008

    The two lines of wisdome from @Atwood... how helpful :p
    @Shawn Oster: With regards to the "Convention" stuff - that's my job with SubSonic. MS has never been of the mind to offer convention to the customer base, but they do see the value in precisely what you're asking for.
    I'm on it (I made you a committer didn't I? YOU get on it! :):)) and am sitting tight for the next CTP.
    Phil - Love you man!

  26. Avatar for Shawn Oster
    Shawn Oster February 21st, 2008

    So far in all of this back and forth I've only heard theory on why people are so passionate about having an interface vs. an ABC. This reminds me *exactly* of design meetings where someone argues up and down for abstracting out the data access layer even farther so they can easily swap DB's down the road and in all those times the backend is never switched, never touched and instead developers trip over that worthless layer.
    I completely agree HttpContext is a 35-year old fat guy trying to pass himself off as baby in a buggy and no one is buying the rattle and bonnet but what are the real, solid, concrete, make my development life better reasons for going IHttpContext vs. HttpContextBase? The only one I can think of is IoC/DI which I'm not sold on as being enough of a reason. Someone enlighten me on exactly what they'd do if they had IHttpContext, not "I could..." but "I would, a week after it was released, do X, Y and Z and I'd put money on it."

  27. Avatar for Francois Tanguay
    Francois Tanguay February 21st, 2008

    The last thing I want to do after I've referenced an assembly and developed a whole application around it is to change the version of the assembly I'm running upon!
    Would you really want to be able to just overwrite you're running app with a version 2.0 of a Grid Control when you're referencing version 1.0 and expect everything to work just fine?
    The first rule of package dependency is to choose one version, test everything against it, run with it and stick to it.
    If there is one thing you'll be sure to do when upgrading version, is recompile, run UTs, test plenty and test again!

  28. Avatar for krzysztof Cwalina
    krzysztof Cwalina February 21st, 2008

    Hi to all,
    Since I am responsible for the guideline (interfaces vs. ABC) and it’s a really interesting and passionate discussion, I thought I would provide some of my thoughts on this.
    “Who doesn't expect to have to recompile their application with a new version of the .Net Framework? The whole premise of that argument seems ridiculous to me.”
    “Why do you have to insist that 10 years old app that was originally developed for .NET 1.0 needs to be able to run on .NET 4.0 with no changes?”
    Many of our customers don’t want to recompile when they move to a new Framework version. Many would not have a problem with having to recompile. Both groups have valid reasons for their preferences, but we can only serve them all by not requiring recompiling. BTW, the first group does not want to recompile because for example they write client apps that are harder to redeploy, don’t want to spend resources on porting, use third party libraries (which would need to be recompiled), lost their source code, and many other reasons.
    “That remark from the Framework Design Guidelines is bunkum. We experience pain because you don't ship interfaces. You may not, but we do.”
    I think you experience pain because we don’t have the right extensibility points in the Framework, not because we don’t ship interfaces. One way to address the problem is for the community to give us feedback on which parts of the Framework are not extensible enough. We are super interested and will seriously look into these suggestions. I really strongly feel that shipping more interface-heavy APIs won’t help and will actually backfire. You can use interfaces all over the place and still have a system that is not extensible. Extensibility needs to be designed. It cannot be created automatically by replacing “class” with “interface”.
    “Sure, abstract class would help but only if all public methods/properties were virtual. Are you going to do this?”
    Yes, Exactly! It’s all about extensibility points design, not about whether it’s a class or an interface. We will not blindly make all members virtual, but we will those that the community needs for extensibility (and we can still design to be safely extensible).
    “It would seem the design advice about interface vs. abc is really only applicable if the interface is meant to be implemented by an end user.”
    I participated in many meeting where we considered a breaking change, decided that the risk of brakes in customers’ code is close to nil, made the change, and then had to revert it in Beta because it was after all breaking many apps. This is the nature of a very large frameworks used by millions of applications. If a change breaks just 0.1% of applications, it still breaks 1000 apps and it costs the customers headaches and money to fix them.
    Don’t get me wrong, we realize that we need to be able to evolve/cleanup the Framework and we are working on technologies that would allow us to do this without breaking customers’ code. For example, moving types across assemblies used to be breaking. Now, with type forwarders, it’s not. We are considering more technologies like that in the future.
    “An interface is a promise; new features should really be a *new promise* and thus behind a new interface. […] What am I missing here?”
    I will try to write a separate post about this at some point, but it’s going to take some time. The best I have now is a video of a presentation where I talk about it. The whole presentation is very long. The part about interfaces starts at 2:54.40. The presentation is at http://www.researchchannel....
    ... that's the longest comment I ever wrote on a blog :-)

  29. Avatar for David Nelson
    David Nelson February 22nd, 2008

    @krzysztof = "Many of our customers don’t want to recompile when they move to a new Framework version. Many would not have a problem with having to recompile. Both groups have valid reasons for their preferences, but we can only serve them all by not requiring recompiling."
    But you are NOT serving them both! You are serving one group by not forcing them recompile, but you are NOT serving the other by limiting your design around this artificial constraint that the other group shouldn't have to recompile, thereby making the design less evolvable. You are not serving them both; you are choosing to serve one instead of the other. This is something that I have been trying to get across to .NET team members for the last several years, but its like I'm banging my head against a brick wall.
    @krzysztof = "I participated in many meeting where we considered a breaking change, decided that the risk of brakes in customers’ code is close to nil, made the change, and then had to revert it in Beta because it was after all breaking many apps. This is the nature of a very large frameworks used by millions of applications. If a change breaks just 0.1% of applications, it still breaks 1000 apps and it costs the customers headaches and money to fix them."
    Yes, it does! So what? Every time the U.S. military plans an operation, the operation includes a concept of acceptable losses, i.e. the maximum number of casualties that can be sustained and still consider the operation a success. The more important the operation, the higher the acceptable losses. If you are saying that when planning a breaking change, acceptable losses of 0.1% of clients is too high, then you will never ship a breaking change! And you are thereby shooting yourself in the foot, and dooming yourself to be the victim of your previous mistakes. This is the road that I think .NET is heading down, and it saddens me greatly that the .NET team is blindly rushing toward the edge of the cliff.
    By the way, I have watched that entire presentation before, and I completely disagree with the vast majority of it. It is predicated on the assumption that most people are stupid and that we should design for the lowest common denominator (most C# programmers don't understand dynamic casts?!?). It also assumes that backward compatibility is the number one design goal of all library developers, which in a very large percentage of cases is not true (but good luck convincing anyone at Microsoft of that). It SCARES ME that this is the thought process that the .NET framework goes through during its design phase. On the other hand, it explains a lot too.

  30. Avatar for David Nelson
    David Nelson February 22nd, 2008

    @Francois "The first rule of package dependency is to choose one version, test everything against it, run with it and stick to it. If there is one thing you'll be sure to do when upgrading version, is recompile, run UTs, test plenty and test again!"
    Absolutely. To say that I should be able to run my deployed application on a new version of the framework that the app has never been tested on is ludicrous. The framework CANNOT guarantee 100% backward compatibility, no matter how hard you try. Therefore the only responsible choice is to only run on versions of the framework on which you have tested. Corporations that say that they want this capability are speaking from ignorance; they don't want to have to do the work of verifying their applications on a new framework version, so instead they want the new framework version to guarantee that it will work with their application, even though it can't possibly make that guarantee. The fact that the .NET design team is perpetuating this absurdity boggles the mind, and forces me to seriously question the commitment of Microsoft to .NET as a long term strategic development platform.

  31. Avatar for Krzysztof Cwalina
    Krzysztof Cwalina February 22nd, 2008


    Sorry, I was not clear when I said that we serve both of the groups. I did not mean that we make the Framework perfect for both of these groups. We are trying to make it the best we can given we have to serve both of these groups. We try really hard not to break customer’s code and we try to design the framework so it’s malleable (abstract classes) and we are adding features to the CLR (like type forwarders) to be able to make breaking changes yet shield customers from them, and we try to serve well the customers who want extensibility. We believe we can do it with well designed abstractions (whether they are abstract classes or interfaces). We sometimes fail here and we would love to hear feedback on where you need more extensibility.
    As to the acceptable loss analysis, we are doing it. We are making some breaking changes in almost every release. The current bar for accepting such changes is very high (security issues pretty much). The bar does not allow for breaking customers because a team wants to add a member to an interface. As I said we are continually looking for ways to allow us more such changes without breaking people.
    Lastly, it’s not about understanding dynamic casts. It’s about self explanatory APIs. I hope you would not like a framework that is full on members returning System.Object and having to down cast to something else to actually use the return value.

  32. Avatar for Chad Myers
    Chad Myers February 22nd, 2008

    I've been thinking a lot on this and trying to come up with a silver bullet and I think as long as the goal is to keep HttpContext somewhat similar to what it is today there is no way out of this pit.
    Leave HttpContext alone and break up everything behind it. Compose HttpContext from all the behind-pieces to preserve WebForms compatability, but for MVC and going forward, have smaller components with interfaces and ABCs that address simple concerns and aren't likely to change much. Provide default compositions of these things using something like IoC or a simple composition wrapper, but allow someone doing alternate impl. or unit testing to pass in mocks of IHttpResponse, IHttpRequest, etc.
    Print big warnings that, for production implementations (i.e. not unit tests), if you derive from the interface, there likely WILL BE breaking changes. You are STRONGLY ADVISED to derive from the abstract base classes (HttpResponseBase, HttpSessionStateBase, etc) if you wish to extend anything. YOU HAVE BEEN WARNED.
    80% of the people will not do either and use everything stock. 19% will use the interfaces for mock testing and won't be too upset if the interface changes in the next update or SP. 1% will actually use an alternative implementation of the interfaces, and will likely be able to handle the complexities (i.e. 'Hot Coffee').

  33. Avatar for Joe Brinkman
    Joe Brinkman February 25th, 2008

    I totally understand Microsoft's position. Having worked on delivering a framework for the last 5 years I know firsthand the pain that is caused when you introduce breaking changes. It is not about the fact that you might break 1000 apps, it is about the fact that you might break applications used by hundreds of thousands of users. One of the "apps" may be a component used in another 1000 apps thereby preventing those dependent apps from being able to upgrade to the latest framework until the component vendor updates their app. This then creates support problems for the component vendor since they now must maintain 2 versions of their application depending on which framework they are compiling against.
    In the end it is very easy to say just break compatability, but if you are not the one who must "support" that decision then maybe you ought to cut MS a little slack. Clearly this is something that they have spent a lot of time agonizing over and whether or not I trust "Microsoft", I certainly trust Scott Guthrie and his team to try to do what is best for the long-term health of the platform.

  34. Avatar for Derek
    Derek March 9th, 2008

    I wonder what the adoption rate would have looked like had there been major breaking changes from .Net 1.1 to 2.0. Would we have seen a lot more companies hesitant to upgrade? If so, I wonder how that might have affected the career progression of all those who hound Microsoft for trying to stay backward compatible. Something to think about ...

  35. Avatar for David Nelson
    David Nelson March 9th, 2008

    @Derek,
    I wonder what would have happened if Microsoft had chosen to fix the many bugs and reimplement the many poorly designed features that have been reported in .NET 1.1 and 2.0, even if it would have resulted in more breaking changes. Would we have seen a lot fewer companies implement costly workarounds or completely recreate a portion of the framework which didn't meet their needs? Would that have resulted in shorter project turnarounds and greater productivity across the board? Would that in turn have created greater confidence and buy-in to the framework, and accelerated adoption of future versions? I guess we'll never know...

  36. Avatar for Scott
    Scott March 16th, 2008

    I know a big reason the we in .Net land are tied to interfaces, is because .Net land doesn't allow multiple inheritance of classes.

  37. Avatar for haacked
    haacked November 13th, 2008

    This made me smile today. http://hammett.castleproject.org/?p=333

  38. Avatar for Suresh
    Suresh December 8th, 2008

    Hello all.. I am new to Interface versioning concept..Can anyone please explain that how to do interface versioning?

  39. Avatar for SMM
    SMM November 15th, 2010

    Let's look at the possible scenarios and why MS chose the wrong one.
    1) You use the built-in types and don't make any of your own.
    PROS/CONS: This is completely equivalent for interfaces and abstract base classes. Doesn't affect the client. Strongly typed versioning will affect both CLR Types the equally.
    2) You want to make your own type and the framework only refers to the abstract base class.
    PROS: They can add to it in future versions and it won't force you to change your implementation.
    CONS: You are forced to inherit from their base and conform all of your types to their framework (my standard MS gripe). Also you will get no notice that anything has changed which they deem a good thing but you might start getting NotImplementedExceptions that you never had before. Now you have to change your stuff anyway but you don't find out until runtime! Their design becomes built and tested with the expectations of using this standard implementation (e.g. with all of HttpContext's standard quirks and dependencies).
    3) You want to make your own and the framework only refers to the interface.
    PROS: You have ultimate flexibility to implement using whatever composure you want. **You can create mock objects with ease.** You can provide implementations that have no concept of ASP.NET. What they are stating as the primary con is also your pro: if you want to know if anything changed in the interface, then you will get compile-time confirmation that you have the complete implementation.
    CONS: If they add to the interface you have to add to your implementation.
    4) You want to make your own and the framework only refers to the interface but it provides a *public* abstract base class.
    PROS: all of the pros of them using an interface, and optionally all of the pros of them using the abstract base class.
    CONS: None. All you have to do is pick which one to inherit from to get the desired effect.