程序员为什么千万不要瞎努力?

本文作者用对比非常鲜明的两个开发团队的故事,讲解了敏捷开发之道 —— 如果你的团队缺乏统一标准的环境,那么即使勤劳努力,不仅会极其耗时而且成果甚微,使用容器化技术、CI/CD,不仅能让开发环境、测试环境、预发环境、生产环境保持一致,同时也对测试和质量保证有至关重要的作用。

作者 | Tylor Borgeson,已获作者翻译授权
译者 | 罗昭成
原文 | A Tale of Two Software Teams
本文首发于 CSDN 微信(ID:CSDNnews)

1. 写在前面

这是我「流行软件开发实践」系列文章中的第四部分,在本系列文章中,我计划包含软件工程师通过提升开发流程和实践来改善软件开发的一系列方法。我曾在 ThoughtWorks 担任软件顾问,现在我在德国一家大型的零售公司工作,这些方法都是我在职业生涯中学习并实践验证过的。

这么多年来,我参加过很多团队活动,如足球、棒球、摔跤、篮球、足球、田径……我基本上参加了所有与运动有关的团队活动。有趣的是,我也加入过很多软件开发团队。

在这些团队中,我注意到了一个共同点,优秀的人才可以为团队成功中做出重要的贡献(如赢得比赛,高效开发需求并上线),但是他们并非团队成功唯一的原因。

在运动项目中,训练很重要,但是并不是所有的训练都重要。真正有用的那些训练是那些看起来不像是训练的训练。所以,对运动项目来说,比赛才是最好的训练,对于软件开发来说,在和生产环境几乎一致的地方测试才是有效的。

这个观点也是本文的重点,在和生产环境一样的环境中,进行开发和测试的效果非凡。下面,我将用两个我以前所呆过的团队中的故事,来阐述这一观点。

2. 勤劳有限责任技术公司 —— 团队一

这个公司名称是虚构的,但是团队的工作情况和公司名字一致。

公司中有一个很大的前端项目,很多团队都在上面贡献这自己的努力,当然,我们团队也写着其中一部分功能。这些团队各自提供着自己的服务,并且这些服务也存在着各种相互依赖的关系。

当第一天到公司的时候,我们不得不在自己的新电脑上设置基础的开发环境。这些环境不仅仅包含我们部门自己的依赖服务,还必须要包含很多其它部门需要依赖的服务。这就导致我很难在本地将整个应用程序跑起来。

经过我的努力,我花费了两天时间,终于在我的电脑上跑起了整个应用程序实例。但据我所知,很多其他的程序员并没有将本地环境跑起来,而是与其他人进行结对编程,共用同一个环境。

很多同事都不能在本地测试他们的代码,这就意味着,他们需要将他们的修改发布到测试环境中去,才能知道他们修改是否能够生效,是否能够正常地与其它服务进行交互。

这在实际工作中,具有相当大的挑战,很多团队并不能及时将所有的代码更改推送到所有的环境中去。这将会有可能出现在测试环境中的测试结果与生产环境的结果不一致。

有一次,我们部门的一个程序员对一个功能进行修改,该功能需要与另外一个部门提供的服务进行数据交换,他很快就开发完成了,并在测试环境中进行测试,但在测试环境中,一直无法正常的跑通。但当我们把修改发布到线上环境,却发现能良好地运行起来。最后排查到问题原因是因为在测试环境与线上环境依赖的服务版本不一致。线上环境使用的是一个新版本(5.0.2),而测试环境却是使用的一个旧版本(5.0.1)。

另外一件“有趣”的事是,我们的测试环境是一台虚拟机,当需要更新代码的时候,我们需要登录到那台机器,在上面跑一个脚本,将最新的代码拉到服务器上,并重启应用。并且,公司的虚拟机数量不足以提供给每一位开发者使用。

