20

What is a good design for allowing backwards compatibility of a file type between different versions of software?

For instance, how does microsoft get word 2007, 2010 and 2013 etc... to all open docx files, but different editions can save more / less data and save the data in slightly different ways, all to the same file type, and a file that is saved in one version can be opened in another, but certain elements of the file might not be available in older versions?

I mean, the really obvious way to do it is to have something like

private string openfile(string filename)
{
    File.Open(filename)

    ... some logic that gets a header from the file that will never change

    switch (fileversion)
        case 2007:
            .....
        case 2010
            .....
        case 2013
            .....
}

but that seems incredibly monolithic, not very extensible, and likely to lead to a lot of copy / pasted code.

So I was thinking of using a base interface for all versions which defines the immutable structures, such as the header, that need to be present in the file, and methods that need to be available for serialisation / deserialisation, then multiple inheritance so that each new version's class that implements the interface inherits the old version, and only overrides stuff that has changed, since the file will be the same, for the most part.

I'm not really bothered about the structure of the file, since it's already decided that we'll be using XML, and the initial schema is, by and large, already decided. However there will no doubt be changes to it in the future, and I just want to be able to design the code in a way that makes it easy to accommodate these changes.

JJBurgess
  • 301

3 Answers3

11

You might have a look at the PNG file format and how it handles version compatibility. Every block has an id describing what kind of block it is, and it has some flags that tell the software what to do if it cannot understand that id. For example "you cannot read the file if you don't understand this block", or "you can read the file but not modify it", or "you can modify the file but you have to delete this block". For backward compatibility, your software just needs to handle the situation when any expected data is not present.

gnasher729
  • 49,096
3

A way of doing this can be by using a base class and interface with the basic functions for your file handling. Then use classes for each version that extend from the base class to handle all version specific cases. Functions that can change can be virtual in you base class of abstract if there are only version specific implementations. When you need a class to handle the file, use a factory that gets the version specific implementation of the file handling interface.

peer
  • 182
2

I have done this with XML and it works well:

Simply allow any element in your document, to have any attributes and any subelements (and when order is not important - in any order). Beginning from first version of program - when reading document, ignore attributes and sub-elements that you dont know in current version.

In future when you are adding new feature to new version of program then add attribute or sub-element. Older versions will ignore it. New version should check pressence of attribute or sub-element and handle with it.

For example you have some items with texts:

<item text="Hello, world!"/>

And in newer version you would like to add color to item so you add attribute color:

<item text="Hello, world!" color="008000"/>

Older version will simply ignore color attribute when opening document. New versions check for pressence of color attribute and if does not exist assigns default color.

With this simple solution you will have both backward and forward compatibility.

user3123061
  • 1,597