Backward compatibility


If you’ve been paying attention to my recent posts, you probably noticed I have been thinking about ways we could improve the XNA Framework API. Which begs the question: how much is it possible to clean up an API while maintaining backward compatibility?

Backward compatibility is a terrifying topic for API designers. You just can’t win.

If we make breaking changes, people are annoyed because their old code no longer works. And worse, this resets the supporting user community. Books, articles, samples, and engine code must be updated to the new version. This might be ok if it only happens every couple of years, but there is a limit to how often we can expect our community to deal with such a disruption.

But if we never make breaking changes, our product stagnates. Every design mistake and not fully thought out feature is forever cast in stone. Every random quirk of obsolete platforms must be inherited by all future platforms until the end of time. That isn’t good for anyone.

In the past, XNA Game Studio has attempted a middle road. We made changes, knowing this could break some games, and required a recompile to move existing projects over to new framework versions, but we provided an upgrade wizard to help with this process, and tried to minimize API changes to make the upgrade as painless as possible. Multiple framework versions can be installed side by side, so old games continue to use the old framework while newer games use the new version. This allows us to make minor tweaks that we do not expect to break most games, knowing that if this causes problems for a few people, they will have a chance to fix their code while upgrading their projects (or of course they can choose to stick with the older version). We occasionally made bigger breaking changes in areas where we felt the benefit outweighed the cost, but every time we do this we see pain when customers try to use older tutorials with newer framework versions, then get confused because things have changed out from under them.

This compromise has worked ok for us so far, but it’s a confusing message: most stuff still works the same, except for some stuff that is different. Your game may or may not “just work” ™

We have learned a lot over the last couple of years. If I had a time machine, I would have many suggestions to send back to when we were originally designing this stuff! But from where we are now, it’s a tough choice. Do we leave things as they are, knowing our design has flaws, or do we fix problems and take the cost of a breaking change?


