这样的浪费有很多原因,但不乏是由于传统行业对于软件开发、部署、发布、迭代以及运维的了解有限,因而本文面向传统企业转型中的困难和疑问,通过推进组织的DevOps转型作为抓手来尝试提供一份数字化转型指南,以资参考。
数字化转型是使用云计算、大数据,以及其他信息技术对企业的运营、组织架构和商业模式进行改造的过程,以提高企业相应客户需求的速度,增强企业与客户的联系。数字化转型不仅仅是技术转型,更需要从商业战略、组织架构、文化、客户关系等多维角度来确定企业的转型策略和目标。
这些维度和开发运营一体化(DevOps)变革和敏捷运动有众多重叠的领域。因而,我们可以使用DevOps作为抓手,在确定商业目标的同时,减少数字化转型中的成本,通过DevOps的成熟度指标,来关联和量化数字化转型的成果。 缺乏量化性的指标,就无法管理数字化转型的过程,也是造成大量投资浪费的原因之一。
开发运营一体化(DevOps)是对于企业内部开发和运营的整合的方法论、工具和指标。 衡量一个组织的DevOps成熟度,需要从技术、流程、度量和文化四个维度来进行评价。根据当前主流业界的标准,DORA(DevOps Research and Assessment) DevOps成熟度模型、软件交付表现SDP(Software Delivery Performance)包含了下面这些指标,包括前置时间(Lead Time)、变更失败(Change Fail)、可靠性(Availability),以及部署频率(Deployment Frequency)和恢复时间(Time to Restore)。
微软公司,作为操作系统和办公软件的业界翘楚,也同样面临着数字化转型的压力。但是不同于其他企业,微软有深厚的工程师文化,强大的IT技术储备。他们面临的问题是如何将基于授权(license)的商业模式转型为以订阅(subscribe)为基础的订阅服务上。例如传统的单机密钥授权转换为云化的office 365订阅服务。
在这期间,微软着重推行了敏捷开发模式并且是office业务上云,同时将其传统的基于私有数据中心的Team Foundation Server改造成为基于微软云业务的Microsoft Azure DevOps。这成为了微软内部的运营开发一体化的转型抓手和重要推动引擎。
依据DORA(DevOps Research and Accessment)超过六年对业界技术能力(Technical)、流程(Process)、度量(Measurement)和文化(Cultrue)四个维度的连续研究和评估,我们同样可以从这四方面进行建设。
版本控制跟自动化紧密相关。事实上,建设持续集成和持续交付能力的建立在成熟的版本控制流程和工具的基础之上。很多企业在建立版本控制的时候,更多关注的是代码,而忽略了代码之外的配套流程和制品,例如测试用例、自动化测试脚本、测试数据、基础设施和数据库。我们在建立版本控制的时候,需要实现 基础设施即代码、配置即代码、数据即代码,以及测试即代码。版本控制可以帮助企业满足以下两个最关键的需求,即:
1)可复制性(Reproducibility)
可复制性是保障我们的开发、测试,以及生产环境的可复制性。能够快速通过自动化的手段实现环境的复制和重建,进而保证环境的一致性。
2)可追踪性(Traceability)
可追踪性的目的是为了保证团队可以在任何时间都可以利用版本重建环境,并且可以比较两套环境的区别。
业界有两种常见的软件开发模式,即功能分支模式(Feature Branch Based Development)和主干开发模式(Trunk-based Developoment)。
1)功能分支模式
功能分支模式是指开发人员从主干分支(Master分支)拉取代码来开始开发,直到开发人员认为代码开发结束,即从不可部署阶段到可部署阶段。如上图所示,即从浅灰色变为深灰色,才将代码重新合并到主分支。
这种模式有两个主要问题。第一,每一次发布都伴随着大量的代码合并,并且会引起代码冲突。原因是每次分支合并的代码量过大;第二,需要手工维护代码的合并,因为代码不仅仅是合并到主干,还需要人工判断是否需要合并到其他功能分支上。一般的逻辑是如果另一个功能分支的发布时间晚于当前要合并的分支,并且后面的发布需要当前分支的功能或问题修复,即需要合并,即所谓的向后合并。向后合并可以采用自动化合并的模式来实现,例如可以依赖于Jenkins来实现自动向后合并。由于每次合并代码都需要完整的测试,所以需要代码锁定(Code Freeze),以确保代码的稳定性。
2)主干开发模式
不同于功能分支模式,主干开发模式是实现持续集成的必要条件。开发人员只有在代码准备发布的时候,才会拉出发布分支, 所以发布分支一直是可部署的状态。而在功能分支模式下,功能分支不一定是可部署状态。开发人员每天都会把当下代码签入主干,但是要求开发人员如果自己签入的新代码引起了任何问题,必须立即修复,否则会阻塞其他开发人员签入代码。因为每次签入的代码量比较少,所以出现代码冲突的可能性就会大幅度降低。同时,主干代码因为继承了回归测试的自动化,任何破坏回归功能的代码都会被立刻修复,也维护了代码质量。主干开发模式不需要锁定代码或者其他手段来保证代码稳定性。
实现主干开发模式的要点:
分支数目控制在3个或以下;
至少每天一次代码合并;
不要采用代码锁定(Code Freeze)和集成阶段;
确保在代码合并之前进行代码复查(Code Review)和代码扫描(Code Scanning), 推荐使用PR(Pull Request)代码扫描。
开发人员经常误认为开发运营一体化(DevOps)就是讨论开发和运维,即Development和Operation,其实这是一个望文生义的一种误解。在推进DevOps转型中,很多企业和团队经常忽略了自动化测试这一个关键的因素。没有完善的测试驱动开发流程, 没有完善的回归测试自动化,持续集成就是空谈。
上图是测试驱动开发TDD的流程示意。新的功能在拿到需求之后,测试人员和开发人员都需要被通知。所有的开发都是基于对测试用例的实现。首先增加新的测试用例,并且运行自动化测试。此时,由于代码还没有开发,测试一定会失败。这么做的原因是让开发和测试人员明确在代码开发之前新增加的测试用例是失败的,从而避免测试用例的错误而造成测试用例错误通过的问题。开发人员根据测试来进行功能开发,直到所有测试用例通过。当测试用例通过之后,开发人员进行代码的重构来进行代码优化,以实现安全性和性能的要求。在签入代码到主干的时候,如果发现自动化回归测试失败,测试人员需要更新自动化回归测试确保回归测试是最新状态。
实现TDD的要点:
代码签入都会触发自动化构建;
代码签入会触发一系列自动化测试;
确保每天的构建和自动化测试必须是成功状态;
如果出现构建和测试失败,开发人员必须立即修复。
自动化测试给开发人员提供了一种快速反馈的机制。自动化测试是保证持续集成的基础条件。自动化测试包括下面两种测试种类:
1)单元测试(Unit Test)
单元测试是TDD流程中经常使用的针对单个函数、类或者方法,来保证开发人员的代码按照预期的测试方法。单元测试的开发早于业务代码,流程在上一节介绍TDD的内容中已经提及。
2)验收测试(Acceptance Tests)
验收测试是针对程序或这API进行功能上的测试,本身也是开发工作的一部分。开发人员在没有通过验收测试之前是不能够认为开发工作已经完成。
上图从四个角度分析了自动化测试的使用。
从业务角度来看,验收测试和手工探索性测试都是针对业务功能进行的,来保证业务流的顺利进行。一般手工测试在代码上生产环境之前进行,有些团队称之为PVT(Product Validation Testing),即产品验证测试,对应的测试人员一般都是业务专家。
从开发支持的角度来看,单元测试和自动化验收测试是实现CICD和TDD的关键。
以上为一个完整的CICD从开发到发布的流程。在commit stage中,经常会进行代码扫描和单元测试。如果单元测试或者代码扫描未通过,开发人员可以获得快速反馈,并根据需要重新修改代码。 这个地方可以实现问题的左移, 即代码风格问题左移和安全性左移。
在自动化验收测试时,如果测试未通过,有两种可能性。第一是业务代码有问题,第二为验收测试代码需要调整。这个反馈应该发送给对应的测试团队和开发团队。
3)自动化测试金字塔(Automation Testing Pyramid)
根据自动化测试金字塔模型,尽可能多的问题应该被自动化单元测试发现,这样可以降低测试成本,开发人员可以尽早获得反馈以修改代码。验收测试的作者和维护者,应该尽可能是开发人员,这一点经常被很多企业和团队所忽略。
测试数据管理是很多团队和企业在做DevOps转型中容易忽略的领域。测试数据是保证测试能够正常进行的基础。没有良好的测试数据管理,会提告测试缺陷的误报率,降低团队的信息,忽略真正的严重产品缺陷。
测试数据管理必须要保证自动化测试能够顺利进行。针对不同的环境,例如测试环境、预生产环境、测试数据必须能够区别管理,因为不同环境的测试数据有可能会有不同。
测试数据管理应该能够自动的在环境设置完成之后,配置测试环境,以便开展自动化测试。在测试完成之后,能够自动清理数据,并且恢复环境至测试开始之前。
测试数据管理必须要能够根据代码开发更新,确保数据的实时性。
本文主要从技术的角度探讨DevOps如何助力企业数字化转型,后续将陆续推出包括DevOps流程、指标、文化和组织角度的解读,敬请持续关注。