转换旧版应用程序的开发和交付流程

我们的团队负责大型企业产品的运营和开发。
在2017年初,我们从重大实施中休息一下,重新阅读了“经验教训”,我们坚定地决定审查应用程序的开发和交付。 我们担心交付速度和质量低下,无法让我们提供客户期望我们提供的服务水平。


现在是时候从言传身教到改变流程了。


本文将简要讨论我们从哪里开始,我们做了什么,现在情况如何,我们遇到了什么困难,我们必须抛弃什么,我们计划做些什么。


开始


有关系统的一些知识


该应用程序是“ 2000年代的建筑泄漏”的整体企业应用程序的经典示例:


  • 经过15年的经营和发展。
  • 它是一组与单个MS SQL数据库绑定的六个WinForms,Windows服务和ASP .Net应用程序。
  • 代码库大小:对于C#为〜1MLOC,对于9000个数据库对象。 许多业务逻辑在数据库端运行。
  • 该应用程序包含约250多个用于创建Win / Web客户端的解决方案(每组相关表单一个解决方案)。 这是先前开发过程和客户端体系结构的遗产。
  • 该应用程序通过更改内部配置来支持多种类型的进程(客户端):在系统数据库配置表中设置进程,权限,灵活字段等。 同时,所有客户端的应用程序代码库均相同。
  • 该应用程序已在25多个站点上部署和支持(每个站点都是系统的独立实例),并为不同时区的数千名最终用户提供服务。

转型前的交付过程


  1. 最终应用程序及其组件的开发和组装由承包商进行。
  2. 代码存储在承包商(MS TFS的本地版本)的侧面。 该代码每月以主存储库分支的当前版本的存档的形式发送给客户。
  3. 交付是通过交付“增量更新”来执行的:针对应用程序(dll,exe等的集合)和数据库组件(对于SQL脚本创建/更改的集合)。 承包商已构建应用程序并准备了增量软件包。
  4. 部署过程由运输系统支持,更改会自动应用。

交付是按月发布的一部分(按照我的安排,我之前在这里告诉过您)。


存在的问题


缺乏控制


  • 尽管有正式的代码所有权,但客户无法实际组装应用程序。
  • 结果,不可能验证发送给客户的代码的可操作性。
  • 代码更改-对客户不透明。 无法匹配产品中请求的更改和实际更改。
  • 代码分析对于SQL来说是困难的,对于C#组件来说是不可能的

人工输入和错误


  • 准备“增量软件包”是开发过程中的耗时过程,是导致错误和某些项目成本的原因。
  • 部署Delta Packet应用程序需要跟踪软件包的顺序。 数据包乱序错误是主要的部署问题,也是重要的事件来源。
  • 经常发生回归:似乎已经修复并推出对产品的更正的错误再次出现。

局限性


  • 几乎没有一次恢复系统状态(回滚更改)的能力。
  • 几乎没有通过吸引客户员工来有效扩展开发和早期测试资源的能力。

预期结果


在项目开始时,我们为解决上述问题设定了明显的目标。


  • 将代码存储库转移到客户控制
  • 将应用程序构建过程移至客户端
  • 修改变更的分配过程,放弃“变更增量”,而进行全面更新

此外,使用实现前两个目标时获得的解决方案,我们计算出:


  • 通过代码控制提高最终解决方案的技术质量
  • 通过提供自助服务部署来提高测试参与度和可用性。

漫长的阶段


分析开发过程的当前状态


第一步:分析现有承包商的开发过程。 这有助于计划更改,以便在可能的情况下不会中断工作。