Comments (35)

  1. enntwo says:

    I don’t think the language/framework should suffer as a result of not wanting to break code, especially where it is possible to have multiple framework versions present.

    Taking the middle road, or putting off breaking changes can be dangerous too, as it can make more important changes further on down the line much more difficult. I would have to venture a guess that from one version to another (minor versions likely, eg 3.0 => 3.1) there are often not many proposed breaking changes, so it would be better to make them as they arise. Making one breaking change each minor version would be favorable to making 5 or 6 on a major version as it allows users to adapt at a more incremental rate.

    As for the community, authors are always looking for a reason to pump out a new edition, so they shouldn’t complain 😉

    Tutorials and samples are often updated by the authors, but if not, it leaves an important exercise to the user to bring the code they created using the sample/tutorial up to the new version. There is often a level of understanding missing when someone creates something according to a tutorial or sample, as much of it can be blindly following the steps, or even using direct copy&paste, and being forced to go in and fix bugs directly when a breaking change is made will increase the users understanding of the code and language.

    Ruby has made it apparent they value overall language quality over any drawbacks of breaking changes (eg string handling from 1.8 => 1.9) and I feel the language itself benefits greatly from it.

    Even if it results in a million people asking the same question ("Why don’t renderstates work anymore?"), that is still a million people flocking to community sites for information, strengthening the community itself.

    Don’t fall into the ways of C++/Java, always put quality/correctness as the top priority, and let the users adapt. (You are doing more than enough by supporting multiple framework versions.)

  2. Lu10ntDn says:

    I agree with enntwo.  Better to improve the framework even when it breaks existing apps.  It would be nice, however, if the changes were clearly identified to minimize the pain for developers.

  3. Jeff Weber says:

    I also agree with enntwo.  Things move so quick these days it’s hardly worth looking backward.

    We’ll all keep up!

  4. clayman says:

    Agree with enntwo too. Real time graphics is always been a rapid revolution field. Compare to the benefit of new feature, I don’t mind breaking change as long as the main application model remains still.

  5. I think one of the major problems with breaking changes is when they are discussed after the event. Ideally, the process should be:

    1) Community reaction. I.e. "Hey guys, we’re thinking about changing X to Y, so that we can do Z. What does everyone think about this?"

    2) After a final decision has been made on what is going to change, a post should be made to the user base letting them know what is going to change, why, and what they should expect to have to do to update any existing code.

    3) This information should be included in the official documentation for the existing framework, so that someone reading it will be able to plan for the changes.

    4) When the new framework is released, the community will be ready and should be able to upgrade easily enough, only making minor modifications to deal with last minute changes.

    What normally seems to happen is that only when a new framework is released do people find out about the changes. I’d much rather have a situation where I could plan ahead when coding because I knew what fundamental changes were being implemented in the framework, then possibly only have to make minor tweaks to cope with last minute changes, than have to deal with a sudden surge of major changes when the new framework is released. I understand that companies need to keep certain things under wraps until "the big announcement", but a steady stream of information to the user base is far better than getting it all at once and having to deal with it.

    (When I say framework here, I don’t mean the XNA framework, just frameworks / SDKs in general.)

    tl;dr: Let the community know what to expect in plenty of time, and they won’t mind so much 🙂

  6. Anders Elfgren says:

    Yeah, I’d have to agree too. I’d rather see XNA 4.0 "live up" to everything it can be even if it means old stuff won’t build anymore. As long as the changes are well described somewhere, along with forums to discuss the changes, I think it’s worth it.

  7. David Black says:

    I think it is important to achieve a middle ground in this respect. Putting off changes too long can lead to inconsistant, "ugly" and obsolete/stagnent APIs(a couple of APIs spring to mind here).

    However too many small changes which break things can be problematic too. Smaller non breaking improvements are often a good thing however IMHO, they tend to improve the API by filling in short comings.

    I think such things however depend a lot on the time frame of releases (probably the main issue with the PhysX API, a very long time between major releases, which is presumably when breaking changes will be able to happen).

    The support in the platform for multiple versions(eg this seems problematic for a plain C API like OpenGL).

    The rate of change of the technology which the API is trying to expose. For example this is probably the major reason D3D has been successful, it has changed along with(or before) hardware/software graphics technology changes.

  8. Pete says:

    Do we leave things as they are, knowing our design has flaws, or do we fix problems and take the cost of a breaking change?

    When an API is getting to a point that you cannot significatively improve it unless you change its design/implementation, be the bold and the brave and go for the breaking change!!!

  9. Lars says:

    "ways we could improve the XNA Framework API"

    I have worked with many game frameworks since the middle of the 90s, what’s missing from almost all of them is simple but correct collision detection. This is one of the hardest parts of making a game with lots of math required, yet every game needs it. A few more small but simple to use collision detection routines in the framework would be a great help.

    Absolutely not a physics engine like farseer or box2D, that is much to complicated and don’t work well for arcade style games, but something that helps you write pong (circle-rect) or space invaders (tunneling bullets). Cirle – rect collision, something for tunneling problems and a built in pixel perfect PointInTexture2D would be a great help for everyone starting out I think.

  10. Mike Vargas says:

    Break break break!  I don’t care if I have to change my existing code; I’ll be happy to update it to the latest and greatest.  I don’t want to work with an outdated and convoluted API any more than you want to.

  11. BigNSyd says:

    I share the same frustrations with the company I work for now. The framework I built for our application is now being used by many and now it’s holding back innovation. I’m making it legacy code and moving on to a new framework.

    I vote for bigger breaking changes. If your app is broke with the next big version, you can always stay with the one that works.

  12. BigNSyd says:

    I share the same frustrations with the company I work for now. The framework I built for our application is now being used by many and now it’s holding back innovation. I’m making it legacy code and moving on to a new framework.

    I vote for bigger breaking changes. If your app is broke with the next big version, you can always stay with the one that works.

  13. Eric Lee says:

    Breaking changes hurt for a moment, backwards compatibility is hell forever.

    Sure, breaking changes shouldn’t be undertaken lightly, and there are things you can do to mitigate the pain, but they’re absolutely the right thing to do from the standpoint of the long-term health of the platform.

  14. Banjobeni says:

    Let me try to put it into as few words as possible:

    "If you break it, break it good."

    [unkown]

    (maybe some more words as an explanation, just to be very clear: Do whatever it takes to not break code. Once the time comes that this is infeasible, make a big nice breaking change and correct _all_ the evil in the API)

  15. Jamie says:

    Jamie’s guideline to breaking changes.

    If it is a major release (2.0) then we do the best job redesigning the API to include the changes/fixes we want.

    If it is a minor release (2.1) then we should not introduce breaking changes.

  16. TreesAreGreen says:

    On 22/2/10 I made what I thought was a good compromise for dealing with breaking changes to fix things that are truly broken.

    You can see the full proposal in the comments for this VS issue https://connect.microsoft.com/VisualStudio/feedback/details/93559/typeconverter-for-value-types-such-as-int-bool-short-etc-return-true-to-isvalid-even-if-the-value-is-not-valid#tabs

    In short it is about early advance notice and having one place to reference the short list of issues you need to be aware of and plan for to stay on the upgrade curve.

    Martin.Robins makes an excellent suggestion that would in effect allow people to get the impact list from the compiler in the form of warnings for their specific projects at least for issues where this is identifiable by the compiler.

  17. Pete says:

    "If you break it, break it good."

    Lol!

  18. AR says:

    So far I have been extremely happy with the "level of breakyness" of XNA updates so far. The middle-of-the-road, approach, I think works well.

  19. I’m all for breaking changes, if it means fixing design mistakes in the past.

    However, the only thing I would ask:

    PLEASE PLEASE PLEASE let developers know as far in advance as possible.   Not only a beg for breaking changes.  for example:  is XNA going to provide a UI system in the near future?  If so, please do let us know, as it would mean not having to spend the manpower on doing it ourselves.

  20. I’m all for breaking changes, if it means fixing design mistakes in the past.

    However, the only thing I would ask:

    PLEASE PLEASE PLEASE let developers know as far in advance as possible.   Not only a beg for breaking changes.  for example:  is XNA going to provide a UI system in the near future?  If so, please do let us know, as it would mean not having to spend the manpower on doing it ourselves.

  21. Óscar says:

    I prefer a new API refactoring/features in the way it’s mean to be do it!. In the end is better fot everyone.

  22. "we could improve the XNA Framework API Which begs the question: how much is it possible to clean up an API while maintaining backward compatibility"

    Make it happen, so we can show the world wicth is the leading platform for game developerment

    Please do so

  23. Mike says:

    I prefer running windows 3.1 as my game server because I did not want to rewrite my server code after the breaking changes that came with 95 and up… see where I’m going with this?

    Honestly, if it is a major release people expect cool new features. If those features are attractive enough, no one will mind code braking changes.

  24. Greg Christensen says:

    Maybe you do take a middle of the road approach, but on a different "road."  The first release uses the ObsoleteAttribute to flag elements that should no longer be used and "will be removed in a future release."  The ObsoleteAttribute is already used anyways.  The next release those elements are completely removed and if you haven’t fixed your compiler warnings well then you (the coder) have to figure out a workaround if you don’t want to fix the compiler errors, which is not the responsibility of the API developers.  Bottom line I agree that the API should always be optimized, regardless of impact to the users.  This isn’t the Men’s Warehouse: I didn’t expect any guarantees when I downloaded the API and nobody should.

  25. Erik Parker says:

    Keeping backwards compatibility with an API like XNA is nice but ultimately not necessary.  Keeping backwards compatibility with something like an OS is much more important.

    That said, if you need to break the API, break it in an obvious way, at the compile level if at all possible.  I hate hate hate silent failures.  I would much rather have something that doesn’t compile at all when I update than have something that compiles but does not work.

    I don’t think that maintaining backwards compatibility with an API is even realistic with something used for game development.  Things change too fast, and sometimes we just really need that performance improvement or new feature, or that newly unsupported feature just needs to go away.

    Discussing changes with your users is also nice, so that they have some warning that breaking changes are coming.

  26. Jon Watte says:

    Fix, fix and fix. If that means breaking eggs, make me an omelet!

  27. Erik Parker says:

    For the record, I agree with Greg and Jamie.

    If you’re making an incremental release avoid making API breaking changes if at all possible, but somehow depricate functions that you know will be breaking in the next full release.

  28. Pop.Catalin says:

    Definitely fix.

    If I have to fix my code to take advantage of the latest advancements, I’d fix it over and over again. (I just may decide to stay on and old version just as well, but fixing is a non issue.)

    I hate it that XNA is somewhat of a barrier in adopting newer technologies (also from Microsoft) by setting a common denominator among platforms. Commonality is good, very good, but there needs to be some room for differentiation also.

    Also why don’t you take a more coarse grained approach to versioning like multi targeting (XNA 3.x Project, XNA 4.x Project, etc)?; so major versions can be installed in parallel and the API is more free to evolve in respect to breaking changes from one version to another.

    In the end a clean and simple, but powerful API (which XNA tries to achieve) can only be achieved with cleanup and replacement, not with stacking or bending old APIs to work with newer technologies.

    I think breaking changes (especially at major version crossover) are highly welcome.

    A great benefit for introducing breaking changes at major version crossover is that, you can have a big list of differences at one point in time (opposed to scattered at many points in time) and the migration can be one "well documented" endeavor (opposed to a series of small gotchas scattered on a long time line, with connection to only minor API versions).

    But I’d be very interested to hear about the versioning strategy the XNA team plans to employ in the future.

  29. Pete says:

    "If that means breaking eggs, make me an omelet!"

    Lol!

  30. If the code needs to change, it needs to change radically enough to force the user to really think about how it needs to be reimplemented.

    If you make a minor change, it’s all too easy for users to not notice the change. Yet all of a sudden things aren’t working for them.

    I’d be very keen to see a radically updated XNA. .Net and C# offer so many opportunities to design very clean, consistent APIs (It’s bloody hard :). Parts of XNA really do show this off, but then there are parts that show their Managed DirectX roots.

    I’m very keen to see how things have changed.

  31. Ark-kun says:

    What about fixing your wrong implementation of quaternions and streamlining all those different Vector and Mactrix classes?

  32. ShawnHargreaves says:

    Ark-kun: curious how you think we should streamline our vector classes? We have only one Matrix type, and three Vector types. All three are important for common game scenarios: which would you propose getting rid of, and what would you replace them with?

  33. Eric Smith says:

    I agree with the other commenters that the framework shouldn’t be held back to prevent breaking API changes, provided multi-version support doesn’t go away.

    If there’s something cool you guys can do and you think it’ll benefit us as game developers, by all means do it! Gaming is a rapidly-changing field and trying to keep older, legacy games working correctly is only going to hurt the framework in the long run.

    The only suggestions I have for future XNA releases is to make certain things a bit more high-level and .NET-like while retaining the same level of low-level access we currently enjoy (think easily customized ‘Camera’ components that could be used instead of a custom-coded implementation). My other suggestion is to get an FPS starter kit working! Last I checked, there still wasn’t one, and people are clamoring for that (particularly me).

  34. Mark says:

    Tooooooooooooooooo many way tooooooooo many breaking changes – it's a joke!!!!!!

  35. Mark says:

    Way toooooooo many breaking changes it's a joke – over 1000 lines of code in my app are broken from shader code changes to everything about graphics and drawing even gametime / elapsed time – who gives a toss – just leave it no one would care if you called it gametime or elapsed time!!!!!!