笔者从 2020 年疫情爆发之前,一直从事后端开发工作。2020 年因为工作原因,加入了 SAP 一个代号为 Spartacus 的开源项目的开发团队。这个项目是一个基于 Angular 的电商 Storefront 框架,其代码贡献者来自全世界各个地区。
实际上,这个项目的开发工作由六个敏捷开发团队组成,笔者是唯一一位来自 APJ 即亚太地区的开发人员。从此,我开启了为期两年多,一直持续到现在的远程办公生涯。
本文通过下列几个方面,向大家分享笔者所在的开发团队,在远程办公领域的经验和团队日常的远程办公,所使用过的一些工具。
目录如下:
我们项目的代码托管在这个 Github 仓库上:https://github.com/SAP/spartacus
每当有新功能开发时,我们会创建名为 epic/XXX 的代码分支,待开发和测试结束后,将其合并到 develop 分支上。

已有功能的缺陷修复,则使用分支 fix/XXX 来完成。对于新版本的发布,使用 release/XXX 分支完成。

通过定义这些分支的命名规范,身负不同类型开发任务的同事们,能够在不同的分支上工作,彼此互不影响。
Github Pull Request 的 Code Review Web 界面,将代码修改前后的状态,提出代码审查意见的 Reviewer 和提出代码审查的申请者所需的下一步修改等动作,完美地进行了封装和呈现,使得不在同一办公室的开发人员们,能够在这些 Web 界面高效地进行代码审查工作。
下图是我的同事在某处代码进行审查后提出的修改建议,修改建议包含修改后的源代码,以及通过文字表达的该建议背后的考虑。

Github 的缺陷(Issue)管理也是其一大亮点。
来自全球的 Spartacus 使用者和代码贡献者,可以按照事先准备好的模板,给我们的代码仓库创建 Issue. 这些 Issue 可以是现有功能 bug,也可以是新的功能请求。每个 Issue 可以分配一到多个标签(Label),用来标识该 Issue 的特征,以及需要解决的领域问题。目前我们的代码仓库有 7804 个已经关闭的 Issue,还有 702 个处于 Open 状态。这八千多个 Issue,通过总共 534 种不同类型的 Label 来描述。

每个 Issue 可以分配给一个项目(Project),这个项目是 Github 提供的项目进度管理模块中的模型之一。在 Github Project Dashboard 里,我们能清晰地看到分配到同一个 Project 的所有 Issue 列表,如下图所示:

这些 Issue 可以分别被放置到名为 To Do,In Progress,Code Review & Local,QA from Server After Merge 的列之下。
每一次敏捷开发的 Sprint Planning Meeting 结束之后,开发团队当前 Sprint 需要做的任务,以 Issue 的方式出现在上图 Project 最左边的 To Do 列之下。每天团队的 Daily 例会上,大家通过 Microsoft Teams 软件,拨入会议远程参加,由 Scrum Master 在自己的电脑上使用分享桌面将 Github Project Dashboard 投影出来,其他团队成员从 To Do 列表里选择自己当天要 work on 的 Issue.
一个 Issue 被某人领取之后,会从 To Do 列移至 In Progress 列。当开发人员完成该 Issue 需要的功能开发或者 Bug 修复,并完成本地测试之后,这个 Issue 从 In Progress 进入 Code Review & Local QA 状态, 等待组内其他开发人员摘取,进行代码审查和交叉测试。当代码审查和交叉测试都由另一位开发人员完成之后,Issue 进入 QA from Server After Merge 状态, 此时团队的质量控制工程师(Quality Enginner) 就可以开始更高级别的集成测试了。
通过 Issue 关联的 Milestone 面板,我们可以轻易监控一个 Project 的完成进度:

以上介绍了通过 Github 管理的 Issue 的一个典型生命周期,我们团队正是通过这种方式实现的项目任务管理。尽管另一款收费软件 Jira 也提供了更专业的项目与事务跟踪管理功能,在任务工作量记录,项目整体进度把控和任务执行明细显示方面更为出色,但是 Github Project 也有其亮点,那就是对 Github Issue 和 Pull Request 的深度集成,后者更是我们这种开发人员来自全球各地,横跨多个时区的全球化开发团队所看重的特色。
程序员每天除了编写代码,提交代码和审查代码之外,免不了要和其他开发人员进行各种互动,比如讨论技术问题,发布组内公告,向其他成员求助等等。
如果是比较简单的通过文字沟通即可解决的问题,我们团队的成员倾向于在 Slack 这款软件里进行文字交流。
个人认为,同大家日常生活中使用的微信相比,Slack 在软件开发领域的远程团队成员沟通中,有下列显著的优势:
很多使用微信群进行工作沟通的朋友都曾经抱怨过,微信群聊天记录仅仅保存在本地,很容易丢失。而 Slack 不存在这个问题,因为一条消息(无论纯文字还是包含了文件),一经发送,就会保存到服务器端,并且 Slack 支持了强大的查询功能。
下面是 Slack 的查询窗口,我们可以看出,Slack 支持如下几种查询方式:
Find in ec-spartacus, 意思是只在名为 ec-spartacus 这个 Channel 里搜索
以笔者为例,我是 2020年8月加入目前这个开发团队的,使用 Slack 搜索,笔者可以轻松定位到任意发生在 2020年8月之前的交互记录:只需要在 Range 里指定搜索的起始和结束日期:

