I have a library of utility classes. One of the classes performs file archiving similar to tar because .NET already has gz.
The archive class uses magic numbers for versioning, so it can support files compressed with older versions of this library. Here is an example:
public void ExtractTo(DirectoryInfo directory, bool overwrite = false)
// removed sanity checks, try/catch, etc. for brevity
using (FileStream archiveStream =
new FileStream(this.archivefile.FullName, FileMode.Open))
byte magicNumber = new byte;
archiveStream.Read(magicNumber, 0, 8);
string ArchiveLib_Version = Encoding.UTF8.GetString(magicNumber);
throw new IOException("Archive file invalid.");
But, the versioned methods depend on other routines in the library that may change in the future, for example my Stream.SubStream extension method:
protected void ExtractTo_v1(FileStream archiveStream, DirectoryInfo dirInfo)
foreach (ArchiveFileInfo arcInfo in archiveHeader)
Stream sourceBytes = archiveStream.SubStream(
using (GZipStream gz = new GZipStream(sourceBytes,
Do I need to version the entire library, create a list of dependent methods, do something else?
What's the best practice for maintaining backwards compatibility in a library?
Best How To :
You have two broad options:
Modify Existing Code while Maintaining Backwards Compatibility
You can go ahead and modify the implementation of
SubStream (and other dependent methods) for newer versions of your archive. This approach can help minimize the amount of duplicated code in your codebase, helping you adhere to the DRY principle.
Unit tests can be used to ensure that
SubStream (and other dependent methods) continue to work for old archive versions. You could write a set of tests that call
SubStream with a mock stream that provides old archive data, and ensure that it gives you the expected results. When you change the implementation
SubStream for new archive versions, a suite of tests can give you confidence that you haven't broken it for old archive versions.
The downside here is that you have to spend the effort on maintaining a suite of tests.
Write New Code For New Versions And Leave Old Code Alone
This approach is modeled on the Open/Closed principle. If your
SubStream method is closed to modification, it will therefore never break. If you need new or different functionality from your
SubStream method for a new archive version, you could simply write a new
SubStream method for the new format, and keep using the old, untouched
SubStream method for the old format.
This can be much less effort than the above option - there's no need for comprehensive regression testing, just go ahead and write new code for your new feature and call it a day. The downside is that you may end up with duplicated code in your codebase. This could be a problem if you discover a defect that affects multiple versions of your methods - you will have to find and fix the bug in each version, rather than just fixing it in one place.
Which approach you take is entirely up to you :)