不幸的是,对开发过程的了解表明,在目前对IT行业的了解中,没有该过程。


  1. 尚未在存储库中最新维护其数据库代码和业务逻辑。 主要原因是:缺少从存储库中的代码实现汇编的工具以及结果的部署。 因此,存储库中的代码只是文档。
  2. 数据库代码的“实际”版本位于通用的“开发数据库”中,数十名开发人员在该数据库上工作。
  3. 客户端应用程序代码(C#,ASP.NET)保留在存储库中,但是不能保证提交的质量和及时性。
  4. 组件(不是整个应用程序)的组装是在开发人员的站点上进行的。 目前尚不清楚汇编之前如何更新代码。 组装后的组件被放置在共享的共享文件夹中。 从那里,为客户形成了一个“增量包装”。
  5. 完全缺乏维护发展分支的实践。 通过间接迹象,我们怀疑了很长时间-但是在深入研究过程之后,一切都变得显而易见。

切换到新的存储库和版本控制系统


对MS平台和公司标准的依赖决定了开发环境的选择-Team Foundation Server。
但是,在我们直接启动项目时(2017年4月),Visual Studio Team Services的版本刚刚发布。 该产品看起来非常有趣,它被指定为MS的战略方向,它提供git存储库,用于本地和云的组装和部署。


公司本地TFS落后于VSTS的版本和功能,仅在讨论过程中才能迁移到新版本。 我们不想等待。 我们决定立即改用VSTS,因为这减少了支持该平台所需的管理费用,并为我们提供了对操作方式和操作的完全控制。


在开始变更时,开发团队具有TFSVC的经验,应用程序代码存储在这样的存储库中。 另一方面,GIT实际上早已成为IT社区的标准-客户和第三方顾问建议切换到该系统。
我们希望开发团队参与确定新的版本控制系统,并做出明智的选择。


我们在VSTS中使用不同的存储库部署了两个项目-TFSVC和GIT。 定义了一组场景,提出了这些场景以测试和评估每个系统的可用性。


在评估的方案中包括:


  • 创建和合并分支
  • 组织联合工作(在一个或不同分支上)
  • 更改链操作(提交,撤消)
  • 第三方整合
  • 在服务器不可用时继续工作的能力。

结果,正如预期的那样,选择了GIT,到目前为止,没有人后悔。


作为一个过程,我们开始使用GitFlow。 就像我们习惯的那样,此过程提供了对更改的足够控制,并允许发布版本。


  1. 我们通过一项要求所有更改都通过请求请求的策略来捍卫开发分支。
  2. 我们努力坚持“一张票一张拉请购单”的做法。 来自不同票证的更改永远不会合并为一个更改。 我们尽力在功能分支上进行测试,以避免在后续拉动重震中进行更正的情况。
  3. 当合并到开发中时,所有更改都合并到一个提交中(压榨)。
  4. 发布分支是从开发创建的。
  5. 如有必要,您可以在发行分支中有选择地添加最新更改(樱桃选择)或全部添加(变基)。 我们不直接在发布分支中进行更正。
  6. 在产品上部署了最新版本之后,它将通过推力进入掌握状态(只有少数人拥有此权利)

产品组装自动化


该应用程序是大量的程序集,数百种解决方案。 事实证明,在过程审核中,所有这些都是分别和“手动”收集的。
在第一阶段,我们决定不重做所有内容(以免停止现有的交付),而是将程序集“包装”为一组msbuild脚本-每个组件一个脚本。
因此,我们很快就获得了执行所有必要的中间工件以及最终产品的脚本。


一个单独的故事是数据库设计。 不幸的是,该系统包含几个结构不完善的CLR组件。 依赖关系不允许带有内容的简单部署基础。 目前,这正在通过预部署脚本解决。
此外,由于系统环境不平衡(在不同位置安装了SQL Server 2008和2014版本),因此有必要组织针对.Net 2.0和4.0版本的基础项目的组装。


在准备好所有脚本并对其进行测试之后,将它们用于构建脚本VSTS中。


在开始组装之前,立即将所有产品的版本更新为通用的标准编号,包括内部版本号。 相同的号码存储在部署后脚本中。 因此,所有组件(数据库和所有客户端应用程序)都是一致且编号相同的。


部署到测试台


构建过程的初始版本完成后,我们继续准备部署脚本。


预计数据库是最麻烦的。


部署真实数据库的“最高”副本会发现程序集和真实系统状态之间存在许多冲突:


  • GIT和实际系统中的版本不一致
  • 计划删除的用户拥有的数据库模式。

稳定发展进程


当然,谈论这一点很奇怪,甚至在这里写下来也是如此,但是对开发人员而言,最严重的变化是引入了“如果不在git中,则不存在”这一原则。 以前,该代码是“用于向客户报告”的。 现在-没有这个,就不可能交付任何东西。


最难的是使用数据库代码。 在切换到从存储库部署数据库之后,通过使用sqlpackage进行组装和部署,“增量”方法被“所需状态”方法代替。 包已成为过去;所有内容都必须自动部署。


但是! 在完全过渡到新的部署过程之前,仍然需要交付更改。 并且有必要以老式的方式进行此操作-“增量更新”。


我们面临的任务是在交付增量数据包和存储库的内容时确保系统状态的完全恒定的一致性。


为此,我们组织了以下过程:


  1. 定期地,从存储库中收集代码并将其部署到空的“模型”数据库中。
  2. 根据“模型”基础,正在准备进行特殊的自动测试。 对于“模型”数据库的每个对象,计算校验和。 自动测试包含所有这些校验和,并在启动时计算“已校验”数据库中相应对象的校验和。 对象组成或其校验和的任何差异都会导致测试下降。
  3. “下降”测试会自动禁止从测试环境进一步转移软件包。 在先前的运输系统中已经实现了这种集成。

因此,使用自动控制,可以相对快速地将git中的产品数据库代码更新为最新版本并对其进行维护,而无需项目团队的额外努力。 同时,开发人员开始习惯于正确,及时地将代码提交到存储库的需求。


集成测试环境中的产品部署


完成上一个阶段后,我们直接着手在测试环境中部署应用程序。 我们完全停止将增量软件包应用到测试系统,并转而使用VSTS进行自动部署。


从那一刻起,整个团队开始收到之前付出的努力的最初成果:部署无需任何额外的努力。 自定义代码是自动收集,部署和测试的。


不幸的是,正如我们稍后所理解的,“存储库的对齐”导致了这样一个事实,即我们拥有稳定支持的“开发”版本,但是“生产”版本仍然不可用。 因此,除了QAS和PRD的测试环境外,没有什么比这更重要的了。


可以将数据库方面的应用程序代码与生产性代码进行比较,并了解它们之间的差异。 没有什么可与客户端应用程序进行比较的-只有一组可执行文件形式的最新生产版本,并且从中编译它们是不可能确定的。


通过自动组装测试产品


更改组装方法后,该产品必须进行广泛的回归测试。 有必要确保应用程序正常运行,并且没有丢失任何内容。
测试时,事实证明,使用数据库侧面的功能会更容易。 幸运的是,我们已经开发了涵盖关键领域的大量自动测试。


但是,没有针对C#的测试-因此,所有操作都是手动检查的。 这是一项大量的工作,并且验证花费了一些时间。


信念的飞跃-试生产部署


尽管进行了测试,但是第一次在产品上进行部署还是令人恐惧的。


我们很幸运-我们刚刚计划了在新站点进行系统的下一次部署。 我们决定利用这次机会进行试点部署。
用户没有看到,新装配的可能错误很容易修复,真正的生产性工作尚未开始。


我们部署了该系统,并在数周内处于生产前使用模式(低负载,可以在产品中跳过的某种使用模式)。 在这段时间内,发现了一些在测试过程中遗漏的缺陷。 他们在发现问题时进行了更正,并立即推出新版本进行验证。


在正式发布和发布后一周的支持后,我们宣布这是“以新方式”组装和交付的第一本副本。


该版本的程序集成为master分支的第一个稳定版本,它挂有fisrt_deployment标签(我们未使用带有哈希值的提交来订购图标)。


在整个生产环境中扩展部署


正如詹姆斯·邦德所说:“第二次要简单得多。” 在试点部署成功之后,我们迅速连接了类似类型系统的其余实例。


但是系统有多种使用方式-一种功能可以用于一种类型,而在其他情况下则不使用。 因此,在第一种类型的实现上测试的功能不一定能保证在其他情况下的成功。


为了测试其余使用类型的功能,我们开始使用正在开发的活动项目。 这个想法是相似的,并且是第一次部署-我们开始使用自动装配,将它们与设计功能一起“滑”给用户。 因此,使用产品的“项目”版本的用户同时检查了旧功能。


扩展本身揭示了意外的技术问题:


系统景观不均
除了直接部署应用程序外,我们还必须首先注意所有地方都一样-.Net版本,Powershell和模块。 这花费了相当长的时间。


网络连接
在某些站点,网络连接根本不允许泵送组件的所有组件。 传输过程中超时,损坏。 我们检查并尝试了很多方法-不太成功。


我必须关注以下解决方案:汇编脚本已完成,因此所有结果都打包到一个大档案中,然后将其切成小片段(每个2 mb)。 我们完成了部署方案的最终确定,以消除下载工件时的并发性,接受了所有2 MB的片段,并从中还原了可以扩展的内容。


与防病毒冲突
我们遇到的另一个奇怪的问题是防病毒软件与部署步骤之一之间的冲突:从工件存档中提取各种“可疑”文件(例如.js,.dll)时,防病毒软件开始仔细查看它们。 最奇怪的是,防病毒软件在解压缩结束之前就开始冲向该文件,并且解压缩过程随着消息“该文件正被另一个进程占用”而下降。 尽管我们为此付出了很多努力,但从扫描中排除了带有伪像的本地文件夹,但这并不是很好,但是我们没有提出其他建议。


工艺改进


, " " — .


  • (service-now.com) VSTS Work Items. develop — .
  • CI feature . —
  • "self-service"
  • — . , .
  • : , CI/CD ,
  • ( )
  • - ( ) . — , .
  • VSTS , , .

总结



  • MS VisualStudio Team Services ( — Azure Devops) . — GIT
  • (/)
  • git / GitFlow .
  • code review .
  • CI. , feature , .
  • . , .
  • ( ) — . - .
  • - 1 . - .
  • "" .


1个— ,6
23
35

— 14


, , , .



, — 250 * .

Source: https://habr.com/ru/post/zh-CN427111/


All Articles