这些问题,也导致代码部署到生产环境的过程非常漫长。所以为了减少部署所花费的时间,所以我们会每两周在生产环境中(像测试环境那样)进行一次部署。当然,每当有新东西(新功能、Bug 修复等)要发布到生产环境中时,都需要重复一次这个耗时的部署过程。

2. 聪明有限责任技术公司 —— 团队二

显然,这个公司名称也是虚构的,但是其团队的工作情况和公司名字一致。

就整个团队而言,这个团队和前文所述的团队几乎一致。我们也致力于多个微服务[1]的开发,我们也需要和其它做着类似事情的部门进行交互。我们通过 REST 接口接收请求,也发送请求到其他服务上。

当第一天到公司的时候,我再次开始设置我的基础开发环境。在代码库中的 README.md 文件中,列出了配置开发环境的几项说明:

  • 安装 Docker;

  • 如何从团队镜像库拉取和推送 Docker 镜像;

  • 如何在本地运行容器;

  • 如何将本地修改关联到容器中。

从我拿到项目权限,一个半小时后,我在本地跑起来了第一个服务,并且能够将本地的改动推送到这个服务上。

这个团队和前文所述的那个团队一样,也有测试环境、预发环境、生产环境。一旦代码提交到主干上,CI/CD[2]上的任务会自动将代码构建成 Docker 镜像,并开始跑测试用例,紧接着会给镜像打上版本和标签并将镜像推送到镜像库中,还会将测试环境与预发环境中的镜像替换成最新的版本。在必要的时候,通过手动触发,将镜像部署到生产环境。

整个过程,在最糟糕的一天,也最多花费 10 分钟时间。

在这个公司中,所有的团队都有类似的设置。

这些环境的区别在于,在测试环境中,使用的是测试数据,第三方的服务要么是被忽略掉,要么是被 mock 掉。在预发环境中,也是使用测试数据,但是其它的服务都是在正常运行状态。

4. 关键点

这两个团队中的差异,我在很多团队都看到过,我能够轻松地指出他们存在的问题。如果让你选择加入其中某一个团队时,我相信大多数开发都会选择同一个团队。

  • 容器化

第二个团队将他们的服务进行了容器化,这给他们带来了很多的好处。因为项目中所有的依赖都在容器中设置完成,所以在新的机器上部署非常的容易,不仅仅只有这一个优点,容器化也使它们在生产环境中的部署变得非常容易。

容器化让整个应用程序变成了一块,可以轻松、快速地进行更换(这也让敏捷开发四个关键指标中的部署频率提高了)。

容器化也能有助于实现多个环境的标准化。

  • 标准化/一致性

在第一个团队中,主要的挑战就是源于他们没有统一标准的环境。

每一个虚拟机都需要单独去更新正确的程序包版本,如果忘记更新某一台虚拟机时,这就有可能会引起问题,这些问题要么是功能问题,要么安全问题,这都非常的严重。

环境不一致也会影响测试的有效性,因为我们不知道在测试环境测试的结果是否与线上环境的结果保持一致。很多错误都是由于环境不一致引起的。

在第二个团队中,使用容器化技术与自动化部署技术相结合,这样能很容易保证生产环境与测试环境一致。当然,即使环境一致也有可能会出现问题。不过,你也不必担心,这种错误的出现会被极大的降低(敏捷开发四个关键指标中的变更失败率)

用一句话总结:

使用容器化技术、CI/CD 能够更加容易地让开发环境、测试环境、预发环境、生产环境保持一致,也对测试和质量保证有至关重要的作用。

朋友们,更聪明地工作,而不是更辛苦地工作。

5. 系列阅读

1. 为什么持续集成和部署在开发中非常重要?

2. 被高估了的测试驱动开发?

3. 为什么程序员如此“嫌弃”主干开发模式?

4. 程序员为什么千万不要瞎努力?

5. 为什么许多程序员讨厌结对编程?

6. 程序员如何用代码彻底终结系统那些事儿?

你可能感兴趣的:(程序员指北,翻译)