使库向后兼容的最佳实践?

时间:2015-01-19 07:50:41

标签: c# architecture

我有一个实用程序类库。其中一个类执行类似于 tar 的文件归档,因为.NET已经有 gz

归档类使用magic numbers进行版本控制,因此它可以支持使用此库的旧版本压缩的文件。这是一个例子:

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[8];
        archiveStream.Read(magicNumber, 0, 8);

        string ArchiveLib_Version = Encoding.UTF8.GetString(magicNumber);

        switch (ArchiveLib_Version)
        {
            case "ALib0000": 
                ExtractTo_v0(archiveStream, dirInfo);
                break;
            case "ALib0001":
                ExtractTo_v1(archiveStream, dirInfo);
                break;
            default:
                throw new IOException("Archive file invalid.");
        }
    }
}

但是,版本化方法依赖于库中可能在将来更改的其他例程,例如我的Stream.SubStream扩展方法:

protected void ExtractTo_v1(FileStream archiveStream, DirectoryInfo dirInfo)
{
    // ...

    foreach (ArchiveFileInfo arcInfo in archiveHeader)
    {
        Stream sourceBytes = archiveStream.SubStream(
            arcInfo.archivePosition, arcInfo.archiveLength);

        using (GZipStream gz = new GZipStream(sourceBytes, 
            CompressionMode.Decompress, true))
        {
            // ...
        }
    }
}

我是否需要对整个库进行版本控制,创建依赖方法列表,还要做其他事情吗?

在库中保持向后兼容性的最佳做法是什么?

1 个答案:

答案 0 :(得分:2)

您有两个广泛的选择:

在维护向后兼容性的同时修改现有代码

您可以继续修改SubStream(以及其他相关方法)的实施,以用于较新版本的存档。这种方法可以帮助您最大限度地减少代码库中重复代码的数量,从而帮助您遵守DRY原则。

Unit tests可用于确保SubStream(以及其他相关方法)继续适用于旧存档版本。您可以编写一组测试,使用mock流调用SubStream,提供旧的存档数据,并确保它为您提供预期的结果。当您为新的存档版本更改实施SubStream时,一系列测试可以让您确信您没有为旧存档版本打破它。

这里的缺点是你必须花费精力维护一套测试。

为新版本编写新代码并单独留下旧代码

此方法以Open/Closed principle为模型。如果您的SubStream方法已关闭以进行修改,则它将永远不会中断。如果您需要使用SubStream方法中的新功能或不同功能来创建新的存档版本,则可以为新格式编写新的SubStream方法,并继续使用旧的,未触及的SubStream旧格式的方法。

这比上述选项要少得多 - 不需要进行全面的回归测试,只需继续为新功能编写新代码并将其称为一天。缺点是您可能最终在代码库中出现重复的代码。如果您发现影响方法的多个版本的缺陷,则可能会出现问题 - 您必须在每个版本中找到并修复错误,而不是仅仅将其修复到一个位置。

你采取哪种方法完全取决于你:)