Versioning Interfaces


I thought I’d share a bit of this thread we are having now over a large internal alias… As always your comments welcome:


 


Questions:


I have an interface (IFooExtension) which has shipped. This interface is public, documented and used by third parties to write custom “plugins”. For the next version, we want to improve this interface (add methods, delegates …). What is the recommended way to name the new version of the interface IFooExtension2, IFooExtensionEx or something else?


 


My response:


Well, first off I’ll say that on the surface it looks we have “teaching moment” here.  So forgive me while I get on my soap box… Had you elected to use a base (or abstract) class rather than an interface for this you would not be in the position you are in right now.  You should only use interfaces when you have high confidence that the scope of the interface is small enough that it is unlikely to be versioned in the future.  You are now forcing some very ugly, com-like API design on our customers.  You, and others designing V1 APIs should take this as an opportunity to revisit each of your interfaces and double\triple confirm that you will not need to version that interface in the future.  


 


That said, the first thing I would suggest is provide a meaningful name… consider what additional functionality you are adding and use that in the name… such as ISeedSecurityExtension or something like that.  See IDispatchEx2 here we come…  and the comments for more context.


 


If after drawing on the sum total of your teams creativity you are not able to come up with any meaningful name then the guideline is to use ISeedExtension2 as it seems likely you will need a ISeedExtension3 and ISeedExtension4 eventually as well given your track record 😉


 


 


 

