• QAD1 持续交付 Continuous Delivery


    每小步验证

    很久以前,工程本科生都要在最后一年做个毕业项目。导师建议尝试参考一些常用的语言发声算法,在专门做信号处理的芯片上写程序,读出一些英文字或句子(与现在不同,当时这技术还未成熟,很多大学还在研究),虽然预计有不少技术难度,但觉得很先进,很感兴趣,便与另一位同学合作,开始制定项目计划。

    我们很努力,全情投入,一方面要研究语言发声的算法,也要并行设计电子线路和软件等。用了2、3个月做好整个电子线路板硬件,然后也设计整个软件架构,并使用计算机模拟,看每个字实现算法后的发声效果,但最后一年课程很多,时间过得很快,从9月开始准备一直到次年3月,软硬件终于都完成,但是不知道什么原因就是没有声音,更不要说能发出一些字和句子了,最后项目以失败告终。

    在之前一年,我很幸运,在大学第三年去大东电报局实习(当时香港的所有国际通讯都是经过大东),实习那部门正如火如荼开发一套新电脑系统取代本来基于UNIVAC的电报系统,总工程师让我用半年时间,在一个微机编程,做一个系统可以从那些电脑收集重要信息,发现异常就警报。头三个月都是花精力做整个系统设计,也买了一些展示电子版,准备用来展示,但经验不足,半年时间后最终什么都展示不出来。

    到了2000年,兼读软件工程硕士课程时,我开始接触敏捷开发,了解两次项目失败的主因:不应该花大量时间去做前期设计,希望做一个完美的设计,而是应该一步一步,先做一些最基本简单功能,逐步优化。例如,在毕业项目,应先做出最基础的简单硬件、软件,先起码发出声音,因为所有功能都没有前人做过,整个项目都是一些从未做过的实验。

    敏捷大师Dave Thomas 先生在2015 演讲里提出敏捷软件开发的核心是:

    1. 向你的目标迈出一小步

    2. 从反馈调整你的理解

    3. 重复

    • 当两种或以上选择的价值大致相同时,选一条让未来更容易修改(软件)的路径

    Agile Software Development:

    1. Take a small step towards your goal

    2. Adjust your understanding based on what you learned

    3. Repeat

    • When faced with two or more alternatives that deliver roughly the same value,take the path that makes future change easier

    (Source: Mr Dave THOMAS, 2015 goto)

    为了避免最后发生严重问题,应每一步都验证,从反馈立马修正。

    这原则不仅仅适用于软件开发, 例如在评估最后一天小组都需要利用有宏(macro)的xlsm 表 记录弱项并且评分, 各页之间有很多依赖关系。例如,xlsm 表会自动从每个过程页 汇总成总的报告页。

    所以我会小组提醒小组每一步都要保存并验证:第一步,按美国随机抽样,勾选过程选择后,先保存一个版本 让我先查看出来的每个过程页是否正确。然后对两个最复杂过程打分,也保存一个版本让我查看。

    先前的经验教训:因没有每步确认, 最后标注两个最复杂的过程时发现严重错误, 尝试修正,但不成功。最终没办法只有从零开始重新做。

    学生时期项目的失败可以谅解,但还有不少软件开发团队出现同类问题,比如有些中型项目,时长6-8个月,发布前最后1-2个月才集成/系统测试,导致一大堆问题到最后才暴露,很多缺陷都难以解决,导致无法按时交付。

    软件设计编码有误,只是引起部署交付失败的其中一类原因。下面是一些其他常见失败例子:

    1) 手工部署 (Deploy Software Manually)

    要准备一个很详细的文档,描述每步部署如何做,哪一步容易出错,也依赖人工测试来确保程序可以跑通,实施人员遇到问题解决不了,只能去问开发人员,导致发布时间延迟,因为现在的应用软件都比较复杂,包含很多中间件,很多配置,任何一步都可能出错。如果人工部署,发布耗费的时间会较长,整个发布部署风险也会比较大,很可能会导致我刚才说的场景。(反过来如整个部署都是自动的话,就能减少了这类问题。)

    2) 开发完成后,才开始部署生产环境(like Production Environment)

    测试人员一直到最后阶段还是在开发机器上测试软件,因为测试都是在内部机器做,做验收的客户代表,都没见过软件真正操作情况,他们第一次见到软件是在发布阶段,因一直都没人来搭建生产环境,或者觉得成本太昂贵,所以放到最后。

    然后开发团队把所有的安装、文档配置、数据库迁移、部署文件等,交给安装工程师,但是一切都未在真正的投产环境测试过。开发团队和部署的工程师也没有沟通。

    (好的做法就是把测试、部署、发布涵盖在整个开发过程中,不要等到最后,避免这类问题。)

    3) 手工配置管理生产环境(Manual Configuration Management of Production Environments)

    人手更改生产应用服务器的配置参数,并手工把更新记录在变更管理系统中。

    这可能导致一直在测试的环境都没问题,但到生产就失败;也会发现在不同的部署环境,表现出来的性能不同,人工配置管理操作,要准备整个部署也很耗时。

    因配置管理没做好,如果某个发布测试失败,无法倒退到前一个成功的状况;也难以看到不同操作系统的不同版本,包括一些程序包,一些补丁,一些软硬件的配置对不上。

    当整个从测试到投产环境的配置是手工管理,会有很多未知之数。(如果使用自动配置管理系统来管,就可以避免刚才的问题。)

    ---===---

    所以若要成功发布,出来代码,部署过程、环境、与配置都须要注意。早在90年代,XP(极限编程)的创始人Kent BECK先生带领瑞士某保险公司的团队做软件开发,他们当时已经可以做到每晚发布。现代,越来越多软件团队已经按这思路,尽量缩短交付时间(cycle time),尽快得到反馈。已经有不少团队可以做到一到两周发布。DevOps 要求这个频率更快,持续交付(Continuous Delivery)要求每天都可以到一个测试好可交付状态。要缩短循环时间,需要多方面的配合,比如要做到持续集成、自动版本/配置管理等。

    持续集成是要做到每天可交付的基础 - 每次代码变更都要做好集成,不要等到集成/系统测试时才出问题。

    因为软件从完成编码到可以在客户投产环境成功部署,中间很多地方可能出问题, 编码后必须经过构建(build),单元测试(unit test),集成/系统测试,最终在接近现场客户环境完成验收测试,才有信心能成功部署, 这过程叫部署流程(deployment pipeline)。

    从代码提交构建,到最终最终交付并在生产环境使用,把整个流程分成很多小步,每一步必须验证通过才做下一步。要做到持续交付(continuous delivery), 上面那些部署流程的步骤就不能再依赖手动,必须自动化, 一个命令,让自动集成系统(e.g. Jenkins) 自动跑命令脚本(script)执行。版本 / 配置管理也非常重要, 不仅包括代码,也包括例如数据库(DB schema),脚本(script),环境配置(configuration)等 因这些都会可能有变动, 如果出现问题,配置管理可以帮我们立马回滚到之前某个稳定的状态。

    软件系统会分成多个子系统/模块,分到几位开发人员并行开发,各模块单必须整合,并通过集成/系统测试,所以持续集成是持续交付的基础。

    不要以为每个开发人员每天提交(commit)代码到版本管理系统就算做到持续集成, 也需要:

    • 每次提交代码要确保已经测试过,没有问题

    • 所有部署发布后的问题都能在10分钟之内解决

    不然还未算达到持续集成的基本条件。所以每天提交只是持续集成的第一步。

    你可能会觉得持续交付太理想,难以达到。实际上有些面对全球客户的互联网公司(e.g. Amazon)已经做到每天部署, 但不要误会持续交付很容易做到,这些成功案例都已经经过多年的不断过程改进,并配合自动化工具,才能做到持续部署(continuous deployment)。

    追求持续交付的努力,可以带来以下好处:

    1. 更快速收到客户反馈(因客户可真正使用新功能),不要等到最后才知道功能并非客户所需要

    2. 不仅仅依赖开发人员自己测试通过,开发人员也可以每天收到反馈,不需要等几个月才发现问题,开发团队与其他干系人更有信心软件没有问题

    3. 步伐越小,后面改错的痛苦就越低。也因为每次部署的功能变动不大,可避免几周后一次性先系统测试,然后部署时才发现大量复杂问题的风险 (问题发现得越晚,越需要花更多时间解决)例如,某家专门服务电信供应商管理各种媒体(如:电影、视频、游戏)播放的软件公司,帮助。他们每次发布(他们叫割接上线)系统新功能都是在半夜。如果在发布前没能通过验收测试,就都要切回本来版本,不能发布。然后他们会回顾失败,为什么常常出现这种问题。持续交付能减少或避免割接问题。

    4. 更好监控项目进展。例如,某家专门做IT项目的公司发现项目开发的延误很严重,导致项目的利润越来越薄。他们希望能有办法管理好软件开发的成本,保持公司利润。持续交付便可更好监控项目时间进展。

    References

    Humble, Jez: Continuous Delivery
    Shore, James: "Continuous integration on a dollar a day" (www.jamesshore.com)

    附件

    A1: 持续集成(Continuous Integration CI)

    基础条件:

    • 要有版本管理

    • 要配合自动化工具,e.g. Jenkins

    • 每当我听到团队还是手工构建,我很奇怪为何不把它自动化,如果我们要持续集成,每天都要构建,包括自动测试

    • 要有团队的赞同

    • 持续集成不仅仅是工具,需要整个团队高度付出参与与纪律,每个人频繁每个小步小步交付他的开发部分。James SHORE 先生在 "Continuous integration on a dollar a day"文章里提出不一定依赖自动集成工具(e.g. CruiseControl 另一种类似 Jenkins的集成工具 ) 只要团队各人都做好自动单元测试,每次提交代码都使用版本管理系统合并, 也能做到持续集成。

    如何开始

    有很多开源的软件可以下载来用,选好你要用的持续集成(CI)软件后,你就开始要安装使用,希望在利用工具来做自动构建,跟安装其他软件一样,开始的时候会遇到困难,你可以在你项目的wiki记录下来,让其他人知道,避免以后重复错误。接下来,大家可以开始用服务器持续集成:

    1. 当你准备好提交(check in)你的最近更改,要确保它是否能正常运行

    2. 它可以正常运行并通过测试,你应该把你的代码从你的开发环境提交到你的版本管理(Version control repository)系统去,也看有没有更新

    3. 跑构建脚本和测试,确保所有都可以在你的电脑正常操作

    4. 如果你在本地构建成功通过,就可以把你的代码提交到版本管理系统

    5. 让持续集成工具自动构建你提交的更新

    6. 如果不通过,你要尽快在自己的机器上修改问题,返回第三步

    7. 如果构建成功,你就可以进入下一步:完成

    如果各成员都按照以上简单步骤,团队便有信心软件在任何电脑,同样配置,能成功运作,一些持续集成的注意点:

    1. 定时不断提交(Check in regularly),可以想象你写了很多代码才发现问题,后面你会花更大精力来找出问题

    2. 创建全自动化测试套件(Create an Automated Test Suite),很多资深的编码人员觉得自己写好代码就可以,不一定做单元测试,单元测试其实是复用率最高的,你可以想象你是持续集成的话,每次都可以靠测试来确保代码正确,如果没有单元测试就无法知道你的代码假如是有更改后,是否有错误 (注1)

    3. 保持较短的构建和测试过程(Keep the Build and Test process short),如果可以把测试和构建简短的话,就不会等到一大堆问题才要解决,就像我们把复杂的系统分成几个子系统,模块逐个开发的道理一样

    4. 管好自己的开发工作区(Manage your development workspace),不要只做好代码的版本管理,配置管理应包括你的测试数据,数据库脚本,构建脚本,安装脚本等,因为每一块都会导致你的软件运作不成功。

    (注1: 如想多理解为什么单元测试很重要,可读我19年的 “TDD 测试驱动开发与精益”文章)

     

  • 相关阅读:
    去重的方法
    【算法】平衡二叉树
    Spring解析之finishBeanFactoryInitialization即初始化单例bean
    Transformer/Bert
    让泛型的思维扎根在脑海——深刻理解泛型
    【前沿学习】美国零信任架构发展现状与趋势研究
    ABAP Web Service 调用的一个例子
    动物园
    第一讲:单链表快速排序
    Java集合面试
  • 原文地址:https://blog.csdn.net/u011250455/article/details/126785290