当您有多个服务器版本时,如何构建自动更新桌面应用程序,并在每个服务器版本之间进行重大更改?

How can I structure auto updating a desktop application when you have multiple server versions, with breaking changes between each server version?

结构:

Server - Desktop Application

我想在桌面应用程序上有一个自动更新机制。这可以通过 Squirel.Windows 之类的东西来实现,并且超出了这个问题的范围。请注意,DesktopApp 针对不同的 OS(Mac 和 Windows)有多种变体。

问题是,服务器并不总是最新版本。例如:

Server.v1 - DesktopApp.v1
Server.v2 - DesktopApp.v1

Server.v1 和 Server.v2 具有不同的行为和重大更改。如何以可管理的方式构建 DesktopApp 上的自动更新?

服务器版本也可以突然转到不同的版本,例如从 Server.v2 到 Server.v1。这是我们无法控制的。

注意:服务器不符合 semver,因此次要版本号可能会有重大更改

建议 1)

像这样使 DesktopApp 向后兼容

if(serverVersion == Server.v1) {
    MetodOfLogicThatWorksOnV1();
}; 
if(serverVersion >= Server.v2) {
    MetodOfLogicThatWorksOnV2();
};

现在我可以随心所欲地自由更新 DesktopApp.v1,而且它将完全向后兼容。桌面应用程序的用户都使用最新版本。

担心:一段时间后会导致逻辑非常复杂,容易出错

建议 2)

让 DesktopApp 更新机制知道何时应该降级

if(serverVersion == Server.v1) {
    DesktopApp.SelfUpdater.Update(v1);
};
if(serverVersion >= Server.v2) {
    DesktopApp.SelfUpdater.Update(latest);
};

现在,用户将获得不同的 DesktopApp 版本,具体取决于他们所连接的服务器版本。

担心:用户将不得不 update/downgrade 取决于版本。维护这个更新逻辑会变得复杂。现在必须对 DesktopApp.v1 和 DesktopApp.v2

进行错误修复

建议 3)

为每个服务器版本创建 1 个 DesktopApp

if(serverVersion != clientVersion) {
    DesktopApp.SelfUpdater.Update(serverVersion);
};

这意味着我知道服务器的版本将始终针对我使用的 DesktopApp 的确切版本进行设计

苦恼:DesktopApp需要制作的版本非常多,需要部署bug fix到很多版本。

问题:

当您有多个服务器版本并且每个服务器版本之间都有重大更改时,我如何构造自动更新桌面应用程序?

如果您的组织同时控制服务器和桌面应用程序,最好的答案是围绕服务器开发进行纪律处分。您应该明确表示,对服务器协议的频繁不兼容更改会增加应用程序团队的工作量。 Pact 是我(轻微)使用过的一种工具,它可以让你 "record" 客户端的请求和预期的响应,然后 运行 那些作为针对服务器的测试用例,无需完整的端到端测试设置。

如果您控制服务器,另一个更好的选择是让服务器支持旧协议版本。我不使用 API directly much, but its API reference 列出所有过去的版本并且有一个更改列表,旧的和新的客户端和服务器可以互操作。 Docker 还实现了您的 "option 1",如果需要,客户端代码可以降级到较旧的协议版本。

否则,从用户的角度来看,你的选项1是唯一好的。经常想要破坏您的工作流程并重新安装自身(选项 2)的应用程序很快就会变得烦人,但如果应用程序在服务器升级时随机停止工作(选项 3),情况会更糟。还有一些常见的部署模式,如 "canary builds" 可以导致旧服务器和新服务器同时 运行,为了支持这些,客户端应用程序需要能够与两者一起工作。

您可以使用定义操作的接口和 "traditional" 工厂方法来实例化正确的实现,而不是开关:

IMyOperations GetMyOperationsFactory(){
  var version = Server.GetVersion()
  if (version == 1) return new MyOperationsV1();
  if (version == 2) return new MyOperationsV2();
  throw new InvalidOperationException("Server version " + version + " not supported");
}

那么您至少可以隔离特定于版本的行为。 如果有益,添加传统的面向对象(继承等等)。