Comments (23)

  1. dreb says:

    That actually doesn’t sound nasty at ALL really.. Because it objectifies all of that Interface functionality even more and will still be pretty invisible to the end user.

    If I understand you correctly, you’re saying to have IMainInterface (let’s say that is what shipped)… and to extend that, you don’t change the interface – instead you create another.. so if you were adding security methods (ISecPolicy) then you could just:

    class MyClass : IMainInterface, ISecPolicy

    right? That doesn’t sound bad at all to me..

  2. Brad Abrams says:

    Yup — I agree dreb, if that works it is a fine design. I am just worried that it is hard to do if the interface was designed to broadly to start with. And, of course, I don’t like the IMainInterfaceEx2 plan….

  3. Benjamin Crawford says:

    You don’t explain, in this post of the IDispatchEx2 one, why a base class versions any better than an interface does. It would be so nice if your "teaching moment" could contain more teaching than pomposity.

  4. Josh says:

    The point is that, with a base class, you can always add additional methods and fields to the class – it doesn’t break the code that uses it. If you add to an interface, every class that implements the interface must be changed to implement the new stuff as well.

  5. Brad Abrams says:

    Good point Ben… I go into a bit here: http://blogs.msdn.com/brada/archive/2003/07/26/50192.aspx

    But the basic problem is that you can’t add a member to an intrface once it has already shipped without breaking clients. (Notice this works fine if you can just ask everyone to recompile, but for the Framework, we can’t do that). If you add a method to your interface then my class that implements the old version of that interface now no longer meets the contract of the interface.. If i recomple the compiler will give me an error, if I don’t the runtime will give a TypeLoadException…

  6. I can’t think of any reason why the user can’t divine a new name for the new interface. If they are adding a new interface, then they are adding at least one new property or method. This definitely has a name, and so has some bearing on what the NEW name of the interface should be.

    It might be helpful if you would point out a case where some form of naming abiguity would cause me not to be able to create another interface name and that might convince me to call it *2 or *Ex.

    Taking the pattern of being the user of some library. If I want to use a new interface that they’ve lately implemented, then I need to code and compile against the new library. That would make versioning identically named interfaces by using namespaces quite possible. The newly created interface of IMainInterface could actually extend the previously namespaced version. Then the versioning names go into the namespace and not into the actual interface name. Something like:

    namespace DWC.PublicInterfaces {

    public interface IMainInterface {

    public string Foo { get; }

    }

    }

    namespace DWC.PublicInterfaces.V2 {

    public interface IMainInterface : DWC.PublicInterfaces.IMainInterface {

    public string Bar { get; }

    }

    }

    It now becomes quickly obvious to me that I can code against IMainInterface still, but have to change which namespace I’m working with.

    Being on my own soap-box though, I better support creating a new interface with a new name that readily identifies its additional purpose similar to the post from dreb. Having my users support a large number of interfaces with few methods each is less daunting than having them support a single large interface (the implement/compile paradigm where users wan’t to test their code ;-), but it makes it more difficult for me to partition plug-ins since each interface has a different function set and I have to cast/check for interface support before using each sub-set of functionality. With the IMainInterfaceEx or namespaced versions, I can check for the latest, and know that it supports everything.

    Tough decisions. Up to you in the long run.

  7. RichB says:

    It’s only recently that the .Net team have moved away from interfaces to abstract base types. For example, the ASPNET 2 PDC release contained lots of new interfaces. These are now abstract base types for the CTP.

    Therefore children, don’t feel bad about this – Microsoft have only just realized it too 🙂

  8. Wait a second, Brad.

    Why can’t I just use the same name with a different version of the DLL?

    If I have a DLL versioned 1.0 with the IMyCoolInterface interface defined in it and wish to change it, I could just change the version number. Then, whenever someone would want to use my DLL, they would refer to version 1.0 and wouldn’t care. If they decided they want to build with the new version, they’d have to change their code. That’s very acceptable.

    Shouldn’t have side by side execution taken care of the problem you’re describing?

  9. dreb says:

    Omer, academically – that’s fine, but in everyday use – that becomes unmanageable. One of the best things a developer could ever, ever do is to adopt practices that make his code self-describing.

    For this problem – if you use an abstract class:

    public MyClass : MyBaseClass

    If you change MyBaseClass – the change is automatically rolled into MyClass and is invisible. It’s self-describing and simple.

    if you employ multiple interfaces:

    public MyClass :IMainInterface, ISecondaryInterface

    Again – it’s obvious (without documentation and via the actual code – not code comments) that the class implements two interfaces. Self-describing and obvious.

    Lastly, if you use namespace versioning:

    public MyClass : MyNS.V2.IMainInterface

    As a developer, when I see that.. I may infer that the V2 means version 2… but wait, what’s that about? How many versions are there? My DLL only has two. What’s the difference between them? Are there ramifications of me using the old one? My app works using V1 – can I just keep using it? It’s just not self-describing at all and leads to developer confusion. Confusion leads to bugs. More specifically "Assumptions are at the root of all software bugs" as I say.

    So although there are technically many ways to solve this one – I’m just pointing out that a developers best friend is to make his code self-describing and obvious..

  10. Jerry Pisk says:

    If I do use base classes instead of interfaces how exactly do I work around the single base class limitation in .Net? I can implement as many interfaces as I want but I can only derive from a single base class, which is very limiting and you’ll eventually end up with classes that are all the possible combinations of the few base classes your users might want to implement.

  11. Paul Gunn says:

    Sorry Brad, but I have to get on my soapbox now.. If microsoft had elected to support multiple base classes, then using them as ‘growable interfaces’ might be a viable option. However, at this point it is not.. So I have to admit your soapbox stance raises my fur. Give us the tools before you suggest using them.

  12. Ken Brubaker says:

    Say you used an interface where you should have used a base class and now you need to extend it…

  13. * sitting back eating popcorn and loving this thread! *

  14. Brad Abrams says:

    Well, Paul, you are right the CLR does not support multiple inhertance and some would say that is a great thing.. It certainly adds to a ton of complexity to C++ and no two languages have the same rules. I for one hope we will never add it.

    In the vast majority of cases the work around is very simple…

    You can’t do:

    public class C : A, B {}

    so do:

    public class C : A {

    public B MyB {get {..}}

    }

  15. Paul Gunn says:

    There’s no reason you can’t do that, but you are losing something. You lose interface discovery – in the second case access to the interface B is dependant upon knowledge of C. In the first case, anyone could take an opaque C, generically query it for B services, and use it generically.

    Personally, I’ve always limited my use of MI. In design pattern speak I’ve used it mainly for ‘mixins’ – something that one can admittedly simulate by delegating to contained classes. My problem is with your suggestion that a base class be used when you forsee a need to grow an interface – given the MI limitation you can’t substitute base classes for interfaces and still have them act like interfaces.

  16. Luke Stevens says:

    As soon as you see the oxymoronic phrase "new version of the interface" you know you are dealing with fundamental misunderstandings. A different interface is a different interface, period. If the new one happens to be so much like the old one that it can inherit it, and the additions are meaningless without the rest, fine, do that. But if you put a little thought into it you will usually find that a monolithic catch-all interface can benefit from being broken up into several small (often single-method) interfaces, and your addition can be just one more little optional interface. If components out there already implement an interface you defined and nothing more, you should respect that and not try to force them to expand to fill your new expectations, when it is so easy to just query for an interface and react appropriately if it’s not there. The Framework does not make every XML-serializable object implement IXmlSerializable or inherit from a hypothetical XmlSerializableBase; it uses the interface when it’s there and does something else when it’s not. Keeping default behavior entirely out of classes that don’t provide their own is a good thing.

    Though interfaces will serve you well so long as you respect their purpose, abstract classes are rife with troubles, not the least of which is the preclusion of any other necessary base class, all for no real advantage. Follow my link and read all about it.

  17. Luke Stevens says:

    One more thing… about multiple inheritance and such… a lot of interesting possbilities would result from allowing generic types to derive from the type parameter. Individual classes could then offer a parameter to specify a base class, which might in turn be an abstract class with another such type parameter. Then you could say:

    class UsesMutliInherit : AbstractOne<AbstractTwo<AbstractThree<object>,int>> {…}

    This would not help callers looking for a particular abstract class like AbstractOne<object>, but it would allow AbstractOne (and simultaneously AbstractTwo and AbstractThree!) to add support for new interfaces that callers could then query for, while still allowing the derived class to inherit from, say, ServicedComponent. I still don’t think this is a good practice, and I don’t know if there are technical reasons for not supporting it, but it is an interesting idea.