原文首发在我的微信公众号 无闻是个码痴 上:在国外远程办公是一种怎样的体验?

前言

受到 Go 语言中文网 的站长 P 神和公司内其它同事的鼓励,我经过反复思考,决定写下这篇文章描述一下我在 Sourcegraph 这家公司作为一名软件工程师的日常。

公司简介

Sourcegraph 是一家基于开源和开放文化的初创企业,主要从事企业级代码搜索和智能提示的软件服务开发,旨在为用户打造一个实现高效生产的标准化开发者平台。

公司文化

全公司上下目前有大约 30 名成员,包括管理、销售、产品和工程师,并且目前仍在积极招揽优秀的工程师、销售经理和 UX 设计师。我们公司目前有约 20 人是分布在世界各地的全职远程岗位,包括德国、法国、葡萄牙、澳大利亚和美国(可能马上就有中国了呢,嗯?),每天去旧金山办公室的人只有大约在 2-5 个,所以咱们的 CEO 已经发出提案将取消办公室,将公司从远程首选(Remote First)转型到全体远程(All Remote)。该提案目前正在进行公示,因为有些同事会存在签证问题,所以还需要进一步地和移民律师沟通确认可行性。

整个公司对于全体成员的人文关怀非常浓厚,有什么问题找经理、找人事,每个人都非常乐意帮助解答自己力所能及的问题。

公司尊崇的是开源和开放文化,因此所有不涉及公司安全的代码仓库、需求文档、员工手册、决策流程等等全部都会以文档的形式记录呈现。所以写好文档、爱写文档是必备的技能点。在这篇文章中,我也会大量地链接到我们的公开文档。

组织结构

因为还是一个初创的小公司,所以还没有部门的概念,但是有以产品功能为划分的小组,一个人可能同时隶属于多个小组,一个产品也会有多个小组的成员协同合作。例如目前正在如火如荼开发的代码自动化(Automation),就是分别从前端组和核心服务组抽调成员进行开发的。

目前的常驻小组分别有:

  • 销售组:主要负责联系客户、销售产品、售前咨询等等
  • 产品组:主要负责产品规划、需求排序等等
  • 开发者关系组:主要负责和开发者搞好关系,了解开发者的诉求,参加各类大会、小会,发周边,发博客,发用户案例,演示产品等等
  • 代码自动化组:主要负责开发代码自动化产品的相关功能
  • 代码提示组:主要负责代码智能提示的相关功能,对多种语言支持定义跳转、引用查找等等
  • 产品分发组:主要负责公司内部的基础设施建设、部署、管理、运维和处理客户需求
  • 前端组:我们公司是前后端完全分离的,因此该组主要负责产品的前端、浏览器扩展(Sourcegraph Browser Extension)和代码托管平台原生插件
  • 核心服务组:这个就是我所在的组啦,主要负责公司所有后台服务的开发和维护,99% 的代码都是用 Go 语言开发的,还有百分之一是 Rust

团队协作

我们所有的文档都会放在 Google Docs 和 GitHub 仓库中,包括路线图、缺陷追踪、功能请求、需求文档等等。

需求定义

如果想要提出一个需求,这个需求的提出者需要编写一份需求文档,我们称之为 RFC(Request for comments),由提出者决定哪些成员是这份文档的审查员(一般为对某个产品部分最为了解的那个人),但是所有成员都可以评论或者提问。只有当所有的审查员都批准了之后,这份需求文档才算完成。接下来就会进入需求排级阶段,决定什么时候、由谁来实现这个需求。

需求文档的生命周期大体上分为:定稿中、审查中、已批准、已废弃和已实现。

如果对我们的需求文档感兴趣的话,可以查看完整的说明和流程

开发生命周期

不管是用户提交的功能缺陷、功能请求,还是团队内部提出的需求,最终都会根据当下产品的主要方向和各小组的工作量进行排级(Prioritization),从而确定由谁进行开发。

