为什么要快速部署?
无论系统架构是多么的漂亮,代码是多么的优雅,测试套件是多么可靠,但唯有真正地将代码部署到生产环境中,我们的工作才能对客户产生实质影响。代码在部署之前,只是一些与面试问答毫无二致的智力活动。部署才能将这些知识产权转变为经济活动。毫无疑问,代码应尽快得到部署。
然而,工程团队却在为此苦苦挣扎。大量有据可查的事实表明,绝大多数的宕机事故都是由部署新更改造成的。道理的确如此,如果什么都不改变,那么发生事故的可能性也就大大降低。因此,部署代码明显是存在风险的。
绝大多数当下流行的工程实践,目的都是在提高软件部署速度的同时,降低因部署加速而引发的故障风险。这些实践大多在小型企业畅通无阻,但是当软件或团队规模随着企业发展壮大而持续增长时,具体场景的重要性就愈发显现。从开发回溯到设计和实现的逆向工程,会暴露出大量的低效之处。
软件的高质量快速部署是现实的目标,基于这一认可,本文将针对软件交付过程提出流程化的观点,识别并疏通瓶颈,提高流程效率。约束理论(Theory of Constraints,TOC)在其中的应用,意味着可对软件的交付流程做逆向建模,进而识别瓶颈,并逐一做优化。
部署会导致服务宕机
正如前文提到的,在生产环境中部署变更的最大问题是会导致宕机,行业应用数据也充分说明了这一观点。由此,大家心照不宣地将部署视为某种神圣活动。但在问题的表面之下,存在大量值得深挖的潜台词。
尽管这一庞大话题本身就涵盖方方面面,但如果最终目标是快速而安全的部署,那么下面列出有效手段是不可或缺的:
部署需要一定的时间
在深入问题细枝末节之前,需要指出的是由于功能切换(feature toggle)的存在,部署并不等同于特性发布。某个功能的实现代码可能已经得到部署,但因为有功能切换,它无需立刻生效。下面深入探讨功能切换的概念。
我曾经共事过的一些团队是反对做频繁部署的,因为部署会占用团队大量的时间。下面列出部署中通常涉及的各个步骤,并给出高效的实现方式。
测试需要一定的时间
我在供职于 Myntra 供应链团队时曾身体力行了端到端的测试。任一功能只有能够完整地通过从客户购物车到物流的一整套不同类型的订单时,才算通过质量检查。测试环境常常被未通过测试的代码破坏,结果让整个过程对开发人员来说过于漫长,对测试人员则过于痛苦。疏通测试中的瓶颈,通常需要从两个方面着手:
要疏通测试中的瓶颈,需区分上述两种路线,让不同的团队负责不同路线。
功能的整体部署
功能开发通常以批处理方式进行。开发人员设计完整的功能,然后一次实现整个设计。在某种程度上,完整功能是开发人员的工作单元。这对于规模不大的功能尚且适用,一旦处理涉及应用中多个部分和层次的大型功能,就需要多名开发人员协同工作,而这一工作方式会带来巨大的风险。如果在部署前就汇总所有的变更,那么将会导致大量的冲突,而且很难预测是否所有的功能依然正常工作。
至此,本文尚未探讨敏捷过程中的 Sprint Story 问题,这是一个更底层的问题。如果代码变更本身就是独立的(例如在数据库中创建新表导致的模式变更、尚未通过 API 公开提供的核心业务逻辑),那么导致其无法部署的原因在哪里?阻止变更部署,会导致如下两方面问题:
但是,实现细粒度功能需具备一些先决条件。
完成上述改进后,部署流程就转化为一些非常小的、经验证是安全的变更,并且其中大部分是已经自动化的,需要最少的人工干预。但是,如果我们坚持分批推送大变更,很难找到可以快速、安全地实施部署的自动化方法或工具。较大的变更集会导致不好的测试和审查,进而导致系统不稳定。
视软件交付为变更流
我的一次思想上的转变,就是将软件交付视为一系列针对实现功能的小变更,而不是将交付看成是将功能从开发人员笔记本转到生产服务器。并不存在所谓“已完工”的功能,所有功能都是不断地发展和变更的。因此,功能不应视为我们交付的一组静态绑定产品,而应视为一组需要在系统某处边界上进行的变更。正如一些观点提出的说法,功能是软件组织中的工作“流”。要实现这一目标,一种做法是在开发过程中采用敏捷技术,另一种做法是在部署和运营阶段基于现成的基础架构功能进行开发。
太长,不读(TL,DR)
尽可能频繁地部署。无论当前的部署成本如何,成本只会越拖越大。除非所要构建软件是生死攸关的,或是受到严格监管的,否则我认为应该尽快做部署。根据破窗理论,以快速部署为工程目标,会直接导致形成强大的工程文化和实践。从长远来看,这对机构也是十分有益的。
原文链接: