微软的开发流程是否有问题?从Windows功能更新事故频发说开去
作者 | Peter Bright
译者 | 薛命灯
可以说,2018 年 10 月份的 Windows 10 更新并不是微软最成功的一次更新。在推出更新后不久,就有用户反应数据丢失,微软不得不暂停发行更新。好在问题已经得到修复,目前正在重新测试,并等待重新发布。
这并不是第一次 Windows 功能更新出现问题——在之前的更新中就已出现硬件不兼容等重大问题——但这次肯定是最糟糕的一次。虽然我们大多数人都知道备份的重要性,但实际情况是大量数据(尤其是家用 PC 上的数据)都没有进行备份,因此一旦数据被删除简直是灾难性的。
Windows 即服务
微软对 Windows 10 雄心勃勃,想要彻底改变 Windows 10 的开发方式。他们希望能够更好地响应用户和市场需求,能够尽快将改进过的功能提供给用户。他们把 Windows 10 看成是 Windows 的“最后”一个版本——之后所有的开发都将被视为对 Windows 10 的更新,并且每年会提供几次功能更新。这个新的开发模型被称为“Windows 即服务”。在经历了一些初步的摸索之后,微软决定每年推出两次功能更新,一次是在 4 月份,一次是在 10 月份。
这一做法在一定程度上取得了成功。在新的开发模型下,用户不再需要等待三年就能获得原先只有在新的主要版本升级中才能获得的功能。例如,在虚拟机中无缝运行 Edge,以便更好地防御恶意网站的侵害。Windows Subsystem for Linux(WSL)能够在 Windows 系统上运行原生 Linux 软件,这对开发人员和管理员来说无疑是一个福音。对于纯粹的消费者来说,Windows 10 更新所带来的好处可能没有那么明显,不过与 SteamVR 兼容的 VR 功能、改进的游戏性能和暗黑主题,这些都是不错的改进。虽然整体改进较小,但目前的 Windows 10 肯定比三年前发布的版本更好。
这是一件好事。我甚至认为,如果没有 Windows 即服务,它的某些部分可能就无法完成(或者至少不能像现在这么成功)。例如,WSL 的开发吸收了来自用户的反馈,WSL 用户向微软反馈他们发现的不兼容问题,并帮助微软优先开发新的 WSL 功能。如果不是每六个月推出一次更新,我不认为 WSL 能够获得这么多的关注——没人愿意为一个小的修复等上三年。定期更新能够激励人们向微软报告 bug,因为他们可以及时看到这些 bug 得到修复。
Windows 即服务的问题主要出在质量上。之前的功能和安全更新问题已经打击了微软对 Windows 10 更新策略的信心。人们普遍认为,Windows 10 每月安全更新的质量已经大幅下降,每年两次赶鸭子上架式的功能更新也很疯狂。用户的这些抱怨长期存在。在 Windows 10 发布后不久,这些不可靠的更新就引起了人们的关注。
有评论员表示,一年两次功能更新太过频繁,应该减少到一次,微软需要停止开发新功能,只需要修复 bug 就可以了。有些人担心微软在经过几次更新之后会失去大量的用户信任,对于一些 Windows 用户来说,可能早就没有信任了。
这并不是微软第一次被呼吁放慢更新的速度——一直以来有人担心会出现大量的 IT 用户和消费者流失——但最近出现的更新问题让这个呼吁变得更加紧迫。
这是方式问题,而不是频率问题
但是,要微软每年只推出一次更新或批评 Windows 即服务这种想法都没能戳中要点。问题并非出在发布频率上,而是微软的开发流程出现了问题。
为什么问题出在流程上,而不是在时间频率上?
Windows 10 的一年两次更新比 macOS、iOS 和 Android 来得更频繁,从某种意义上说,微软是在试图超越它们。但这种发布频率并不是前所未有的:Ubuntu 每年都会发布两个版本,谷歌 Chrome 浏览器每六周就会推出一次更新。除了操作系统之外,微软的 Office Insider 计划每月为 Office 用户提供新功能,并且可以在不产生太多投诉的情况下实现这一目标,提供稳定的新功能和修复。Visual Studio 团队同样为其开发环境和在线服务提供频繁的更新。显然,微软内部的一些团队能够很好地为他们的应用程序提供定期更新。
从在线服务和云服务方面来看,无论是在微软内部还是在其他领域,都在逐步采用持续交付。系统更新在通过足够的自动化测试之后就会被自动部署到生产服务器上。
的确,这些项目都没有 Windows 那么复杂。Ubuntu 包含了很多软件包,但好在这些软件包是作为独立单元进行开发的。Windows 也包含了很多单独的组件,但它们的规模仍然异常庞大,集成方式也不同寻常。至少在某种程度上,Windows 已经非常老了。
这些因素让开发 Windows 变得极具挑战性——但至于让每年发布两个版本变得那么不切实际吗?这个很难说。我只知道,它需要的可能是一个正确的开发流程。
由来已久的流程
微软尚未完全透露 Windows 10 的开发流程,但从开发流程的一些可观察特征以及从公司内部收集的一些信息来看,他们的开发流程存在缺陷——与之前三年发布一个版本的流程有很多相似之处。时间频率变得更加紧凑,但很多开发方法都没有改变。
在过去,当产品发布周期为两到三年时,开发流程被分为几个阶段:设计和规划、功能开发、集成、稳定。规划和设计可能为期 4 到 6 个月,编码时间为 6 到 8 周,然后是 4 个月的集成(每个功能通常都在自己的分支中开发,到最后必须合并在一起)和稳定(测试和 bug 修复)。在产品开发周期中,这些阶段将被迭代两到三次,对于 Windows 来说需要经过三次迭代,第一次是针对原型,接下来的两次是针对真实的产品。阶段的时间跨度可能会发生变化,但基本结构在公司内部得到了广泛应用。
我们从这种流程中可以看出一些问题。也许最引人注目的是花在编码上的时间非常少:一个 Windows 版本在三年内只有 6 到 8 周的编码时间,而在规划设计阶段与产品成型之间的时间跨度却非常长。这个因素足以说明这个开发流程并不那么“敏捷”。在你将产品放到客户面前时,新功能已经融入到最终产品中,很难根据反馈做出修改。
开发和 bug 修复的分离也是一个问题:在开发和集成阶段,软件的可靠性和稳定性会急剧下降。被集成的功能未经过全面的测试(因为测试是在后面进行的),并且从未相互使调用过(它们在进入集成阶段之前都是在各自的分支中单独开发的)。然后,通过测试、报告 bug 和冗长的 bug 修复阶段,软件才逐步成型。
新世界并不那么新
在新的世界里,我们可以看到微软将整个周期变为七到八个月。虽然版本之间只间隔了六个月,但下一个周期的开始发生在上一个周期结束之前。
每次更新在一开始都很平静,没有明显的变更,然后在接下来的几个月会引入一些重大变更和大量 bug。在更新即将发布之前的一个月左右,我们会发现变更的数量急剧减少,他们开始关注 bug 修复而不是引入新功能。
正如微软员工所描述的那样,最后几个月的开发被分为“告诉”阶段和为期一个月的“询问”阶段。在“告诉”阶段,Windows 负责人被告知需要做出哪些变更,并默认接受这些变更。在“询问”阶段,默认变成了拒绝。在这个阶段,只允许真正有必要的变更,通常一天只有几个变更。
例如,10 月份的第一个更新版本(代号 RS5)早在 2 月 14 日就已发布给内部人士,4 月份更新(RS4)的稳定版本在两个月后推出,也就是 4 月 16 日。RS5 在 3 月 7 日之前没有收到任何重要的新功能。在 5 月、6 月和 7 月增加了很多功能,而在 8 月和 9 月只做了很小的修改。8 月份甚至移除了一些小功能,因为它们未能为 10 月的发布做好准备。
流程当中肯定存在一些差异。例如,新功能会在预览版本中存在几个月时间。这表明新功能的集成似乎进行得更快,开发完成后就进行集成,而不是在最后来一次大融合。
质量急剧下降
但也有一些主要的相似之处。其中最重要的一点是集成带有 bug 的代码,然后在测试和稳定阶段解决这些 bug。他们甚至明确承认了这一点:在发布一个新的预览版时,微软会警告说“开发周期的早期构建版本可能包含对某些用户来说很痛苦的 bug。如果这让你感到不舒服,可以考虑切换到慢速通道(Slow Ring),慢速通道将提供更高质量的产品”。
我们可以在 RS5 中看到这种例子。去年 10 月份的更新为 OneDrive 引入了一项新功能:使用占位符表示存储在 OneDrive 中但未被下载到本地的文件。当应用程序试图打开文件时,OneDrive 将从云存储上获取文件并将其保存到本地,应用程序不会知道这个文件最初在本地是不可用的。如果本地磁盘空间不足,将选择性地从本地删除从云端复制的文件。
这是一个非常智能且有用的功能,可以无缝地使用云存储。这些代码都是新增的,有一个内核驱动程序在云同步代码(用于下载文件和上传变更)和文件系统中的占位符之间提供了粘合剂,还提供了一组 API(第三方可以利用它们来实现自己的同步服务)。
我们期望微软能够对新代码进行一系列测试,以便验证它们是否能够正常运行:创建文件,检查是否能够正常同步,删除本地副本,留下占位符,打开文件以便再次从云端获取文件,完全删除文件,等等。有一些围绕文件和目录的基本操作,在敏捷开发流程中应该有测试来验证所有操作能否按预期工作,并确保 API 能够做它应该做的事。
另外,任何无法通过测试的代码变更都不会被集成到系统中。这些有问题的代码需要被修复,通过测试,然后才能被合并到主代码中。
然而,事情并非如此:很多预览版中都存在 bug,比如删除一个已经同步到 OneDrive 中的目录会导致机器崩溃。这个 bug 不仅被集成到了 Windows 代码中,还被发给了最终用户。
在交付之前进行测试,而不是之后
这无疑是在告诉我们一些有关 Windows 开发的基本信息。要么代码压根就没有经过测试(并且我被告知确实是这样的,他们允许在没有测试的情况下集成代码,但我希望这不是常态),要么测试失败被认为是可接受的非阻塞问题,并且允许开发人员集成他们知道无法正常运行的代码。对于外人来说,无法确切地知道哪种情况是真的——有可能是两者的混合——但不管哪样都不好。
Windows 比较旧的部分可能情有可原——它们是在真正认识到自动化测试价值之前的时代开发的,而且当时很可能没有真正的测试基础设施。但 OneDrive 占位符是新开发的功能,我们可以原谅旧代码未经测试,但并没有充分的理由说新代码不应该有一组可靠的测试来验证其基本功能。并且已知存在 bug 的代码在得到修复之前肯定不应该被合并,更不用说被发给测试人员了。
因此,Windows 10 的开发仍然在遵循类似于 Windows 10 之前的轨迹。功能被合并,但稳定性和可靠性却在下降。测试和稳定阶段被用来解决问题,并将代码库修复到可接受的状态。
不充分的自动化测试或对测试失败的忽视意味着 Windows 开发人员无法确信变更和问题修复不会产生波及效应。下面就进入了“询问”阶段:最终成为更新版本一部分的变更非常少,因为微软对每个变更的影响范围不太有信心。这种信心只会来自大规模严谨的测试基础设施:你知道变更是安全的,因为所有测试都能成功运行。但不管微软对 Windows 做了什么测试,都不足以获得这种信心。
但在其他方面,微软似乎表现得确实有这种信心。微软确实提供了很多测试,Windows 的完整测试周期需要数周时间。他们确实使用了完整的测试周期,只是没有被用在实际要发布的构建版本上。2018 年 10 月的更新就是一个例子:代码建于 9 月 15 日,然后于 10 月 2 日发布。不管是 RS5 的哪个版本经过了完整的测试周期,但肯定不是我们实际使用的那个版本,因为完整的测试周期太长了。
这是非常矛盾的。如果确实有信心随后的代码变更不会破坏现有的东西,那么在稍旧的构建版本上运行完整的测试周期就没有什么问题。但如果微软真的高度确信这些变更不会破坏任何东西,那么就不必在“询问”阶段严厉地限制它们。
这才是正确的做法
与真正的敏捷项目形成鲜明对比,这才是关键之处。以 Google 广告服务器的开发流程为例。广告服务器是 Google 的一个关键基础设施,Google 的开发人员表示,他们针对小 bug 的代码修复可以在一天内被部署到生产环境。当修改的代码被提交到代码库时,会自动进行重新构建并执行一系列测试。代码所有者随后对变更进行评审,然后接受变更,并将其合并到主代码库中,重新进行测试并部署到生产环境。
当然,这种比较有点不公平。对于云服务来说,在发现错误时可以更轻松地回滚代码变更。对于 Windows 系统来说,一个导致启动蓝屏的变更是难以撤消和恢复的。但是,广告服务器仍然是 Google 的一项非常关键的服务——这是 Google 收入的一个主要来源——一个糟糕的变更可能会损失数百万美元。Google 开发流程中的测试和自动化意味着刚刚加入公司的开发人员很快就可以上手开发,并在几小时内将变更部署到生产环境,并且充满信心。
从根本上说,Google 的开发思维方式与微软是不一样的。新功能在开发阶段可能是不稳定的,但在合并到生产代码库之前,必须达到非常高的质量标准。微软则是“现在合并 bug,以后再来修复”。
云应用程序确实具备一定的灵活性,而这种方法其实也可以用于桌面软件。例如,Google 在 Chrome 方面也应用了类似的工作流程。Chrome 开发和测试分支确实偶尔会出现 bug,但总体来说,他们的代码始终接近“可发布的质量”。实际上,Chrome 团队的工作原则是即使是最新版本的代码也应该具备可发布的质量。你可以将 Chrome 的开发分支作为常规的浏览器使用,除了图标稍有不同之外,你可能永远都不会知道你所使用的并非“稳定”的分支。大量的自动化测试和评审流程促成了这一点:在整个开发流程中,Chrome 的代码都具有很高的质量,不存在 Windows 上的那种质量下降和后续维修工作。
Google 还在基础设施上做了很多投入来实现这一目标。它有一个分布式构建系统,使用了一千个核心来构建 Chrome,因此可以在几分钟内完成整个构建过程。他们有条理地使用分支,让合并变得容易和可预测。Google 提供了大量功能测试和性能测试,以便能够尽快发现 bug 和功能回退。Google 为此付出了很大的代价,也因此能够定期发布稳定的 Chrome。
Windows 的开发流程从未好过
微软的新开发流程增加了用于开发新功能的时间,同时缩短了用于稳定和修复这些功能的时间。如果新开发的功能从一开始就具备很高的质量,并在集成新代码之前提供测试基础设施支持,那就没有什么问题。但到目前为止,Windows 10 的经历告诉我们,微软并不具备这种新方法所需的流程和系统。
问题是,即使将发布数量减少到一年一次也不能解决问题。人们总是透过有色的眼镜看待 Windows 开发的旧时代。如果我们重新回到 Windows 7 及以前的日子,我们仍然会看到与今天类似的问题。在发布 Service Pack 1 之前,通常不建议升级到新版本的 Windows。为什么不?因为初始版本有 bug,不稳定,并且直到 Service Pack 1 才会解决掉大多数问题。
不同之处并不在于 Windows 新的开发方式比以前更糟糕,或者旧方法提供了更好的结果,而是我们“等待 Service Pack 1”的时刻变成了一年两次。通常在发布更新后三到四个月,微软会再次发布他们认为质量更高的代码,这也就是我们的“新”Service Pack 1 时刻。
我们进入了一个最糟糕的世界:在旧的 Windows 开发时代,发布的初始版本不够好。在新的 Windows 开发时代,我们每年会看到两次发布,而不是每三年一次。这个不稳定的 Service Pack 一直与我们如影随形。
根本的问题在于,集成没有经过充分测试的功能,破坏了代码库的稳定性,然后希望在以后解决所有问题,但这不是一个好的流程。Windows 每三年发布一次并不好,但即使是每六个月发布一次也好不到哪去。
这不是 Insider 的工作
第二个问题是微软的测试方式。微软曾经拥有大量专门的测试人员,每个功能都分配了开发人员和测试人员。这些测试人员中有很多在 2014 年被裁掉或重新分配到其他团队,他们认为可以将更多的测试工作转移给开发人员。Windows Insider 计划带来了大量的非正式测试——拥有数百万成员,比任何 Windows 测试计划都要多。
旧开发方法不一定就能够捕获造成数据丢失的 bug,或许专门的测试人员也测试不到导致数据丢失的特定场景。但很明显,微软正在努力处理由 Insider 非专家测试人员提出的 bug 报告。数据丢失问题在更新发布前三个月就已被提出。很多 bug 报告看起来质量很差,缺乏必要的细节或者使用了不恰当的术语,但如果微软在三个月内都没能发现问题,那么即使更长的开发周期也不会有任何效果。更长的开发周期只能意味着 bug 将被忽略六个月而不只是三个月。
微软承诺改变 Insider 反馈流程,允许 bug 报告者指出问题的严重程度,以便更多地关注这类问题。这或许会有所帮助,只要 Insider 恰当地使用严重性指标,但似乎仍然不足以解决因为质量太低而导致的大量 bug。
这与代码质量问题有关。Insider 计划的真正优势在于硬件和软件的多样性,帮助消除兼容性错误和驱动程序问题,等等。然而,Insider 不应该成为测试的主力,但这好像就是微软推出这一计划的目的。
另外,开发阶段的代码质量下降意味着预览版本通常不适合用于日常的 PC,因为它们不够稳定。这反过来降低了 Insider 测试的价值:事实上,Insider 并没有让新版本运行在所有的硬件和软件上,因为他们并没有在他们的主要机器上使用构建版本,他们使用的是不常使用的辅助机器和虚拟机。
在工具上进行投入
为 Windows 这样复杂和庞大的东西搭建一套类似 Chrome 那样的测试基础设施将是一项艰巨的任务。虽然 Windows 的某些部件可以进行独立的测试,但很多部件只有在作为整体系统时才能进行有用的测试。其中一些,例如 OneDrive 文件同步功能,甚至依赖了外部网络服务,所以这绝对不是一件轻而易举的事。
要让 Windows 代码始终保持很高的质量——不是“经过几个月的修复”,而是“现在,随时”——将是一个巨大的挑战。但这是必要的。从一开始,微软就应该让每一个更新都具备符合生产标准的质量。在这个世界中,用户升级到最新和最好的版本将是一个明智的选择,而且可以放心地升级。功能更新不应该是什么虚张声势,要让用户几乎注意不到。一年发布一次或每三年发布一次并不会带来这样的效果,从来都不会。微软需要改变的是流程本身,而不是发布频率。
英文原文
https://arstechnica.com/gadgets/2018/10/microsofts-problem-isnt-shipping-windows-updates-its-developing-them/