目前为止,我们所有的仓库都托管在 GitHub 的公共托管平台上( https://github.com ),并且使用了大量的私有库用于存放基础设施和安全相关的配置、脚本和程序等等。

sourcegraph/sourcegraph 是我们的主要产品仓库,里面包含了开源版和企业版的全部代码,所有的代码提交最终都会以 GitHub 合并请求(Pull request)的形式进行审查、修改和合并。

代码提交

我们使用的是特性分支(Feature branch)的开发模式,即每个功能会有自己独立的分支,团队成员也会在自己的分支上进行开发和测试,完全没有使用到仓库的派生(Fork)功能。一般来讲,每个成员的分支都会以名字的简写作为前缀,以方便分类和确定归属。例如我的简写是 jc,那么隶属于我的分支就会以 jc/ 开头,像 jc/bitbucket-cloudjc/gitserver-v1-response 之类。

代码审查

GitHub 的 Pull request 是一项伟大的发明,虽然依旧称不上完美,但在极大程度上简化和便利了代码审查的流程。

我们通过一个 CODEOWNERS 文件定义谁是某个文件的代码所有者(Code owners),因此每一个 Pull request 都会有默认指定的审查员。如果开发人员觉得还需要其它特定的成员帮助审查,可以再额外指定。

如果对修改部分的争议比较大,可以采用直接发消息或者视频会议的方式进行一轮快速讨论。工具和交流方式并不是目的,解决问题才是根本目的。

对于需要多少个批准(Approval)才允许将代码合并到 master 分支并没有硬性规定,基本原则就是你觉得行就行(谁提的合并请求,就谁负责点合并按钮)。但一般情况下,都是经过至少一位成员的批准后才会比较安心地执行合并操作。

持续集成和部署

我们的代码拥有海量的单元测试、回归测试、端到端测试和自动化发布测试,每一次代码提交都要经过数千个测试的持续集成。如果测试没有出现问题,则还会自动发布对应每个代码提交的 Docker 镜像到 Docker Hub,然后通知部署服务拉取镜像将最新的版本部署到我们在谷歌云上的 Kubernetes 集群中。

我们目前选用的 CI & CD 平台是 Buildkite,因为它支持自建资源,有利于更高程度的自定义化。不过这个平台也有它自己的问题,目前我们正在评估其它 CI & CD 平台或服务,以期满足我们目前存在的一些痛点。

版本发布

发布周期

运行在 sourcegraph.com 上的版本就是我们主仓库最新的 master 分支,但我们在每个月的 20 号会进行针对客户本地实例的月度发布。每一次月度发布都会有一个轮值主管,用于按照既定流程截取分支、发布版本、组织会议和协调各部分完成所有与发布有关的事项。这个 Issue 显示了 3.10 版本的发布流程和进度

发布回顾

在月度发布完成后,轮值主管会要求成员提交反馈意见,然后组织一场回顾讨论。所有人会根据自身意见给所有的反馈打分(每人一共可以用 10 分),得分最高的几项就会由轮值主管主持讨论。一般来讲,回顾讨论要求控制在一个小时以内,所以能够讨论的主题数取决于每个主题所占用的时长,确保时间的有效利用。

团队交流

公司主要使用谷歌的 G Suite(包括 Gmail、Google Calendar、Google Docs、Google Meet)、Zoom、Slack 和 GitHub 进行交流和协作。我们的 Slack 有 90 天自动删除归档的策略,要求所有人将重要事项的讨论成果编写成可朔源的文档。

会议

鉴于大部分的成员都是全职远程办公,且分布在不同的时区,所以公司鼓励多写文档、写好文档、异步交流的方式。

每周晨会

每周晨会是唯一的全公司会议,每个小组会从客户角度汇报上一周的大体情况,一般在半个小时内必定结束。为了体现公司对文档的高度重视,咱的工程副总裁也逃脱不了写需求文档的形式来提议晨会的汇报格式

小组例会

除了全公司的晨会来汇报各自小组的进展,每个小组每周一般还会举行各自的例会,时间和时长由各组自行决定。小组的例会主要是针对每个组更加细化的成员工作汇报,会有工程副总裁和产品经理共同参加。各个小组每周的需求排级和组内讨论就会发生在例会上,如果讨论过于深入,会要求相关人员另行安排时间完成后续的讨论。

一对一交流

每周、每月、每个季度,每个成员都会和自己的同事、上级、老板定期交流和谈心。可以讨论工作上遇到的挑战,生活上遇到的困难,前几天看到的新闻,反正就是谈天说地,扯淡闲聊,增进感情。

团队建设

公司充分信任和支持每一个成员,所以我们没有打卡制度、不需要请假许可、也没有请假上限、每年必须至少放假两周、不建议加班、有产假、有子女假等等等等,全都清清楚楚写在手册里。

除此之外,鼓励远程工作的公司最大挑战之一就是如何让每个人都觉得自己不是孤立的存在,而是一个完整的集体。我们公司对于团建的经费有非常明确和慷慨的政策,简而言之:

  • 每半年一度的公司活动宿旅费全包
  • 每人每年可享有上限 4000 刀的小组团建经费(假如一个组有 3 个人,那么整个组就有 12000 刀的整体经费)
  • 每人每年可享有一次到旧金山办公室驻场工作的全额费用报销(包括机票和酒店,驻场天数最长为 7 天 6 夜)
  • 每人每年可享有上限 1000 刀的职业发展和培训经费(参加大会、在线课程、线下培训等等)

以上这些还并没有完全包括每个人的基础福利,包括通勤费、话费、健身房、搬家补贴等等。

结语

这个作者很懒,并没有附上结语。