Files
CategoryResourceRepost/极客时间专栏/研发效率破局之道/工程方法/11 | 研发环境:Facebook怎样让开发人员不再操心环境?.md
louzefeng d3828a7aee mod
2024-07-11 05:50:32 +00:00

150 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<audio id="audio" title="11 | 研发环境Facebook怎样让开发人员不再操心环境" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/a0/4f/a0604718d5322013784241950e93144f.mp3"></audio>
你好,我是葛俊。今天,我来和你聊聊研发环境的问题,也就是如何才能让开发人员少操心环境,甚至不操心环境。从这篇文章开始,我们就一起进入工程方法模块了。
在[第5篇文章](https://time.geekbang.org/column/article/129857)关于“持续开发”的讨论中,我与你介绍了获取开发环境是开发工作的核心步骤之一,对提高研发效能来说是非常值得优化的环节。当时,我与你提到了开发环境服务系统以及沙盒环境,解决了开发环境的准备工作。
而这里的“开发环境”只是研发环境的一部分,特指开发机器环境,包括开发机器的获取、网络配置、基本工具以及代码的获取和配置。今天,我们就来看看整体的研发环境的配置问题,从全局上切实解决开发人员因为操心环境而导致的效能低下。
在此之前,你可以先回忆下是否对以下问题似曾相识呢?
- 开发人员使用的电脑配置太低运行太慢编译一次要10分钟
- 测试环境不够,上线时熬夜排队等环境;
- 工具零散,不成系统,很多步骤需要手动操作,开发思路常常因为流程不连贯而被打断;
- 团队成员的环境设置参差不齐,有个别开发人员环境配置得比较好,效率比较高,但没有固化下来,其他团队成员也用不上。
这些问题,实际上都可以归结为研发环境不够高效。就像低劣的空气质量和食物质量会影响我们的身体健康一样,不理想的研发环境会严重降低研发效能。
具体来说,按照开发流程,软件研发需要以下几种环境:
- 开发机器;
- IDE
- 开发过程中使用的各种工具、数据和配置;
- 本地环境、联调环境;
- 测试环境、类生产环境。
接下来我会按照这个顺序分别与你介绍这5套环境如何配置。
因为Facebook在环境配置上做得非常好比如说他们可以保证开发人员在5分钟之内拿到一套干净的开发机器环境。所以我会与你着重分享Facebook的实践然后根据这些实践总结出一套提供高效研发环境的原则。同时我也会与你介绍一些我在其他公司的落地实践帮助你掌握与环境配置相关的内容。
## 如何配置高效的研发环境?
### 开发机器
Facebook从不吝啬在开发机器上的投资。每个开发人员除了有一台笔记本外还在远程数据中心有一台开发机器。数据中心的机器用于后端以及网站的开发为方便描述我称之为后端开发机。而笔记本有两个用处一是用来做移动端App的开发二是作为终端连接到后端开发机做后端和网站开发。
两台机器的配置都非常强劲。后端开发机一开始是实体机器后来为了便于管理和提高资源利用率逐步转为了虚拟机但不变的是配置依然强大。在2015年的时候绝大部分机器配置都能达到16核CPU 、144G内存。笔记本有两种选择一种是苹果MacBook Pro另一种是联想ThinkPad都是当时市场上顶配或者顶配下一级的配置。
开发机器的获取和释放,则是通过共享机器池以服务化自助化的方式完成的。更多细节,你可以再复习下[第5篇文章](https://time.geekbang.org/column/article/129857)的相关内容。
### IDE
IDE指的是集成开发环境。Facebook持续在IDE上投入以完善其功能、一致性及一体化体验。接下来我会以后端和网站开发为例来说明。
因为代码存放并且运行在后端开发机上所以在2012年以前绝大部分开发人员都是使用SSH远程登录到后端开发机在那里使用VIM/Emacs这类能在命令行里运行的编辑器进行开发工作。也有人尝试在笔记本上运行GUI的IDE远程挂载后端开发机上的文件系统但总是有卡顿效果不好。
在这种情况下公司首先采用的办法是尽量提高命令行编辑器的体验把VIM/Emacs配置成类似IDE的工具将最常见的功能比如代码搜索、代码跳转、Debugger等集成进去效果还算可以。
不过与GUI形式的IDE相比这种命令行的工作方式还是有一些局限性比如和其他工具服务集成不方便需要记忆大量快捷键在显示形式上不够丰富导致用户体验不够好等等。所以Facebook持续投入研究GUI形式的IDE。
第一个成型的GUI IDE是一个Web IDE也就是在数据中心运行一些Web IDE服务。这些IDE服务连接到开发者的后端开发机上获取代码同时提供网页界面供开发人员用浏览器登录进行开发工作。这种专门的IDE服务解决了远程文件夹挂载的卡顿问题同时跟其他服务集成起来也很方便。
比如它可以与Phabricator的代码审查功能集成在一起在代码中用inline的方式显示其他人对你的代码的comments也就是说在两行代码之间显示一个额外区域用于展示comments。类似的它还可以方便地与代码搜索服务、代码跳转服务、Debugger集成甚至还可以跟CI/CD工具链的发布工具集成所以非常方便。
到2014年的时候Facebook的大部分开发人员都逐渐转移到这个Web IDE上去了。如果你想深入了解Web IDE可以参考下[Apache Che](https://www.eclipse.org/che/)项目。
这个Web IDE已经很方便了但基于网页的IDE在易用性和安全性还是有一些局限所以Facebook继续加大在GUI形式的IDE方面的投入最后使用Electron框架实现了一个原生的IDE也就是[Nuclide](https://nuclide.io/docs/quick-start/getting-started/)。
Nuclide的工作原理和Web IDE基本一致都是在数据中心运行IDE服务IDE的前端则运行在本地笔记本上通过与IDE服务联通实现代码编辑等功能。只不过Nuclide的前端是运行在开发者笔记本上的一个原生应用而Web IDE的前端是运行在笔记本上的网页浏览器而已。Nuclide的功能比Web IDE更强大易用性也更好同时因为没有浏览器的依赖安全性也更好一些。
### 本地环境、联调环境
关于Facebook的本地环境我已经在[第5篇文章](https://time.geekbang.org/column/article/129857)中介绍过了,主要就是加快本地构建,使用生产环境的数据,从而使得本地环境更加快捷、方便。
而至于联调环境,我曾在[第6篇文章](https://time.geekbang.org/column/article/131673)中简单提过。在代码提交到Phabricator上进行审查的时候Phabricator会调用一个沙盒系统创造出一个沙盒环境运行正在被审查的代码。这个系统也是用机器池实现的同时也是一个自助式服务也就是说开发人员可以不通过Phabricator直接调用API来生成沙盒环境。
本地环境和联调环境是开发中最高频使用的环境,对持续开发很重要。接下来,我再与你分享**两个我在其他公司的实施案例**吧。
**第一个例子是我在Stand公司搭建本地环境**。Stand的业务规模小因此并没有使用微服务主要的服务只有单体的网站后端服务、数据库服务MySQL、缓存服务Redis以及一些数据监控服务相对来说比较简单。
我们的做法是,把这些依赖服务尽量在本地开发机器(也就是笔记本)上都运行一个实例。实在不能在本地运行的服务,要么在本地环境运行时不调用它,要么就在调用它的时候传递额外的参数,表明这个调用来自开发环境,而被调用的服务则针对这样的调用进行特殊处理,从而达到不污染线上环境的效果。
这是一个很常见的办法,简单有效。不过,它的缺点是本地环境数据跟线上环境有区别。
如果你的系统采用的是微服务则可以采用以下3种常见办法。
- 第一种方法是,直接在自己的机器上把所有的依赖服务都跑起来。这种方法的优点是方便,但要求开发机器配置要求高。
- 第二种方法是,团队维护一个环境,让大家的开发环境接入。也就是,开发者自己的机器上只运行自己开发的服务,调用其他服务时就使用这个共享环境中运行的服务实例。这种方式对开发机器要求不高,但需要团队维护一个环境,并且一般来说大家需要经常更新这个环境中的服务,整个环境容易不稳定。
- 第三种方法是,使用服务虚拟化工具,来模拟依赖的服务,比如[Mountbank](https://github.com/bbyars/mountebank)、[WireMock](https://github.com/tomakehurst/wiremock)。你可以参考[](https://juejin.im/entry/5a54a432f265da3e591e27ee)[篇文章](https://juejin.im/entry/5a54a432f265da3e591e27ee)来了解WireMock的使用方法。
**第二个例子是,我为一个云产品团队提供联调环境**。这个云产品结构非常复杂有十多个服务至少需要3台服务器不但有软件还有数据、组网等复杂的设置部署很困难更严重的问题是这个环境一旦损坏就很难修复需要从头再来所以开发人员自己配置基本不可能运维人员也是忙于维护应接不暇。
针对这个问题我们也是使用了机器池的办法。不过这个机器池里面的单元不再是单个机器而是由3台机器组成的服务。这个服务自助化提供给开发者使用使用之后自动回收销毁。
同时,确保机器池中有两套空闲环境。不够就补充,多了就删除,以保证获取环境时可以马上得到,同时又不会因为有太多空闲环境而造成资源浪费。
另外,每次有了新的稳定版本,运维人员都会更新脚本,并重新安装和配置系统,保证开发人员能够在稳定版本上进行联调。
这样一来就解决了团队开发人员的环境问题将获取环境的时间由2~4个小时缩短到了几分钟。
### 开发过程中使用的各种工具、数据和配置
除了IDE开发过程中还会用到其他工具比如代码搜索、发布部署以及日志查看工具等。这些工具的组合可能与你平时理解的开发环境不大一样但事实上它也是一种广义的开发环境对开发效率影响很大。
这部分环境的优化,主要是使用工具之间的网状互联来提高效率。关于工具的网状互联,我在[第4篇文章](https://time.geekbang.org/column/article/128867)中有介绍。这里我想强调Facebook的另一个重要实践**重视开发体验,将开发流程中常用步骤的自动化做到极致**。
我用一个具体的例子来说明。我们都知道Git 的Commit Message代码提交描述是提供信息的重要渠道。但它有一个局限就是只能存储文本而图片在描述问题时常常比文字有效得多也就是“A picture is worth a thousand words”翻译为中文就是我们常说的“一图胜千言”。
为解决这个问题Facebook采用了以下方式
1. 提供了一个图片存储服务并为上传的图片提供永久URL
1. 开发了一个端测的截屏工具截屏之后自动上传到图片存储服务而且在上传成功之后自动把图片URL保存到本地笔记本的系统剪贴板中
1. 提供了一个内部使用的URL缩短工具避免URL太长占用太多文字空间。
这三个工具集成起来一个具体的使用场景是这样的我在写Commit Message的时候如果要截屏描述修改效果就使用一个快捷键比如Cmd+Alt+4激活截屏工具随后拖动鼠标截屏然后使用Cmd+v就可以直接把图片的URL粘贴到Commit Message里面了。
这个工作流非常顺畅、高效不仅被大量用于Commit Message的书写中也经常被用在聊天工具中。后来我到了其他公司都会先配置这样一套工具流程。
### 测试环境、类生产环境
在测试环境、类生产环境的管理上Facebook使用一个叫作[TupperWare](https://engineering.fb.com/data-center-engineering/tupperware/)的内部系统以IaC的方式进行管理。不过Facebook并没有开源这个系统。如果你所在公司使用的是Docker那可以使用Kubernetes实现类似的功能。
如果你们没有使用Docker可以试试HashiCorp公司的[Terraform](https://www.terraform.io),或者使用[Ansible](https://www.ansible.com)、[Chef](https://www.chef.io)之类的配置管理工具,来产生一套干净的环境供团队成员使用,之后再销毁,既方便又不浪费资源。
这里,我再与你分享一个我在**Stand公司使用AWS管理压测环境的例子**。当时我们没有使用Docker于是我们选择了AWS的OpsWorks框架。它是AWS基于Chef-Solo开发的一个应用程序管理解决方案同时支持基础设施的建模和管理。
OpsWorks这个框架的用法也是声明式的只不过这个声明不是纯代码而是在AWS的网页上配置的使用效果和TupperWare差不多就是**首先**定义一个压测环境需要几台机器,需要运行什么操作系统、需要什么负载均衡器、需要什么数据库等。
**然后**通过OpsWorks上暴露的钩子使用代码来管理应用的生命周期从而实现系统和应用的初始化。通过这种方式我们可以很方便地使用OpsWorks产生一个云主机集群用于压测结束之后马上删除方便而且划算。
其实使用Ansible或者Chef也可以实现类似功能但需要自己开发些东西这里我就不详细讨论了。
## 提供高效研发环境的原则
通过以上实践可以看出,配置高效的研发环境主要包括以下几条原则:
1. 舍得投入资源用资源换取开发人员时间。Facebook之所以从不吝啬在开发机器硬件上的投入是因为人力成本更高。
1. 对环境的获取进行服务化、自助化。这一点可以在开发机器、联调环境的获取上得到很好的体现。同时常常使用IaC、配置管理系统比如Chef和机器池的方法来实现同时利用弹性伸缩来节约资源。
1. 注重环境的一体化、一致性也就是要把团队的最佳实践固化下来。比如Facebook一个常见的操作是配置文件统一处理。以VIM为例将VIM的配置文件存放到网络共享文件夹中开发人员只要在自己的.bashrc文件中加上一行就可以搞定。
```
source /home/devtools/vimconfig
```
## 小结
今天我首先按照开发流程也就是开发机器、IDE、本地环境和联调环境、开发过程中使用的各种工具及配置以及测试环境和类生产环境的顺序与你讲述了高效研发环境的具体实践。然后基于这些实践总结了3个基本原则一是用资源换时间二是服务化、自助化环境的获取三是实现环境的一体化、一致性。
我认为这些原则和实践的背后有一个重要思路就是Facebook重视环境并持续优化环境。这一点在IDE的演化上尤为明显从命令行到Web IDE再到Nuclide一直在进步。另外在去年年底Facebook停止了对Nuclide的开源项目的维护这也意味着后面他们可能还会有对IDE的一轮新的优化。
以上种种做法使得我在Facebook做开发的时候对研发环境的感觉就是不用操心需要使用的时候直接到网站上申请就可以使用配置也方便团队的配置都已经在那里了同时环境中的各种工具、流程都很顺畅让我能够静下心来做开发、写算法做我最能提供价值的事情。
## 思考题
我在“开发过程中使用的各种工具、数据和配置”这一章节中提到的截屏工具流程,你觉得价值大吗?值得引入你所在的公司吗?如果值得的话,可以怎么来实现?
感谢你的收听,欢迎你在评论区给我留言分享你的观点,也欢迎你把这篇文章分享给更多的朋友一起阅读。我们下期再见!