透明思考


Transparent Thoughts


  1. 持续交付2.0:云原生持续交付

    持续交付》提出了一系列贯穿整个软件交付生命周期的最佳实践。但它成书的年代(2010年)云计算尚未得到广泛应用,尤其在软件开发过程中的应用非常有限。如果站在今天的技术水平和对云计算的理解水平基础上回顾《持续交付》的内容,我们有可能提出一组全新的、原生于云环境的持续交付实践。

    软件发布的反模式

    《持续交付》中列举了软件发布过程中的一些反模式,这些在行业中常见的不佳实践使软件发布过程容易出错,使软件发布的风险和压力增大。这些与可靠的发布过程相对应的常见的反模式包括:

    • 手工部署软件。靠详尽的发布文档来描述发布步骤及每个步骤中易出错的地方,靠手工测试来确认发布后的应用程序是否运行正确。不自动化的部署过程既不可重复也不可靠,会在调试部署错误的过程中浪费很多时间。
    • 开发完成之后才向类生产环境部署。开发团队认为“开发完成了”,才第一次把软件部署到类生产环境(比如试运行环境)。假如应用程序是全新开发的,第一次将它部署到试运行环境时可能会非常棘手。
    • 生产环境的手工配置管理。通过专门的运维团队来管理生产环境的配置,如果需要修改一些东西,就由这个团队登录到生产服务器上进行手工修改。经常导致部署到生产环境时就失败,尽管多次部署到试运行环境都非常成功。

    在云计算的背景下,我们可以看得更远一步:这些反模式如果在今天的研发团队中仍然出现,背后反映的是这支研发团队还不会利用云计算提供给他们的便利能力。

    • 手工部署软件 => 软件发布形态和流程不标准。因为软件的发布形态多种多样(JAR、WAR、RPM、DEB……),因为软件的功能与配置不解耦,所以才会需要手工部署。而发布形态和发布流程的不标准,背后的原因是计算资源稀缺,需要复用服务器。
    • 部署到类生产环境太晚 => 开发环境与生产环境不统一。因为开发和测试用的环境与生产环境有很大差异,才会出现部署到类生产环境时的种种困难。开发环境与生产环境的不统一,背后的原因也是计算资源稀缺,生产环境昂贵,无法做到随需可得。
    • 生产环境手工配置管理 => 环境管理情况复杂。因为环境需要长期使用且不断升级,才有了对环境进行管理的需求。环境需要长期使用和升级,背后的原因是计算资源缺乏弹性,不需要的时候不能随意丢弃。

    对于这些反模式,《持续交付》提出的解决办法是“将几乎所有事情自动化”。但在当时的技术水平下,由于软件发布的形态和流程不标准、开发/测试环境和生产环境不统一、环境管理情况复杂,“将发布流程自动化”在每个团队的具体做法都不同,因此持续交付的水平高度依赖于团队的能力与觉悟。《持续交付》也只能苦口婆心地劝说“如果需要执行这个流程数十次的话,就不是那么容易的事了”,而且“不需要把所有的东西一次性地全部自动化……随着时间的推移,最终你可以、也应该将所有环节全部自动化”。

    但如果在软件的开发过程中充分利用云计算的弹性能力,这些反模式有可能被根除,而不必由每个开发团队重复地尝试通过自动化来缓解。

    部署流水线

    《持续交付》提出了“部署流水线”的概念(如下图)。“随着某个构建逐步通过每个测试阶段,我们对它的信心也在不断提高。当然,我们在每个阶段上花在环境方面的资源也在不断增加,即越往后的阶段,其环境与生产环境越相似。”

    在充分利用了云计算的情况下,部署流水线会有两方面的改变:

    1. 不存在“所用环境与生产环境的相似度增加”的情况,从提交阶段开始(甚至在此之前的开发阶段),所有环境都与生产环境是一致的。
    2. 由于不需要根据项目拥有的计算资源来定制各个环境与生产环境的相似度,这个部署流水线不再是一个需要由开发团队来实现的概念模型。部署流水线可以是标准的、一致的,开发团队只需要定义自己这个软件的生产环境即可。

    《持续交付》中提倡整个部署流水线“只生成一次二进制包”,并且在各个验证步骤之间传递二进制包。只生成一次二进制包的实践是非常必要的,因为“出于审计的目的,确保从二进制包的创建到发布之间不会因失误或恶意攻击而引入任何变化是非常关键的”。但实际的项目中经常出现二进制包非常庞大、在各个步骤(及各个环境)之间传递二进制包很费时的情况,这也是导致一些项目最终仍然退回到每个步骤重新构建二进制包的原因:增量的编译和构建可能比通过网络传递整个二进制包还省时。

    如果构建的产物是容器镜像,所有运行时环境都从云上获得,那么实际上不存在传递二进制包的过程。每个验证步骤都用指定版本的容器镜像搭配对应的配置,启动一个新的运行时环境后,在云上的运行时环境中执行(自动的或手工的)验证即可。

    持续集成

    尽管《持续交付》说“选择并安装好持续集成工具之后,只要再花几分钟的时间配置一下就可以工作了”,但实际上很少有哪个项目的持续集成实施会如此顺利。例如当“发现在运行持续集成工具的机器上缺少一些必需的软件和设置”时,《持续交付》提出的建议是“将接下来你所做的工作全部记录下来,并放在自己项目的知识共享库中……并将重建全新环境的整个活动变成一个自动化的过程”。实际上,这是一件需要高度技能水平和纪律性的事,拥有这两者的技术领导者(Tech Lead)很罕见,希望每个开发团队都有这样一名技术领导者坐镇是个奢侈的梦想。

    而且,持续集成环境与开发环境仍然是有区别的,这个区别很可能是由于计算资源的限制。《持续交付》中说,“你可以很有把握地说:‘只要是在与持续集成一模一样的环境上,我的软件就可以工作。’”。然而问题就在于大多数情况下,开发环境与持续集成环境不是一模一样。这也是为什么持续集成必须集中式地进行,需要有“铃声和口哨”来及时发现构建失败,并且“要让持续集成能够发挥作用……整个开发团队就必须有高度的纪律性”。

    在充分利用云计算的情况下,开发一类软件(例如“Java微服务”或“ReactNative移动应用”)所需的环境和部署流水线可以由少数几名优秀的技术领导者来标准化,开发团队不需要再操心如何配置一个持续集成环境的问题。

    并且正如《持续集成将死》一文中所说,云的弹性能够使每个人、每次构建都使用标准的类生产环境,因此持续集成没有必要发生在一个中心化的“持续集成工具”上。由于持续集成的“集成”这个动作在代码进入团队代码库之前发生,很多的提醒和纪律变得不必要了:构建失败就不能提交代码,于是确保构建成功成了每个开发人员自己的事,不能把不成功的构建扔给团队去处理。


  2. 持续集成将死

    在思考“云时代的研发环境长什么样”这个问题的时候,我逐渐意识到一件很重要的事。2000年首次被提出、在过去十几年中我们习以为常的敏捷核心实践持续集成,很可能正在走到它生命周期的尾声。

    让我们来回顾一下Martin Fowler在他那篇著名的文章里如何描述持续集成这个过程:

    一旦完成了修改,我就会在自己的计算机上启动一个自动化build。……当我build成功后,我就可以考虑将改动提交到源码仓库。……然而,提交完代码不表示就完事大吉了。我们还要做一遍集成build,这次在集成计算机上并要基于mainline的代码。只有这次build成功了,我的修改才算告一段落。……在持续集成环境里,你必须尽可能快地修复每一个集成 build。好的团队应该每天都有多个成功的 build。错误的 build 可以出现,但必须尽快得到修复。

    从上面加粗的文字就能看出,过去的十多年里,在谈及持续集成这个实践时,我们已经预设了这个场景:有一个集中式的持续集成服务器在监听代码库的变化,每当有人提交代码时,持续集成服务器会自动取出最新的代码,执行整个构建和测试流程。围绕着这个场景,我们发展出了一整套的纪律来保障持续集成少失败、失败的时候能尽快修复。围绕着这个场景,我们发明了CruiseControl、GoCD、SnapCI等一代又一代的持续集成服务器,并在我们所有的项目中使用它们。这个场景在我们的脑海中如此根深蒂固以至于我们不再去询问:为什么需要这样做?

    实际上,我们需要一个集中式的持续集成服务器,这是有历史原因的。2000年代初期的技术时代背景,尤其是以下两个非常具体的约束条件,造成了今天我们看到的持续集成的形态:

    1. 计算资源短缺。这个约束条件决定了完整的、与生产环境相似的、能执行端到端验证的环境必定是稀缺品。典型的交付团队没有能力给每个成员配备整套环境,只能在他们各自的计算机上模拟一套尽可能接近于生产环境的开发环境。于是开发环境的验证结果不足为信,必须在一个标准的、更接近于生产环境的集成环境上通过验证,才能说软件达到了质量要求。
    2. 版本控制工具的局限性。Subversion(以及其他更早的版本控制工具)在pre-commit阶段通过服务器端回调钩子很难——如果不是完全不可能的话——得到完整的“提交后版本”,因此svn的pre-commit钩子基本只能用于检查提交信息是否符合规范,完整的验证则必须在代码已经合入代码库之后才能——在一台独立的“持续集成服务器”上——进行。

    云计算彻底改变了第一个约束条件。计算资源仍然不能说极大丰富,但企业应用开发所需的x86架构计算资源在云环境下已经不再短缺,结合各种基础设施自动化和配置自动化的技术,随时、按需提供整套环境已经不是难题。而且使用docker等容器技术开通出来的环境是抛弃型的、不可变更的,因此也就不存在环境不一致、验证结果不可信的问题:每个开发人员都可以从云上拿出一套环境,执行build,其过程与效果都与持续集成服务器的build完全一致。

    在过去的十多年里,持续集成之所以必须是一种“技能”、一门“手艺”,而不仅仅是一套工具的定制与实施,很大程度上正是由于计算资源短缺这个约束条件造成的。因为计算资源几乎总是短缺,所以每个团队、每个项目拥有的计算资源几乎总是有些这里那里的不同——这个项目可能有两套完整的测试环境,那个项目可能只有一套。这种资源的局限,逼迫每个项目的技术领导者们不得不根据手上能得到的环境,来微调持续集成的流水线乃至软件交付的流程。简言之,流程是依据环境来调整的。

    当计算资源短缺的约束条件不再存在,在考虑构建流水线时就可以有一个根本的观念转变:可以制订一套标准的构建流水线,并要求计算环境向这套流水线对齐。这时,持续集成就可以不必是每个团队的技术领导者都掌握的“技能”和“手艺”,它完全可以在一个组织范围内定制和大规模实施。因为环境可以弹性地适配流程,我们就能够为相同类型的项目定义统一的最佳流程。

    而git对svn的全面取代则带来一个细微而深远的影响:由于可以在pre-commit阶段直接获得完整的待提交快照、并在这个版本基础上执行测试,不能通过build的代码将直接被拒绝提交。换句话说,整个“持续集成纪律”尝试解决的问题——有缺陷的代码进入团队的代码仓库从而妨碍其他人不断提交没有缺陷的代码——将不复存在,有缺陷的代码将根本无法进入团队的代码仓库。

    综上所述,这两个要素的结合:

    1. 每个开发人员(以及自动构建)都可以在PaaS云上获得完整的技术栈运行时环境;以及,
    2. pre-commit阶段可以对待提交的代码进行完整的构建

    带来的是一个非常重要的影响:持续集成服务器这个东西,我们不再需要了。持续集成的“集成”这个动作,将在代码进入团队代码库之前发生。我们有办法(git的pre-commit钩子)确保这次集成发生,也有办法(云化、容器化的环境)确保这次集成是可信的。因此我们不再需要一个持续集成服务器来扮演团队的守门人。集中式的持续集成服务器将退化为团队研发行为的可视化仪表盘:它不再负责管理环境和构建软件,只负责采集所有构建中产生的数据、并以适当的形式展示,作为团队研发过程的可视化呈现。

    当持续集成服务器消亡,一个开发者的典型工作流程可能会是这样:

    • 从git仓库clone出代码,在自己的电脑上做修改;
    • 修改完成,从研发PaaS上获得一个运行环境,把刚写好的代码运行起来,用浏览器查看一下效果;
    • 执行构建,构建脚本自动从研发PaaS上获得一个运行环境,在其中执行编译、打包、代码检查和测试;
    • 构建通过,提交代码并push,git仓库的pre-commit钩子自动触发一次构建,过程与效果都与刚才手动执行的完全一致;
    • 如果没有手工执行构建就尝试提交,自动构建会失败,代码无法push到团队的代码仓库中,开发者自己去修复;
    • 如果自动构建成功,代码提交完成,最新版本的代码被构建成容器镜像;
    • 测试人员从研发PaaS上获得一个运行环境,把待测版本的容器镜像装载上去,执行测试,如果测试通过就将该版本标记为“发布候选”;
    • 运维人员从生产PaaS上获得一个运行环境,把发布候选版本的容器镜像装载上去,即完成上线。

    这个流程直接地实现了《持续交付》中描述的“两道门”结构。虽然每个项目运行的环境不同,但这个持续交付的结构可以是完全一致的,因为环境可以弹性地适配研发流程。

    与持续集成服务器同时消亡的,还有持续集成这个概念本身。由于对响应力(responsiveness)的要求是如此之高,现代的IT团队已经不能容忍有缺陷的代码先进入代码库、阻塞整个团队的工作、然后再来修复(甚至不修复、或者还需要说服某些团队成员去及时修复)。持续集成是如此重要,以致于它会变成团队的“空气和水”。它会被嵌入到日常的研发工具当中,成为程序员感知不到、而又不可妥协的质量要求——正如IntelliJ之类现代IDE把“通过编译”这项要求变成了程序员感知不到、而又不可妥协的质量要求。

    持续集成对于软件开发是如此重要,以至于不应该把它交给软件开发者自己去做。

    这就是为什么我认为持续集成工具、以及这些工具背后的持续集成概念在云计算深入研发之后将会消亡。取代持续集成的,将是更紧密地内嵌质量要求、更充分地利用云计算优势的云原生(Cloud Native)开发方法及支撑工具。


  3. 数字化企业的API架构治理

    前文中我们说到,传统企业在逐步建设自己的数字平台过程中,需要抓住交付基础设施、API和架构治理、数据自服务、创新实验基础设施和监控体系、用户触点技术这五个支柱。今天我们就来谈一谈API、架构治理这些听起来非常技术性的概念与企业的数字化战略之间有何关系。

    企业资源服务化

    从1990年代起,企业资源计划(ERP)一直是企业信息化的核心议题。植根于供应链管理,ERP通过对企业内部财务会计、制造、进销存等信息流的整合,提升企业的计划能力与控制能力。然而近年来,在互联网的冲击下,传统企业开始面临全新的挑战。尤其是在互联网的去中介化效应影响下,原本在供应链上下游各安其位的企业突然间都被压缩到了“生产-流通-消费”这个极度精简的价值链中。药品购销两票制就是这个极简价值模型的直观呈现。在这个模型中,掌握技术优势和消费者入口的互联网企业有可能形成一家独大的超级垄断,挤死传统的流通企业,把生产企业变成自己的OEM厂商,这是传统企业对来自互联网的竞争者恐惧的根源。

    为了对抗互联网企业的竞争,传统企业最好的办法不是硬拼互联网上的技术和流量,而是在自己擅长的领域开战:把自己多年积累的线下资源变成线上服务,构建起本行业的线上生态系统,不仅支撑本企业的线上经营,而且为上下游周边企业提供线上经营的平台,从而把线下优势转化为线上优势,以资源优势对抗技术优势。

    为了支撑企业资源的服务化,在设计在线服务的API和架构时需要考虑以下问题:

    • 平台架构和API的设计应该注重开发者体验
    • 在API的背后,应该从业务功能的角度出发划分合理的限界上下文和服务边界,对外提供高内聚低耦合的服务。
    • 在服务边界之间,应该考虑使用异步的事件机制实现服务之间的通信,来解耦领域模型,客观地描述运行时间比较长、甚至本质上不可能立即完成的操作。
    • 为了方便使用,应该提供API网关作为所有服务使用者的单一入口,在API网关背后去处理众多内部IT系统的复杂性。
    • 整个API架构应该以微服务的风格呈现,避免典型SOA架构中普遍存在的过于复杂的ESB编排逻辑。

    ERP之后是什么?

    进入2010年代以来,“后ERP时代”这个说法不断被提出。在谈到ERP的发展方向时,通常都会涉及业务与技术两个角度。例如一种观点认为,ERP需要从以流程为中心转变为以客户为中心,并且需要用好云计算、社交网络、大数据和移动化等新技术。

    ThoughtWorks认为,ERP在互联网时代的发展方向将是企业资源服务化(Enterprise Resource Servicification,ERS),通过数字平台的技术能力,把一家企业的资源融入一个行业的互联网生态,为企业铺下明确的数字化道路。

    API和架构治理解读

    下面我们来近距离看看,在“API和架构治理”这顶帽子下面,有哪些具体的问题需要被考虑到。

    开发者体验

    当企业资源以服务的形式对外提供,也就意味着不可能——像传统的IT系统建设那样——强迫别人使用这些服务。尤其是要把这些服务提供给第三方开发者、希望他们开发出形形色色的应用程序,那么服务的API是否易用就会很大程度上影响它能吸引到多少第三方开发者。ThoughtWorks第16期技术雷达还专门把开发者体验作为一个重要的技术主题。

    在讨论开发者体验时,可以从开发工具和开发环境的安装、配置、管理、使用、维护等角度来考量。具体而言,开发环境和测试环境是否能弹性地随需获得,开发/测试基础设施和持续交付流水线是否以源代码的形式提供并完全自动化,是否提供对主流开源软件的支持,是否提供可编程的、命令行友好的(而不仅仅是图形化的)工具界面,安全、数据访问权限等企业规章是否严重影响开发者的效率和感受,这些都是影响开发者体验的要素。

    服务边界

    和所有的面向对象设计一样,服务的设计应该是高内聚低耦合的:与一个业务相关的修改只在一个服务内部进行,并且一个服务的修改/部署不需要影响其他服务。和一个代码库内部的对象设计不同,每个服务通常有专属的代码库,并且由专人负责维护(而不是所有人拥有所有代码),因此服务边界的改变会带来更大的变更成本。所以,服务边界的划分需要投入精力认真对待。

    从设计原则上来说,服务的边界应该体现业务的边界,而不是单纯从技术角度出发划分服务边界。从业务功能的角度出发划分合理的限界上下文,以领域模型和领域事件的聚合为出发点来划分服务,更可能得出与业务边界一致的服务边界。随后再以业务目标驱动建设全功能一体化团队,就能做到业务、技术、团队三者对齐(康威定律再次起作用)。四色建模事件风暴等方法都能有效地实现领域驱动设计,从而建立起良好的领域模型及服务边界。

    事件驱动架构

    使用异步的事件机制实现服务之间的通信。对于运行时间比较长、甚至本质上不可能立即完成的操作(例如涉及人工操作),使用异步通信是合理的选择。即便不考虑响应的实时性,事件驱动的架构还表达了领域模型之间的松散耦合关系:跨领域的协作以事件而非方法调用的形式来表达,系统追求最终一致性而非强一致性。这一结构准确地映射了真实世界中多支相关但独立的团队之间的协作关系,避免了过度依赖其他服务的响应速度或可靠性等服务质量指标,使服务真正具有技术上的独立性。

    在设计系统时,借助事件风暴方法,可以通过领域事件识别出聚合根,进而划分微服务的限界上下文。当出现跨多个聚合根的事件时,可以很自然地将其实现为异步的领域事件,从而获得与领域设计高度吻合的实现。关于如何设计和实现领域事件,可以参阅ThoughtWorks咨询师滕云的文章

    在实现事件驱动的架构时,当然可以沿用传统的SOA架构中的消息中间件。但由于微服务架构中,业务逻辑都存在于各个服务内部,没有庞大臃肿的ESB(稍后我们还会详谈这个问题),因此消息机制也不需要强大的服务编排(orchestration)能力。RabbitMQ这样标准的消息代理当然很好,也有很多系统(例如Bahmni)采用更简单的做法:领域事件发生时,以ATOM格式发布;关心特定领域事件的其他领域模型则订阅特定的ATOM feed主题。这种基于HTTP的事件传播方式最大的好处就是简单,几乎不需要增加新的软件就可以实现。不过这个方案在处理低延迟的场景时表现不佳。

    公共网关

    微服务提供的API粒度与客户端的需求不同,所以客户端一个请求经常需要多个服务;服务端和客户端之间可能需要通信协议转换;不同的客户端对数据的需求不同,例如浏览器客户端需要的信息可能多于移动客户端;服务的终端信息(主机+端口)可能变化;不同数据片可能由不同的服务终端来提供——以上这些因素都指出:有必要对服务做一层门面封装,提供API网关作为所有服务使用者的单一入口点。

    API网关处理请求的方式有两种:一种是直接代理/路由给合适的服务;另一种是由一个请求扇出/分发给多个服务。API网关可能针对不同客户端提供不同的API,可能包含针对客户端的适配代码。横切需求(例如安全)也可能在API网关实现。

    当服务数量变多、API网关变大以后,维护一个通用的API网关会增加API网关层的复杂度,导致一个独立的“API团队”出现,协调和沟通的工作量加大。这时可以考虑引入公共网关的一个变体:为特定前端设计的后端(Backend For Frontend,BFF),即为每个前端应用提供一个单独的API网关,使对齐业务的一体化团队能够拉通前后端开发、而不必等待“API团队”完成他们的backlog。

    API网关可以实现为一个独立的服务端应用,其代价则是增加一层复杂度(和出错的可能性)。为了降低这一代价,可以考虑用Zuul等工具来实现API网关。

    微服务SOA拓扑

    与传统的SOA架构相比,所谓“微服务”最大的特点可能就在于没有一个重量级的ESB。重量级的ESB有其历史原因。在2000年代业界刚开始采用SOA时,很多企业尽管把业务系统包装成了web服务,但IT团队的组织结构并没有发生改变,仍然是由一组人集中式地掌管整个业务流程——只不过系统集成的方式不再是直接的方法调用,而是服务编排(orchestration)。原本存在于集成代码中的复杂逻辑,现在被转移到了ESB中。而这个“ESB团队”成了IT交付的瓶颈:不论发布事件的服务还是消费事件的服务、或是编排逻辑本身的改变,与事件相关的变更都需要通过ESB团队。这个团队的backlog堆积起来,使得每个服务、每个应用都无法提供快速响应。

    微服务架构更重视服务与业务的对齐。贝索斯所说的“两个pizza的团队”不仅负责一个IT系统的交付,而且要负责用这个IT系统来支撑一个业务的成功。为了做到单个服务能够独立开发、独立部署、独立运行,这支团队应该能够在很大程度上掌控自己的进度,而不依赖于一个集中式技术团队的进度。因此微服务应该通过服务注册与发现机制获得自己需要的依赖服务、自己判断是否要直接调用或订阅依赖服务的事件,每个服务包含与其业务对应的复杂度,而不是把整个系统的复杂度集中在ESB和编排逻辑上。整个系统的架构(以及团队的架构)应该呈现为若干个端到端拉通的、与业务对齐的纵切服务,而不是一个横切的大块(ESB)覆盖所有业务。

    小结

    为了激活企业线下资源、打造行业线上生态,IT需要一套有效的服务API和架构治理方法。首先从领域驱动设计入手,划分出合理的限界上下文和服务边界,然后用异步消息机制来描述领域事件。设计好的服务通过API网关或BFF暴露给前端应用,把依赖关系和集成逻辑约束在与业务对齐的一体化团队内部。在整个服务架构的设计中,需要保持对开发者体验的关注。顺畅地将企业资源服务化,这是企业数字化旅程的第二步。


  4. 数字化企业的交付基础设施

    前文中我们说到,传统企业在逐步建设自己的数字平台过程中,需要抓住交付基础设施、API和架构治理、数据自服务、创新实验基础设施和监控体系、用户触点技术这五个支柱。那么,当我们谈“交付基础设施”,我们究竟在谈什么?怎样的交付基础设施能加速数字化项目的交付?

    什么是交付基础设施

    云时代的研发环境应该以原生支持云计算的方式提供、管理和维护。在提供基础的弹性计算能力的IaaS平台之上,交付基础设施负责为交付团队提供便利的、最好是自助式的工作环境,让交付团队专注于交付软件的功能性需求,而不必操心软件功能之外的“脚手架”工作。按照ThoughtWorks数字平台战略的定义,这些脚手架包括:

    • 弹性基础设施,即交付团队使用底层云计算平台的方式,既包括各种虚拟机和镜像的管理,也包括生产环境的水平伸缩能力。
    • 持续交付流水线,交付团队编写的代码需要通过这条流水线最终变成可以上线运行的软件。
    • 部署运行时,软件在开发、测试、试运行、用户验收、培训、生产等各种环境需要部署的环境。
    • 监控,为交付团队提供生产环境(及其他环境)的可观测性,方便他们发现和解决问题。
    • 安全,把安全内建在软件的研发过程中,尽量避免因为人为失误造成安全隐患。

    从前这些交付基础设施脚手架通常是由每个交付团队的技术领导者(Tech Lead)来负责搭建和维护的。并且由于软硬件资源的稀缺和不灵活,团队经常需要微调自己的实践来适应不同的环境。所以,即使在同一家公司,各支团队所使用的交付基础设施也可能大相径庭。交付基础设施不一致、不规范的情况会迫使团队花费额外的精力去操心脚手架工作,并且使最佳实践不易推广普及。走上数字化道路的企业必定有大量的软件项目,尤其是微服务架构风格的引入会使企业拥有数量更多、单体规模更小的软件应用,此时交付基础设施不一致、不规范的情况就会对企业的数字化进程带来更大的阻力。

    云计算带来的弹性和灵活性让组织级的交付基础设施标准化、规范化成为可能。一个跨越项目团队的、组织级的交付基础设施团队现在可以在IaaS的基础上封装标准的脚手架,甚至把脚手架本身以PaaS的形式提供给交付团队。通过把整个企业优秀技术领导者的知识与经验内嵌在交付基础设施脚手架中,就降低了对单个交付团队的技术要求,帮助企业缓解优秀技术领导者难以获得的人才挑战。从这个意义上,以PaaS形式提供的交付基础设施本质上是技术领导者作为服务(Tech Lead as a Service)的云计算应用形式,它解决的是优秀技术人才的弹性和灵活性问题,让企业能够以一种创新的方式使用这些人才。

    架构师写代码吗?

    关于“架构师是否应该写代码”这个问题,业界有各种不同的声音。在敏捷的社区里,意见倾向于认为架构师需要写代码,因为这是他们获得关于技术决策的反馈和建立技术领导力的重要方式。将交付基础设施明确提出来,就给了架构师又一个清晰的编程目标——他们需要用代码的形式描述软件交付中的基础设施和最佳实践。除了培训、开会、代码评审等我们已经知道效率并不太高的方式以外,架构师对交付团队的指导和监管现在可以用实实在在的代码来承载。当交付团队不理解架构师说的某件事应该怎么做,现在他们更有理由要求架构师“show me the code”。

    交付基础设施解读

    下面我们来看看,在“交付基础设施”这顶帽子下面,架构师/技术领导者们究竟应该关心哪些问题,又有哪些最佳实践应该被纳入他们的视线。

    弹性基础设施

    允许交付随需获得计算能力。在微服务语境下,这种弹性有两层常见的含义:在生产环境下,服务可以随负载动态获得和释放计算资源,从而更高效地使用计算资源,更自动化地应对负载变化;在研发环境下,开发、测试、运维等不同角色可以随需动态获得完整的环境,从而统一环境、标准化研发实践、规范化研发能力,并且给研发提供体验更好的开发环境。

    为了实现弹性基础设施,一方面基础设施需要支持弹性,例如使用支持弹性计算的公有/私有云,并且有对生产环境的监控和自动化手段;另一方面应用本身需要有可扩展性,例如服务能分别独立部署、无状态化、容器化、有透明的前端负载均衡机制。有状态服务(比如数据库服务)的弹性伸缩问题是特别需要考虑的重要挑战。

    持续交付流水线

    用持续交付实践打通微服务的开发、构建、验证和部署流程。在数字化、服务化的背景下,众多互相依赖的微服务形成的系统架构,对构建、验证和部署造成更大的压力:各个服务有独立的代码库和构建流程,又需要随时能组合成可用的软件;构建产物需要有统一的存储管理;完整的运行时环境应该能按需获得;配置和部署应该能快速准确地完成。

    为了应对这些挑战,交付基础设施中应该包含完整的持续交付概念:流水线、环境管理、构建产物管理等。应该鼓励对服务虚拟化,最好是每个主机运行一个微服务,而不共享使用主机。应该包含配置自动化工具,例如Chef、Puppet等。在服务化的背景下,持续交付流水线需要体现服务间的依赖关系和团队间的协作关系,设计一个运转良好的流水线不是容易的任务。

    部署运行时

    交付基础设施应该包含生产系统所使用的运行时环境,并把生产环境前向拉通到验证和研发环节。为了在研发流程的出口得到服务化友好的交付物,最好是在整个开发过程中一直使用与生产环境近似的环境。例如开发人员应该使用全套环境随时验证,自动化测试和手工测试都基于全套环境开展。在这种情况下,环境的设置、管理、更新不可能由每个开发人员和测试人员自己进行,所以环境的管理更新必定是集中进行的,环境的设置必定是自动化的。

    在《技术栈管理:云时代的研发环境》一文中,我们已经介绍过“一个平台、两个PaaS服务、三个运行时环境”的技术栈管理理念。特别需要注意的是,如何将生产数据拉通到验证和研发环节。

    监控

    在微服务架构中,系统由多个小服务组成,且广泛使用异步通信,使问题和故障更难定位。因此交付基础设施需要提供全面可靠的监控机制,帮助交付团队了解系统的整体状况。

    监控的实现涉及日志、服务指标跟踪、业务语义综合监控等方式。在云环境下如何划分和管理监控的层级,监控系统如何无侵入的在各个微服务体系中收集故障和信息,如何有效管理监控的反馈环,如何在前后端分离和移动应用情况下收集和监控客户端日志,都是常见的挑战。

    安全

    当数字化、服务化IT系统的数量剧增,安全的设置会变得更加复杂。在微服务架构下,系统的安全性需要有一个整体的考虑。例如单点登录、服务间的身份验证和授权、各种防御措施等安全考量不应该下放到交付团队,而应该被涵盖在交付基础设施中统一提供、统一管理、统一更新。

    交付基础设施还应该鼓励安全实践内建(Build Security In),例如团队应该熟悉OWASP安全列表和测试框架、需求分析中应该包含安全需求和恶意用户需求、测试过程中应该包含安全性测试、应该进行自动化安全性测试并纳入持续交付流水线。这些流程与工作方法虽然不能完全以软件代码的形式承载,但它们同样是交付基础设施的重要组成部分。

    小结

    数字化、服务化的IT大背景会让企业开发和拥有的IT系统数量剧增。当企业IT交付更多地以“两个pizza团队”的形式组织,依赖于每个交付团队的技术领导者来搭建和维护一套完整高效的交付基础设施脚手架,这种期望即使不是完全不现实,也会对企业的人才积累提出非常高的要求。因此,企业应该集中优秀的技术人才(包括架构师们),打造一套标准的交付基础设施,充分考虑生产环境与研发环境的弹性、持续交付、部署运行时的统一、监控、安全等因素,并借助云计算的弹性和灵活性将其提供给交付团队。用便利的脚手架赋能一支能快速交付的团队,这是企业的数字化旅程的第一步。


  5. 技术栈管理与云时代的持续集成

    在刚刚发布的第16期技术雷达中,我们看到ThoughtWorks在“技术”象限里旗帜鲜明地列举了几项与持续集成相关的反模式。这些存在多年的实践和现象被放在了“暂缓”一环中,意味着ThoughtWorks正式向我们的客户指出:如果你的组织仍在这样实施持续集成,我们认为你应该考虑改变了。那么,这些被批评的点背后映射出哪些问题,基于技术栈管理的云时代研发环境又能带来什么新的思路?我们一起来深入分析。

    持续集成的反模式

    最需要被点名批评的现象莫过于“持续集成剧场”了:

    很多开发者只是简单的搭建了持续集成服务器就以为在做“持续集成”,但他们实际上会遗失持续集成的关键优点而导致失败。常见的失败模式包括:虽然在一个共享的主分支上运行持续集成,但是代码提交不频繁,所以集成并没有真正的“持续”。以及在一个测试覆盖率不足,甚至是长期状态为红的情况下进行构建;或者在功能分支上运行持续集成,这会导致持续隔离。

    简而言之,这些团队并没有真正体会到持续集成的好处,而是为了完成上级的任务而演一场“我们在持续集成”的戏——这也正是这个反模式的名字由来。过去十年中,我们在众多刚开始实施持续集成的企业见过这一幕。领导认识到持续集成的好处,但是推行成了个大问题:推轻了,下面团队不愿动,技术问题解决不了;推重了,下面团队来个上有政策下有对策,领导想看什么就给你演什么——持续集成剧场就此落成。比如说你见过一个表面看起来一直是绿色但是背后连编译都不敢跑的持续集成吗?我见过。真是一场好戏。

    为了解决持续集成演戏的问题,一些规模较大的企业开始建设持续集成中心。想法很符合直觉:既然团队自己做持续集成有技术困难、还有可能变成演戏,那么我就组建一支团队专门帮他们一个个把持续集成跑通、帮他们管理持续集成服务器,持续集成的运行和统计数据都在这个中央团队手里,下面的团队总没办法演戏了吧?于是,他们又遭遇了第二个持续集成反模式:“所有团队共用一个持续集成实例”。

    那些必须使用中心化持续集成服务器的交付团队,常常依赖中心的团队去完成小的配置任务,或者在共享的基础设置和工具中排查问题,这给他们在进度上带来长时间的滞后。

    这次是康威定律带来的困难:如果每个团队使用的技术栈配置不同、技术栈配置和管理的职责仍然在每个团队中,那么技术栈演进与持续集成的演进就难免出现节拍不一致。于是管理着持续集成中心的中央团队开始疲于奔命,帮一个个项目团队修持续集成,而项目团队还感到没有得到足够的支持。

    第三个反模式是“企业级集成测试环境”,这也是很多组织建设持续集成中心的初衷之一:由于能执行完整端到端测试的环境稀缺,各个团队的集成测试无论如何也必须在一个瓶颈处统一调度,所以中心化管理持续集成也就顺理成章。然而,

    这些企业集成测试环境通常称为 SIT 或预生产环境)是当下持续交付常见的瓶颈。环境本身很脆弱而且维护成本很高,而这些环境通常存在一些需要由单独的环境管理团队手动配置的组件。在预生产环境的测试给出的反馈慢且不可靠,而且会重复测试那些在隔离的组件上已经测过的功能。

    云时代的新思考

    技术雷达中批评的这些持续集成的反模式,是过去的时代背景造就的。尤其是以下几点约束条件,造成了今天我们看到的持续集成的形态(以及长久以来存在的挑战):

    1. 计算资源短缺。这个约束条件决定了完整的、与生产环境相似的、能执行端到端验证的环境必定是稀缺品,因此一个组织中多个团队的集成必定会受限于某个瓶颈,或是企业级集成测试环境、或是持续集成中心。
    2. 计算环境没有弹性。不仅硬件资源短缺,而且环境的开通、配置和管理很麻烦,所以团队会调整自己的技术实践去适应已有的环境,而这个调整的动作主要由团队内的技术领导者来执行。其结果是即便多个团队开发的软件在技术栈上非常相似,他们的持续集成实践也可能相当不同,在技术能力不足的团队就会变成持续集成剧场。
    3. 版本控制工具的局限性。Subversion(以及其他更早的版本控制工具)在pre-commit阶段通过服务器端回调钩子很难——如果不是完全不可能的话——得到完整的“提交后版本”,因此svn的pre-commit钩子基本只能用于检查提交信息是否符合规范,完整的验证则必须在代码已经合入代码库之后才能——在一台独立的“持续集成服务器”上——进行,而此时如果构建失败就会阻塞整个团队的工作。这也导致更多的团队倾向于放松持续集成的要求、甚至沦落成持续集成剧场。

    而这几个约束条件在今天的时代背景下已经不复存在:计算资源仍然不能说极大丰富,但企业应用开发所需的x86架构计算资源在云环境下已经不再短缺;在IaaS的基础上,技术栈管理的PaaS提供了计算环境的弹性,使用相同技术栈的多个团队可以轻易地获得完全一样的环境,因此团队也可以采用标准的技术实践,而不必为了将就手边的环境而调整实践。而git对svn的全面取代尤为值得玩味:由于可以在pre-commit阶段直接获得完整的待提交快照、并在这个版本基础上执行测试,不符合持续集成要求的代码将直接被拒绝提交——而不是在提交后才把问题暴露出来。于是,以下两个要素的结合:

    1. 每个开发人员(以及自动构建)都可以在PaaS云上获得完整的技术栈运行时环境;以及,
    2. pre-commit阶段可以对待提交的代码进行完整的构建

    将带来两个重要的影响。首先,持续集成不再需要一个“服务器”。从它发展的早期开始,持续集成这个概念就一直与各种“持续集成服务器”软件工具紧密关联:从早期的CruiseControl、Bamboo到后来的Jenkins、GoCD,以及云上提供服务的TravisCI、SnapCI,持续集成中的“集成”这个动作一直发生在代码已经提交之后、发生在一个团队共有的服务器上。而现在,持续集成可以在代码提交之前发生、在一个从PaaS云上弹性生成的环境中发生。

    这个技术性的改变带来的组织性改变将有着重要的意义:保证持续集成通过将会彻底变成每个开发人员自己的责任,没有折扣可打,没有其他地方可以推卸责任——现在构建不通过不会阻碍其他人提交代码了,只有这个开发人员自己不能提交代码。由此,持续集成将由一项团队实践变成一项个人实践、由一项有较大妥协空间的实践变成一项强制性的实践。正如IntelliJ之类现代IDE把“通过编译”这项要求变成了程序员感知不到的、而又不可妥协的质量要求,技术栈管理PaaS平台将把持续集成也变成程序员感知不到的、而又不可妥协的质量要求。

    持续集成是如此重要,以至于我们不应该把它交给程序员自己去做。

    在这样的一个研发环境下,每个开发人员从写下第一行代码开始就必须遵循组织的质量规范,能够被提交到团队代码库的代码都是通过了验证流程、符合质量要求的。6年前当我构想这样一个研发环境,我觉得它更像是一个遥远的梦想。然而今天,支持这样研发环境的技术栈管理PaaS平台已经被实现出来了。你需要的就是在你的研发云上实施它。


  6. 什么是数字平台战略

    传统企业正在面临IT新技术的挑战——单从“传统企业”这个居高临下的称谓,你就能读出“非传统企业”(也就是IT企业、互联网企业)满满的优越感。每天在各种新媒体平台看着BAT们又掌握了什么黑科技、又颠覆了哪个行业,“云大物移”已经成了高频出现的热词,传统企业们愈发清晰地感受到IT的重要性与挑战。数字化浪潮躲不过,和BAT拼技术又拼不过,传统企业的出路在哪里?

    目光投向大洋彼岸,最传统的传统企业、年收入数千亿美元的沃尔玛在过去几年中的数字化历程颇有可玩味之处。直到2011年,沃尔玛还不是出色的数字化玩家,只能算有个电商网站的线下零售商而已。正因为如此,当沃尔玛的电商收入在2011年至2014年的三年间增长150%、从年销量49亿美元增长到122亿美元、超过史泰博(Staples)成为亚马逊和苹果之后美国第三大在线零售商时,这一变化才更令人惊叹。像沃尔玛一样的数字化转型先行者,能给我们带来哪些启示?

    数字化企业的三个关键字

    首先,传统企业们需要清楚一件事:“传统”不应该是贬义词,它同时意味着数十年积累的宝贵资产,包括客户关系、数据、品牌形象、供应链、渠道等等。传统企业要在互联网时代的竞争环境中占得一席之地,靠的不是突破最高精尖的技术领域,而是以数字化的形式激活自己多年累积的核心资产,将核心资产转变为可以在互联网上使用的服务,使其焕发新的价值。

    对众多成功的数字化企业的调研显示,这些企业有着一些引人注目的共性。在“激活核心资产”的过程中,他们对三个关键字的关注特别值得我们关注:IT效能;生态系统;创新实验。

    首先,这些成功的数字化企业重视提升IT团队的效能。正如ThoughtWorks在第16期技术雷达中所指出的,技术人员的工作体验正在成为科技企业的差异化竞争优势。这里所说的“体验”不止是给程序员舒适的座椅和人体工学键盘,更重要的是消除IT团队在工作中遇到的阻力和摩擦,尤其是充分利用云计算的弹性能力大量简化和自动化与实现业务功能无关的基础设施性工作,让IT团队将注意力集中在真正与业务相关的工作上。这里涉及的一些技术和实践(例如技术栈管理)乍听起来可能困难重重,但为提升IT团队效能付出的成本终将物有所值。

    随后,这些成功的数字化企业把他们的核心商业能力与资产以服务的形式在互联网上提供出来,构建本行业的数字化生态系统,使新的服务和产品能够在这些服务的基础上被创造出来。同样是在技术雷达中,我们看到了“平台的崛起”:几年前只有亚马逊这样的巨头企业能在互联网上提供各种云服务;而现在有更多原本不太有“互联网基因”的企业围绕自己的核心资产建立起了数字化平台,不仅对内、而且对外提供服务。在国内,我们看到华为把软件开发能力变成了云服务海航建立了自己的云生态。我们相信,更多的企业也能从核心资产的服务化中受益良多。

    最后但绝非最不重要的,这些成功的数字化企业养成了创新实验的习惯。在互联网中弄潮的经验让他们承认,自己不能预先掌握所有需求、做好所有设计。因此他们转而打造组织的响应力,致力于缩短精益创业的“构建-度量-学习”周期。他们知道成千上万的用户不会明明白白地说自己想要什么功能,于是他们监控用户行为、用A/B测试等方法进行受控实验,用“假说-实验”代替了“需求-实现”,在不断的反馈中完善自己的产品和服务。

    数字平台战略的五大支柱

    以提升IT效能、构建行业生态、促进业务创新为目标,有志于迈出数字化步伐的企业应该立即开始制订自己的数字平台战略蓝图。不要被“平台”和“战略”这样的大词欺骗:这个以增强企业响应力为目标的平台战略不应该是漫长的规划之后建设出一个庞然大物,而应该是迭代的、精益的、价值驱动的。更多的时候,我们谈论的“数字平台”更像是一系列IT技术与实践的落地结合。这些技术与实践有机构成的五个支柱,让数字化的企业能快速交付IT系统、围绕核心资产构建云上生态系统、从线上系统和用户行为中获得洞察、开展受控实验、并为顾客创造全渠道统一的用户体验。在成功的数字化转型案例(例如沃尔玛的案例)中,我们就能看到这五个支柱的投影。

    第一个支柱是支持云和敏捷的交付基础设施。为了让IT团队快速交付,他们使用的基础设施应该具有弹性,开发、测试、运维等不同角色应该可以随需动态获得完整的应用环境,从而统一环境、标准化研发实践、规范化研发能力。他们开发的应用程序应该用持续交付实践打通开发、构建、验证和部署流程,使软件随时处于可发布状态。他们的交付流程中应该内建对安全的考量,而不是依赖最后的整体安全检查。生产系统所使用的运行时环境应该前向拉通到验证和研发环节,保障运行时环境的一致性。需要对系统的IT运维和业务运营进行全面的监控,聚合起来了解系统整体状况。

    第二个支柱是以微服务为核心的API和架构治理。为了鼓励不仅企业内、还包括企业外的开发者在平台上发挥创造力,平台架构和API的设计应该注重开发者体验。在API的背后,应该从业务功能的角度出发划分合理的限界上下文和服务边界,对外提供高内聚低耦合的服务。在服务边界之间,应该考虑使用异步的事件机制实现服务之间的通信,来客观地描述运行时间比较长、甚至本质上不可能立即完成的操作(例如涉及人工操作)。为了方便使用者,应该提供API网关作为所有服务使用者的单一入口点,在API网关背后去处理众多内部IT系统的复杂性。整个API架构应该以微服务的风格呈现,避免典型SOA架构中普遍存在的过于复杂的ESB编排逻辑。

    第三个支柱是允许开发团队数据自服务。为了让业务和研发团队获得关于生产环境、关于线上业务、关于顾客的洞见,他们需要首先定义数据流水线,使数据能够顺畅地流过收集、转换、存储、探索/预测、可视化等阶段,产生业务价值。他们需要用实时的架构和API在短时间内处理大量、非结构化的数据,从中获得洞见,并“实时”影响决策。为了提高应变能力,系统中的数据不做ETL预处理,而是以“生数据”的形式首先存入数据湖,等有了具体的问题要回答时,再去组织和筛选数据,从中找出答案。IT团队会更进一步把数据包装成能供外人使用的产品,让第三方从数据中获得新的洞见与价值。为了支持数据产品的运营,他们需要实现细粒度的身份认证,针对不同的用户身份,授权访问不同范围的数据。

    第四个支柱是创新实验基础设施和监控体系。为了让创新真正基于数据(而非拍脑袋)来开展,IT团队需要从多种来源采集关于系统、关于顾客的数据。需要根据业务目标在系统中埋设监控点,并及时把监控结果可视化呈现给业务用户。为了降低实验试错的风险,在把新版本发布给全部用户之前,应该以“金丝雀发布”的形式首先发布给一小部分用户,确保新版本不造成重大损害。系统需要支持功能切换开关(toggle),允许团队在不修改代码的前提下改变系统的行为,再加上用路由技术支持蓝-绿部署和A/B测试,方可高效地开展受控实验。

    第五个支柱是支持全渠道的用户触点技术。为了通过多样化的触点技术向顾客提供随时随地、连贯一致的用户体验,整个企业需要建立对其顾客和目标顾客的唯一、连贯、准确、整体的视图,从而更好地了解和服务顾客。他们需要结合顾客的特征和不同数字渠道的特征建立连贯的内容策略,在多种渠道(例如电脑、智能手机、门店等)之间引导顾客的消费旅程,与顾客产生正确时间、正确地点、正确方式的交互。基于从各种渠道获得的顾客本人及其行为的数据分析,他们可以向顾客提供定制化的内容、服务和产品推荐。作为必要的技术保障,所有数字渠道的软件应用(尤其是原生的Android和iOS应用)都应该实践持续交付,这样才能实现全渠道的快速响应。

    小结

    在数字化的浪潮面前,传统企业不必恐惧于互联网企业的技术优势。只要抓住交付基础设施、API和架构治理、数据自服务、创新实验基础设施和监控体系、用户触点技术这五个支柱,逐步建设自己的数字平台,不断提升IT效能、构建本行业的数字化生态系统、养成创新实验的习惯,传统企业同样可以用数字技术激活自己多年积累的核心资产,在新的竞争环境中找到自己的一席之地。

    (更多关于数字平台战略的信息,请关注ThoughtWorks数字平台战略网站。)


  7. 云时代的研发环境:实施路径

    前文讲到,在云计算的时代大背景下,我们推荐采用研发技术栈管理平台来集中管理组织中的技术栈,允许基于一个技术栈创建开发测试PaaS和生产PaaS两个PaaS服务,从而支撑开发、测试、生产三种运行时环境。通过三种运行时环境的区分,技术栈管理平台实质上设置了一条标准的精益软件生产流水线,为软件研发生命周期中的三个核心工种——开发、测试、运维——布置了标准的“工位”。在实施技术栈管理平台时,从这三个核心工种之中的任何一个切入,都可以优先建设该工种对应的工位,从而拉动整条云化生产流水线的实施。

    从开发切入,打造规范的软件开发底座

    在数字化的大背景下,众多IT组织都面临技术能力短缺的境况。尤其是传统企业的IT部门,需要用有限的研发专业技能交付越来越多、变化越来越频繁的IT系统,还需要管理外包合作方的团队,对于开发底座规范化的要求日益显著。这些开发团队常见的一些挑战包括:

    • 技术实践能力有限,不能保证每个项目采用业界最佳的框架与工具组合。
    • 开发流程不规范,代码质量关注不够,技术债累积严重。
    • 外包团队管理乏力,对外包团队的开发实践缺乏约束。

    实施技术栈管理平台以后,整个组织可以识别并聚焦几种具有普遍代表性的软件形态(例如“Java微服务”、“Java Web应用”、“安卓移动应用”等),集中技术骨干力量,搭建项目基础架构,以技术栈的形式固化下来。开发团队要启动一个项目时,只需要从技术栈管理的PaaS平台上选择自己需要的技术栈,就可以立即生成自己的构建运行时,其中包括代码仓库、应用基础框架、依赖软件、自动化构建工具等。基于这个构建运行时,开发团队可以基于已经搭好的脚手架立即开始编写代码,并在PaaS云上进行基本的验证,然后提交到团队代码仓库。团队的技术领导者不需要考虑开发环境应该如何配置,开发人员也不需要在自己的电脑上做任何环境准备工作,从而极大地降低了项目启动的技术门槛。

    作为对开发工位的规范要求,技术栈中会规定“提交门”的质量标准,达不到质量标准的代码将无法提交到团队代码库中。这个实践与持续集成一样,都是源自丰田生产方式的“安灯”实践:如果出现质量隐患,应该立即停线修复,而不是让带着质量隐患的生产线继续运转。在一般的开发团队中,提交门的质量标准至少包括(1)代码能通过编译;(2)代码能通过静态质量检查。通过引入代码复杂度、代码规范性检查等基本质量标准,能促使开发团队关注代码质量,避免基本的技术债不断累积。水平较高的团队会在提交门中包含单元测试,单元测试不通过、或单元测试覆盖率达不到标准的代码将无法提交。

    如果需要引入外包团队来协助开发,外包团队可以直接从技术栈管理PaaS服务商获得自己的构建运行时,绝大部分的开发规范可以用提交门验证的形式来承载,从而将组织的质量要求固化到开发环境中,降低规范化管理外包团队的难度和成本。

    在开发工位实施技术栈管理后,随着开发规范化底座的建立和开发阶段质量要求的逐渐提升,开发团队将具备逐步缩短交付周期的能力。随着开发交付周期缩短,待测试、待发布的版本会累积起来,对后续的测试和运维工位形成压力。此时研发管理者应该密切留意测试工位的累积情况。如果测试团队抱怨转测版本太多、人手不足,都反映出工位之间产能失衡的问题。当这一问题出现时,就应该抓住契机,提升测试工位的标准化和自动化程度,使测试工位能跟上开发的交付周期。

    从测试切入,建立云测试平台

    在数字化、互联网化的IT大背景下,软件系统上线的周期不断缩短,两周一迭代已经成为众多团队的标准配置,一些创新型业务已经要求将上线周期缩短到一周、几天、甚至一天几次。不断缩短的上线周期,使很多IT组织在测试方面的问题暴露出来:

    • 测试自动化程度低,手工回归测试跟不上频繁上线的节奏。
    • 测试环境争用,环境管理工作量大。
    • 性能、安全等非功能性需求的测试投入不足,到项目晚期才开始测试。

    如果这些问题是一个组织当前最大的痛点,技术栈管理平台的实施也可以从测试工位开始入手,为整个组织打下坚实的质量保障基础。测试和开发的技术骨干可以一同选择适宜的自动化测试工具,将其连接配置好,准备好自动化测试的脚手架,打包到技术栈的验证运行时中。测试人员只需按照业务需求编写自动化测试例,并放在技术栈中规定的“验证门”环节自动执行。当系统最重要的功能都能被自动化测试覆盖,测试人员就能从繁重的手工回归测试中解脱。

    自动化测试需要可靠且可复制的测试环境来执行,这正是云计算的优势所在。在技术栈管理PaaS中定义了测试运行时环境后,每当测试人员或自动化的验证门要执行自动化测试例时,就会从云中取出一个测试运行时,其中除了被测系统的依赖软件外,还包含了配置好的各种测试工具。被测系统会被加载到测试运行时环境中,执行自动化测试例,收集测试报告,然后测试运行时环境就会被销毁回收。整个过程中不需要测试人员手工管理测试环境,也不需要与其他测试或开发人员共用一套环境。

    一旦测试人员不用“人肉回归”大部分软件功能,他们就可以把更多的精力投入非功能性测试。性能测试、安全性测试等非功能性测试所需的工具集同样可以被内建在技术栈中,方便测试人员日常工作。同时,测试人员还可以把非功能性测试编写成自动化的测试例,将其加入验证门的测试集,从而使非功能性需求也持续得到保障,以免在项目晚期才发现重大性能或安全问题。

    当云测试平台建立起来,有了基本的自动化测试覆盖,测试人员就可以起到质量监督和建议的作用,而不是跟在开发后面做简单重复的手工验证。由于软件产品必须在验证运行时上通过测试,研发管理者就可以借此拉动开发团队使用云测试平台进行自验证,在习惯养成后再逐步在开发过程中推广使用构建运行时,从而用一个技术栈拉通开发和测试的工作环境。

    从运维切入,构建高响应运维能力

    同样,数字化、互联网化的大背景也对运维团队提出了新的挑战。从业务客户的角度,他们不仅希望自己的需求能尽快上线被用户使用,而且还希望及时获得来自用户的反馈,帮助他们做出调整。在一些领先的企业,运维更是能支持业务客户针对真实用户进行快速的受控实验,从而验证自己的业务假设。在这些新的要求下,很多IT组织的运维团队暴露出了能力上的不足:

    • 运维自动化程度低,需要大量手工操作,工作量大,可靠性低,容易出错。
    • 系统监控不完备,出现故障时不能及时发现和快速排错。
    • 生产系统的信息不能快速转换成业务洞见,无法支持频繁的线上受控实验。

    技术栈管理平台的实施同样可以从运维工位入手,以打造高效的DevOps体系为优先目标。

    你说的是哪种DevOps?

    由于历史原因,如今大家在谈起“DevOps”这个词时,其中包含的可能是三重相关但不同的含义:

    1. 如何借助基础设施即服务、运维自动化等手段,加快代码部署到生产环境的速度。
    2. 如何借助日志和监控手段,及时把生产环境的情况反馈到开发团队。
    3. 如何借助端到端的埋点、数据采集、分析和可视化,把用户行为反馈到业务。

    以运维视角优先切入时,技术栈的建设就自然地偏向运维工具。在支持计算资源弹性分配的IaaS层(例如基于ScaleWorks的私有云)之上,将自动化配置管理工具(例如Chef、Puppet、Ansible)及其他常用的运维工具打包在应用运行时中,运维人员可以随时从技术栈管理的PaaS服务中获得完整且配置好的应用运行时,再从通过了测试验证(可能是手工验证)的发布候选版本中选择一个放入应用运行时,即可快速完成应用的部署上线。生产环境的配置以代码形式记录,可以由技术能力较强的DevOps团队专门维护,从而省去了大多数运维人员手动管理运行时环境的工作量与风险。

    在应用运行时环境中,可以根据软件系统的特征预先配置好日志工具(例如ELK、Splunk)和服务指标监控工具(例如Collectd),使开发团队无需额外工作就能获得丰富有用的生产环境信息。一些水平更高的团队会在应用运行时环境中设置更智能化的运维功能(例如基于Hystrix的服务熔断机制),使运维更具响应力。

    应用运行时环境中还可以植入端到端综合语义监控所需的工具设置,从而支持对业务场景埋点和分析,甚至是结合流量路由技术进行受控实验,用数据为业务决策提供支撑。业务有了缩短反馈周期的诉求,运维有了快速响应变化的能力,两端夹击可以倒逼研发环节提升响应力、缩短交付周期,这也是研发组织变革的一个套路。

    运维工位采用技术栈管理平台以后,研发管理者可以从交付物入手倒逼开发和测试环节,要求通过测试的发布候选版本以容器镜像的形式交付,以保证上线效率和可靠性;同时提供基于技术栈管理PaaS的构建和镜像版本管理基础设施,方便开发和测试团队构建符合要求的交付物。等开发和测试团队养成基于云和容器环境的交付方式,就可以逐步实施云测试平台和基于技术栈的开发底座。

    小结

    技术栈管理平台的目标是为现代IT组织创造云环境下的精益软件生产流水线。但对于很多组织而言,这条流水线并非一步到位,而是一个分阶段建设的过程。在这条流水线上,开发-测试-运维三个核心工位都可以成为实施技术栈管理的切入点。从组织当前最显著的痛点出发,选择一个工位开始实施云化的技术栈管理平台,并依循瓶颈理论拉动其他工位的逐步改进,这对于众多不以IT能力见长的组织而言,是一条可行的云化、数字化道路。


  8. 沃尔玛的数字化平台分析

    尽管2009年就已上线了电商平台Marketplace,但直到2011年,沃尔玛在数字化领域也不能算成功者。当时他们的电商网站只有相当基本的功能,用户体验不算方便,搜索不太好用,也不能与店面或供应链无缝对接。之前的几年,沃尔玛的电商收入跟其他零售商(例如西尔斯、梅西)一样缓慢线性增长。正因为如此,当沃尔玛的电商收入在2011年至2014年的三年间增长150%、从年销量49亿美元增长到122亿美元、超过史泰博(Staples)成为亚马逊和苹果之后美国第三大在线零售商时,这一变化才更令人好奇。

    数字化之旅

    沃尔玛的全球电商部门主要有三方面的责任与行动:

    1. 运营沃尔玛全球10个网站,在线提供超过700万种SKU,无缝连接门店与仓库,给顾客提供多种购物选择。
    2. 通过@WalmartLabs这个创新孵化器,不断更新网站和移动应用,利用顾客数据和社交网络洞察预测顾客行为,给顾客提供更好的在线和在店购物体验。
    3. 对内打造沃尔玛的电商能力,在全美国建设线上业务服务中心,建设新的电商操作系统Pangaea。

    为了达到这些目标,沃尔玛在几年中收购了多家IT企业,光是作为创新引擎的@WalmartLabs就收购了14支科技团队,为整个企业的数字化转型提供了能力上和文化上的支撑。2013年,沃尔玛收购了提供云计算解决方案的OneOps公司。该公司拥有成熟的PaaS和私有云IaaS能力,支持多种公有和私有云平台,包括Azure、Rackspace、AWS、OpenStack等,与沃尔玛的云化、服务化趋势相符。到2016年,沃尔玛全公司有超过3000名工程师基于OneOps平台开发和管理IT系统。

    在电商销量猛增的过程中,沃尔玛的IT系统遭遇了性能瓶颈,这也是他们开始将IT系统服务化的重要出发点。他们希望“系统拥有足够的弹性去处理峰值,同时不产生负面的用户体验”。事实证明,微服务架构带来的效果是明显的:

    • 销售提升:转化率在一夜之间提升了20%,移动端的订单立即增长了98%;
    • 可靠性提升:黑色星期五或节礼日等大型购物节期间,再没有出现过宕机;
    • 运维成本降低:将昂贵的硬件换成了便宜的X86服务器,节省了40%的计算资源,总成本下降了20-50%。

    沃尔玛还把自己的数字化能力提供给自己的供应商。2014年,他们上线了自己的广告平台Walmart Exchange(WMX),用自己门店和线上电商的数据帮助供应商更有效地投放广告(包括沃尔玛网站、第三方网站和邮件广告)。

    数字平台战略视角分析

    数字平台战略的角度分析,沃尔玛在构建自己的数字平台能力支柱方面已经取得了令人瞩目的成绩,这也是其电商销量能大幅提升的重要原因。

    交付基础设施

    • 通过将业务系统改造为大量、小规模、无状态的服务,使系统可以部署到廉价服务器的集群上。同时弹性基础设施也允许随需增减计算节点。
    • 没有应用服务器。所有服务以standalone的形式通过docker部署。
    • 全面的监控机制(使用ConductR),当服务失败时能自动响应,并提供排错所需的信息。在集群层面汇集日志,避免需要分别查看每个节点的日志。
    • Akka可以把一个交易建模为一个有穷状态机,可以在中途持久化状态,可以取回状态,提供了一种错误恢复的机制。
    • Akka的监控(supervisor)机制类似于Erlang:“let-it-crash”,不需要假设虚拟机或计算节点可靠。

    API和架构治理

    • 用Play实现API Gateway,以RESTful API的形式为其背后的系统提供统一的入口。
    • 原来的大块系统按照业务领域划分为小块,团队也随之划分,例如搜索团队、商品团队等等。每个bounded context有它自己的词汇表、拥有自己的数据。
    • 服务切分不仅仅是IT系统的事,而是组织、代码、数据库三个层面的重构。一开始不先直接做“硬”的切分,而是先从逻辑上做划分(例如数据库的schema命名规则、代码的包),然后检查是否有循环依赖;等依赖关系逐渐理清了,再分解成独立的服务、独立的数据库、甚至NoSQL数据库。
    • 解决性能问题的主要方式是通过异步操作(使用Akka):把数据库写操作异步化,从而减少对JVM线程的占用,并且使能并行处理,极大地提升系统的性能和可扩展性。

    数据自服务

    • 因为数据量太大,必须改变ETL、数据预处理的思路,对数据做真正意义上的实时处理(使用Akka Streams)。
    • 用Spark对数据进行单件流处理,数据处理的延迟由6小时(ETL过程)缩短到10秒。

    数据方面的架构如图:

    创新实验基础设施

    • 组织层面上,@WalmartLabs是一个创新的孵化器机制。
    • 技术层面上,OneOps提供了路由技术和监控能力,使在线的快速实验成为可能。
    • WMX能统一收集和利用各种渠道(门店和电商)的用户数据。

    客户触点技术

    • @WalmartLabs对整个组织输出全渠道、移动、响应式设计等能力。
    • 沃尔玛的电商平台支持多种客户触点(电脑、移动)。Walmart.com在美国的流量超过一半来自移动设备,Walmart Pay应用部署到4600多家门店。
    • 使用大数据(购买行为、搜索历史等)个性化顾客的交互体验。个性化搜索引擎Polaris提升了20%在线销售转化率。
    • WMX支持单一顾客视图,形成对顾客的全面理解。

    参考材料


  9. 技术栈管理:云时代的研发环境

    前文介绍了云计算大背景对研发环境的影响。我们已经指出,现代IT组织应该把研发技术栈以PaaS的形式提供给开发人员,其中的要点是:

    • 将标准的研发环境封装为虚拟化、云化的技术栈,由技术专家管理维护;
    • 核心业务价值与技术支撑解耦,工程师专注于业务系统的开发;
    • 自动化研发流程,降低研发管理成本。

    如何实现这样一个研发技术栈管理的平台?我们的观点是,这样一个平台应该集中管理组织中的技术栈,允许基于一个技术栈创建开发测试PaaS和生产PaaS两个PaaS服务,从而支撑开发、测试、生产三种运行时环境

    一个平台

    在一个典型的敏捷软件开发场景(例如更具体的“用Java开发微服务”的场景)中,开发者需要频繁地用到下列工具:

    • 编程框架,提供基础的结构与功能来支撑业务逻辑代码,例如Spring Boot和Jersey。
    • 版本控制工具,例如git。
    • 依赖软件,例如PostgreSQL数据库。
    • 自动测试工具,包括单元测试工具(TestNG)和功能测试工具(Concordion、Selenium)。
    • 自动构建工具,Maven或Gradle。
    • 持续集成工具,Jenkins或GoCD。

    所有这些工具以及它们适当的组合与配置,我们把它称为一个技术栈。我们上面的例子就是“Java微服务开发技术栈”,类似的,一个组织中还可以有“Java Web应用开发技术栈”、“H5前端开发技术栈”、“ReactNative移动应用开发技术栈”等等若干个技术栈。对于一般的IT组织而言,有限的几种技术栈就可以覆盖大部分软件项目的形态。体量大如有数万研发员工的某IT巨头,提出的主要技术栈也只有十余种。

    在传统的软件开发团队中,技术栈的组合与配置是由团队的技术领导者负责的。在云计算的大背景下,将基础设施作为源代码的思想再往前推一步,我们就会很自然地得出技术栈作为源代码的想法:使用Docker和Ansible等技术,将技术栈的结构以源代码的形式描述。在“基础设施作为源代码”的阶段我们已经知道,以源代码形式管理环境会带来很多好处,例如更高的自动化程度、允许版本控制等。把技术栈作为源代码以后,会带来几个重要的收益:

    1. 技术栈可以很容易地复用,因此可以把搭建技术栈的工作收拢到较少数技术领导者手中,研发团队则只需在技术栈基础上开发业务功能,降低了研发团队的技能门槛。
    2. 最佳实践可以被内嵌到技术栈中,并通过持续集成的形式对研发团队形成约束,从而使研发改进举措更容易推行。
    3. 缩短研发实践的实验和创新周期,可以对多个研发团队开展受控对比实验,团队中自发产生的优秀实践可以被快速抽取并固化到技术栈中。

    技术栈管理平台作为组织级的研发管理载体,承载的是组织对研发团队的引领和治理形式。在这个平台上,技术领导者会创建并维护技术栈,项目团队则可以根据自己的需要选择适合的技术栈,跳过大部分迭代0的技术准备工作,直接进入功能开发,并在整个产品生命周期中享受云化开发环境带来的收益。

    两个PaaS

    基于已经定义好的技术栈,当项目团队开始研发工作时,技术栈管理平台可以为他们创建两个PaaS服务:一个是研发过程中使用的开发测试PaaS,另一个是真实上线用的生产PaaS。两个PaaS的协作关系如下:

    • 开发人员从开发测试PaaS中获得一个开发环境,在这个环境中编写代码;
    • 新编写的代码被提交到代码库中,后台的服务自动运行“提交门”测试,测试通过后,把代码构建成可运行应用;
    • 后台服务针对可运行应用自动运行“验证门”测试,测试通过后,这个版本的可运行应用即被标记为可发布应用,并被存入构建产物仓库;
    • 测试人员针对通过了“验证门”测试的可发布应用进行必要的手工验证;
    • 生产环境与开发/测试环境基于同一个技术栈(运行时环境上有具体的差别),开发测试PaaS中构建出的可运行应用可以直接部署到生产环境;
    • 随不同组织的发布流程不同,构建产物仓库中的可发布应用可能直接(自动或手动)发布到生产环境,也可能被同步到生产PaaS的产品仓库,以后再手动发布到生产环境。

    可以注意到,这个流程、尤其是在开发测试PaaS中发生的流程,与Dave Farley在《一键发布》文中介绍的持续集成流水线非常相似。我们相信:持续集成对于现代软件开发是如此重要,以至于它不应该以独立的工具形式存在(因为这样人们就有可能不用或者误用)。持续集成应该被内建在软件开发的工具和过程中,使它不被开发者注意、同时又不能被绕开——正如Spring内建了面向接口编程、IntelliJ IDEA内建了编译和代码格式检查。

    三个运行时环境

    前面介绍的流水线已经暗示,在整个软件交付周期中,存在三个不同的运行时环境。这三个运行时环境都有同样的基础,例如操作系统、依赖软件等。同时它们也有一些重要的差异:

    1. 构建运行时:包含开发工具、构建工具和(可能是部分)测试工具,这是开发人员编写代码的主要环境——需要注意,“编写代码”在敏捷软件开发的上下文中意味着“编写代码并频繁进行提交门测试”,这是为什么这个运行时环境中必须包含(至少部分)测试工具。
    2. 验证运行时:包含全部测试工具及其他质量保障工具,这是对软件质量进行全面验证的主要环境。
    3. 应用运行时:包含运维工具,这是软件真正运行的环境。这个运行时可能被应用于生产环境,也可能仅用在组织内部(例如UAT测试环境、培训环境、demo环境等)。这个运行时中的依赖软件(尤其是数据库)也有可能被替换为环境之外独立运行的软件。

    尽管为了支持不同环节的工作要求而有这些差异的存在,底线是:构建运行时构建出来的可运行应用,可以在验证运行时中接受完整的验证,也可以被部署到应用运行时正常运行。这与持续交付中“制成件流过整个流水线”(而非在各个构建步骤中分别生成制成件)的理念是一致的。

    制成件的形式

    前文中我们已经提到:软件包是一种对云环境不友好的交付形式,理想的研发交付物应该是容器镜像(很可能是一组彼此连接的容器镜像),可以在云上直接运行。Docker等容器技术使我们可以把所有软件(不论背后使用什么编程语言、实现什么功能)都抽象为“IP地址+端口”的服务;再加上例如Docker Swarm或Kubernetes之类集群工具的支持,更可以把服务进一步简化为一个端口。于是,技术栈管理的基础设施可以得到更大程度的复用:不同的技术栈(不管编程平台是Java、NodeJS还是Python)构建出的应用都是一个(或一组)Docker镜像,从而将“产物的形态”与“生产流程的结构”解耦。

    小结

    针对前文提出的云计算大背景下对软件研发提出的挑战,本文提议了一种解决方案:技术栈管理平台。通过实施技术栈管理平台,为研发团队提供开发测试PaaS和生产PaaS两个PaaS服务、构建/验证/应用三个运行时环境,研发组织能够将技术栈的搭建和管理与业务系统的研发解耦,从而降低研发团队技能门槛、快速有效地推广研发最佳实践、使研发过程中的技术与流程实验和创新成为可能。


  10. 云时代的研发环境长什么样?

    云计算正在毫无疑问地成为企业IT的主流。据麦肯锡调查,六成以上的企业计划在两年内将某种形式的云作为主要IT平台。在国内银行业,中国银行业信息科技“十三五”发展规划监管指导意见中明确提出:到2020年,国内银行业面向互联网场景的重要信息系统应全部迁移至云计算架构平台,其他系统迁移比例不低于60%。其他行业也有同样的趋势。信息系统云化的大背景给软件系统的研发流程带来了什么挑战,作为软件研发组织的领导者应该如何应对这些挑战?这是本文试图回答的问题。

    首先,有必要回顾云计算给企业IT带来的收益。IBM认为云计算有三大优势:

    1. 更灵活。用户可以根据需要,“弹性地”获得IT服务。
    2. 更高效。减少IT团队管理和维护底层基础设施的工作量,IT服务可以更快推向市场。
    3. 战略价值。通过灵活组合现有IT资产与新兴数字渠道,支撑企业业务创新。

    云计算与虚拟化的区别

    有很多企业已经采用了虚拟化技术:将企业的计算资源(服务器、存储等)集中管理,以虚拟机的形式分配给使用者。虚拟化与云计算的区别在于:虚拟化是指“用软件管理硬件资源”,而云计算是指以虚拟化方式管理硬件资源之后能够对外提供的服务。

    除去这个概念上的差异,我们注意到一些企业在谈论“虚拟化”的时候,背后隐含着一个自动化程度不高的、需要人工参与的虚拟机申请和开通的流程。在这样的流程下,获得一台虚拟主机需要的时间通常以天计。因此,虚拟机的使用者倾向于预先申请虚拟主机并长期占用。在这种情况下,“虚拟化”往往意味着缺乏弹性(elasticity)的计算资源分配——尽管虚拟化技术本身并不妨碍弹性。

    可以看出,为了兑现云计算的三大优势,企业IT系统必须云化:软件的形态由从前需要在本地安装的软件包,转变为透过网络在线使用的服务,让使用者随时能够获得;原来体型巨大的单体(monolithic)应用,需要转变为细粒度的服务,从而支持灵活的组合与复用。

    原来习惯了开发本地安装的软件包和/或巨大的单体应用的研发团队,现在要转为开发云化的软件服务,这个转变并非总是无痛的。首先,研发交付物的形态应该是对云环境友好的。从前研发交付物通常是以软件包的形式提供给用户或是运维团队,例如平台特定的JAR、WAR、EGG等软件包,或是RPM、DEB、MSI等操作系统特定的软件包。软件包是一种对云环境不友好的交付形式,因为它没有包含软件运行的环境。例如一个软件需要用到PostgreSQL数据库和monit作为监控工具,平台特定的软件包无法确保这些软件依赖的存在;某些操作系统特定的软件包可以描述软件依赖,但也无法确保依赖软件被正确地配置。过去一段时间里,自动化的配置工具(例如Chef/Puppet/Ansible)被用于解决运行时环境的问题。而在今天的技术背景下,理想的研发交付物应该是容器镜像(很可能是一组彼此连接的容器镜像),可以在云上直接运行。

    对研发交付物的要求随即会影响到研发过程。为了在研发流程的出口得到服务化友好的交付物,最好是在整个开发过程中一直使用与生产环境近似的环境。例如开发人员应该使用全套环境随时验证,自动化测试和手工测试都基于全套环境开展。在这种情况下,环境的设置、管理、更新不可能由每个开发人员和测试人员自己进行,所以环境的管理更新必定是集中进行的,环境的设置必定是自动化的。而且,如果环境固定分配、长期使用,对计算资源的占用可能很大,所以环境应该是云化的、弹性的、按需获得的。

    云计算的大背景还会影响研发实践。为了降低搭建研发环境的技术难度,云化的研发环境应该内建研发工具链(包含开发工具、质量保障工具、持续集成/持续交付工具、DevOps工具、项目管理工具等)。为了规范团队研发质量水平,良好的研发实践(例如代码静态检查、自动化测试等)和流程要求应该固化在工具的日常操作中。理想的情况下,研发团队应该只聚焦关注业务功能开发。开发工具的组合、生产环境的配置、持续集成和持续交付流水线的搭建等工作都应该被标准化和自动化。

    综上所述,在云计算的大背景下,IT组织需要将更多的软件应用部署在云上。云化的IT系统对软件研发的交付物、研发过程、研发实践都提出了新的要求。我们认为:现代IT组织应该从研发环节开始,以原生支持云计算的方式提供、管理和维护研发环境,从而在研发过程中利用云环境的弹性,确保研发交付物对云环境友好,并把优秀的研发实践和流程要求内嵌到研发环境之中。IT组织可以通过以下方式管理其研发环境:

    • 将标准的研发环境封装为虚拟化、云化的技术栈,由技术专家管理维护;
    • 核心业务价值与技术支撑解耦,工程师专注于业务系统的开发;
    • 自动化研发流程,降低研发管理成本。

    在下一篇文章里,我将介绍如何具体实现技术栈的云化管理,把研发技术栈以PaaS的形式提供给开发人员。