就可以快速找到我需要查找的包含某关键字的交互记录:

Slack 的文本支持加粗,斜体,删除线,引用,插入代码等多种格式化选项,同纯文本相比,这些格式化效果提高了开发人员阅读文本信息的效率。

除此之外,Slack 的文本编辑器,支持种类丰富的 Emoji 表情符号,能给程序员每天单调的生活增添一丝亮色:

使用微信群讨论工作问题的朋友都有这样的苦恼:微信群里的信息流,没有层次结构的概念,所有的信息流都位于同一层级,因此很容易出现同一群里,同一时刻有若干不同主题的讨论同时发生的情况,群的使用者很难凭借阅读这些文字记录,获得每个不同主题的讨论的上下文。
Slack 引入了 Thread 的概念,来高效管理一个 Channel 内不同主题的并行讨论文本流。
一个 Thread 代表一个主题,可以包含一到多条文本信息。一个 Thread 除了第一条原始文本信息之外的其他文本信息,称之为 Reply. 当用户针对 Thread 第一条文本消息进行回复时,这些回复的消息就称之为 Reply,自动同 Thread 的第一条消息关联起来。
下图是一个例子,屏幕左边的区域显示了两条 Thread,分别包含 4 条和 7 条 Reply. 单击每条 Thread,选择 View Thread 菜单项,可以在屏幕右边的明细页面区域里,查看该条 Thread 所有的 Reply.

通过引入 Thread 和 Reply 这组具有类似父子包含关系的概念,Slack Channel 可以高效管理不同主题的文本讨论。
在 Slack App 市场 https://slack.com/apps,能查阅众多包含可以显著提高远程工作效率的开箱即用的 Slack App :

我们可以为 Slack Channel 添加这些现成的 App:

也可以自行开发符合团队实际工作需要的新 App.
比如我们团队目前在使用的一个自开发的 Slack App,如下图所示。每当开发人员有新的代码提交,导致持续集成服务器的 Central Build 失败后,该 App 就会推送一条消息到 Slack Channel 中,并且包含三个链接,分别指向失败的构建,导致构建失败的代码提交,和构建的历史信息。
有了 Slack App 这种即时的提示信息,开发人员能够避免手动去检查构建状态,从而能够更快地对失败的构建做出响应。

对于远程办公的敏捷开发团队来说,Daily Scrum,Planning Meeting,Review Meeting 这些会议都需要放到线上进行。另外,当开发人员遇到复杂度较高的问题,靠纯粹的文本信息讨论难以解决时,也需要通过语音加上共享屏幕的方式来交流。
尽管 Slack 本身也提供了语音通信的功能,但是对于在线会议,我们团队最终选择的是 Microsoft Teams 这款软件。除了在不稳定的网络连接环境下,我们测试出 Teams 的表现优于 Slack 之外,我们可以使用 Teams 的Recording 功能,将重要的会议过程记录下来,并以 MP4 的格式方便地进行导出。这些会议的 Recording 对于新加入团队的同事以及因为种种原因错过了会议的同事非常有用。

Slack 里的文本信息流虽然搜索起来非常方便,但是比较碎片化,不适合用来维护系统的、篇幅量较大的、图文并茂的知识类文章。因此我们选择了 Atlassian Confluence 用来搭建团队 Wiki, 实现团队的知识分享。
Atlassian Confluence 可以支持多用户对文档的编写,能够方便高效地创建软件研发过程中的需求文档、产品架构设计文档、项目管理文档、技术分享等文档。
其丰富的页面控件,多种类别的开箱即用的模板,基于富文本和文档源代码级别的编辑方式,使得开发人员和非技术人员都能够编写出专业的文档。

其版本管理和差异比较功能,即便在多个用户分别对同一文档进行编写的情况下,也能根据需要,轻松回溯出每一次修改的明细信息:


本文通过笔者的实际工作经验,分享了笔者所在的全球化软件开发团队,在远程办公这个领域,所使用过的一些工具和经验。虽然由于疫情以及团队成员所在地理位置的原因,开发团队的成员们不能在同一间办公室里面对面地工作,但是感谢现代日新月异的 IT 技术,通过本文介绍的这些工具,即便远程办公,我们的开发效率也没有受到太大的影响。
希望疫情能够早日彻底结束,所有开发人员都能够回归到疫情之前正常的开发工作中去。
我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>
我想用ruby编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象