[3] 作为交流的代码审查:以企业软件开发者为例
这个段落位置已不存在。请使用目录或当前章节查找内容。
保拉·比亚尔斯基(Paula Bialski)
交流是一团由思想与文化的丝缕交织而成的丰富乱麻,它编码着我们这个时代与自身的种种对峙。理解交流,就是理解远比交流更多的东西。
——约翰·杜伦·彼得斯(John Durham Peters)
2017 年 8 月初,一名谷歌员工发布了一份题为《谷歌的意识形态回音室》(“Google’s Ideological Echo Chamber”)的内部备忘录。我们大多数人都还记得这份备忘录的内容,也记得它在硅谷内外的科技圈引起的轰动:备忘录列举了种种理由,论证谷歌的多元化举措从根本上就是错误的。其中有一段尤其让我——一名研究企业软件开发者的民族志学者——觉得具有特别的误导性:“谷歌试图通过结对编程和更多协作,让软件工程变得更加以人为本”,然而这一举措从根本上受制于“某些岗位和谷歌本身能够以人为本到什么程度”(Motherboard, August 8, 2017)。这份备忘录传达的信息之一,是科技公司应当“淡化共情”。就软件开发者而言,在构建技术系统时,谁又需要共情呢?
我承认,这份备忘录围绕科技行业的性别偏见、围绕女性擅长什么和不擅长什么、乃至围绕男女之间的一般差异本身,掀起了一场旷日持久的争论;但为了不偏离主题,我将把这场争论搁置一旁,而聚焦于文中的一个论断:交流与共情不应被强调为科技从业者的优势。
数字文化中的交流是多面向的。我们知道,它可以发生在人与人之间,以数字技术为中介。它可以发生在人与机器之间(例如我们录下自己的声音或在屏幕上打字的方式)。它也可以发生在机器与机器之间(正如芬恩·布伦顿[Finn Brunton]在本书第一章中所精彩阐明的那样)。
谷歌备忘录的作者所忽视的是:软件或许正是数字媒介与人类社会性真正交织在一起的最复杂的例子之一。团队会议中人的共情,与合并由不同人分别编写的代码片段,是并存的。在本章中,我想把镜头拉近,聚焦于一家大型软件开发企业的种种过程,揭示人与机器的共处与共创如何调用了多种交流模式。在前面的章节中,布伦顿通过追问技术实体之间那种类似外星的对话来探讨交流与数字技术——更多地关注机器之间的交流;邦茨(Bunz)则考察了这些技术实体是如何被设计来召唤我们这些用户的,以及这类设计(孩子气而居高临下的)对我们产生了何种影响。本章将把你——读者——带入一个民族志田野,去看看机器之间、人与机器之间、以及构建机器的人与人之间的交流是如何展开的。我希望,这样做能为你提供一个扎根于实际的例子,说明数字文化中交流的多面向性质。
Charlie
我大约是两年前在柏林新克尔恩区(Neukölln)Noah 举办的一次电影之夜上认识 Charlie 的。我们都坐在 Noah 家客厅的沙发上,谈论着他们的软件公司——后来我正是在那里开始了长期的田野工作项目。这家公司专注于开发地图与导航软件,约有六千名员工,其中一千人是形形色色的软件开发者。我和 Charlie 一起在“导航”团队工作,这个团队的工作内容之一是如何找到从 A 到 B 的最佳路线(这个问题远比听起来要难)。
我原本想当然地以为 Charlie 是个开发者。他也确实演得像。他谈起代码、漏洞、故障和更新来头头是道,我不知怎么就断定他对编程懂得很多。直到最近几周,我开始在他的部门工作时,才察觉到有些不对劲。在一次产品负责人[1]会议上,他也在场,就坐在桌边。他在会上非常投入,发言踊跃,一点也不像开发者。我起初以为他是首席开发者,或者只是某个热心到愿意参加产品负责人会议的人,直到我意识到,他其实就是一名产品负责人。这种混淆——即我并不确切知道一名员工究竟在做什么——是相当常见的,即便对任何一名普通员工来说也是如此。这既是由于他角色的流动性(他自己都不清楚自己是产品经理、产品负责人、错误管理员,还是其他若干可能职位中的某一个),也是由于他所掌握的技术知识的多寡(他对他们正在构建的软件系统的了解,处在一个介于懂技术和完全不怎么懂技术之间的灰色地带)。
Charlie 有着最为考究的英国口音。每次他一开口,这口音都让我吃惊。这或许是因为这家软件开发公司雇用了来自五湖四海的各国员工,在办公室里形成了一种“全球语”(Globish)的嘈杂声响。偶然听到一位真正以英语为母语的人说话,反而显得颇为奇特。而他说的那种英语,是一种“欢乐满人间”(Merry Poppins)式的英语,会用上诸如“I’m just taking care of some bits and bobs”(我正在处理些零零碎碎的事)和“we’re far away from everything being tickety boo”(离一切妥妥帖帖还差得远呢)这样的句子。尽管他总是一副乐呵呵的样子,Charlie 却总在解释说自己压力很大,肩上的工作很多。
Charlie 也非常理解我作为民族志学者的角色,跟我说话时语气温和,对我所做的事情抱有真诚的兴趣。那天下午,在我几次问起他正在扑救的那场“火”之后,他提出给我看看他在忙什么。他拿起一个咖啡杯和他的笔记本电脑,我们走到楼梯旁边的公共区域,那里摆着漂亮的木制野餐桌。他打开笔记本电脑,向我展示一个名叫 Gerrit 的软件界面——一款免费、开源、基于网页的代码协作工具。[2] Gerrit 显示着一份合并列表——所谓合并,指的是对代码库的更新或添加。这份列表包括更新的类型、更新者,以及更新的状态(通过还是失败)。在合并过程中,代码会被自动测试,各种问题都可能出现。我了解到,作为错误管理员(这是在他产品负责人的工作之外额外分派给他的一份工作),他的职责就是监控这些更新,尤其是在生产的最后一周。那天正是“功能完成日”(feature complete day)——意味着新软件版本的所有功能或改动都应当完成并合并进代码库。合并并不会天衣无缝地进行。Charlie 预计会有什么地方出错,所以在这样的日子里,他总是开着电脑,监控每一次合并的进展。
他看着笔记本电脑,开始指着一列红色和浅蓝色的条块,它们标示着合并过程的状态。每一个条块都是属于某位开发者的一“块”代码,这位开发者把这段代码推送进了构建的其余部分之中。条块会根据代码是否与其余代码成功合并、或者说是否能与其余代码协同运行而改变颜色。我看着其中一个变红并显示“merge error”(合并错误)的条块,问他:“那么,这是不是有点像把两块拼图拼在一起,但有人把其中一块拼图的一只‘胳膊’剪掉了,所以它没法像原本设计的那样嵌进另一块?”
Charlie 解释说:“你得想象有一份谷歌文档(Google Doc),两个人在同时编辑。同一时间,一位编辑修改了另一位编辑正在处理的内容。当他们合并这两份文档时,各自的改动就会发生冲突。”
Charlie 解释道,这就叫作合并冲突——即一位开发者合并的某个改动或任务,影响到了另一位开发者合并的另一行代码。我们俩都专注地盯着屏幕上一长串约十五个任务,其中一些旁边标着“merge conflict”(合并冲突)。在接下来一起坐在那里的十五分钟里,我能看到他一直专注地监控着这块屏幕。他解释说,每当一位开发者想把自己正在做的东西合并进主代码仓库时,服务器大约需要四十分钟来测试合并后的代码。在监控这块屏幕时,Charlie 等待的是一位开发者、服务器和代码库向团队其他成员(包括他自己)传达关于代码状态的某种信息。而除了合并冲突之外,还可能出现其他冲突。
我注意到自己开始对程序员如何协同工作有了一点点感觉。而他们协同工作的方式,是通过各种形式的交流、对交流的回避,或对交流的分析。“交流”这个词在办公室里不断飘来飘去。如果以 Charlie 为例,仅仅是与他互动的这几分钟,就展示了软件开发环境中发生的种种交流:言语的、非言语的、基于机器的、人与机器之间的,或基于团队的。Charlie 的英语与他同事的英语之间的差异构成了一个交流问题。Charlie 的客户表达他们需要 Charlie 负责的功能为用户做些什么的方式,构成了一个交流问题。一位开发者的代码与代码库进行交流的方式,构成了一个交流问题。两位开发者在同一款软件上工作的种种方式,构成了一个交流问题。
展开的时刻
数字媒介技术如何影响社会,社会又如何影响数字媒介技术——这一问题最好在这类难以把握、总是滑溜溜、总在变化的展开时刻中加以研究。我讲述这段田野工作的开场轶事,目的是向你简要介绍软件开发所涉及的高度复杂的交流壮举。夹杂在服务器、腼腆、全球语、软件标准、测试标准与客户期望之间的,是在同一项目上协作的人们。这种协作包含着人与机器的深度交融。正如梅赛德丝·邦茨(Mercedes Bunz)在本书她所撰写的章节中所指出的,数字交流需要在不止一个层面上加以概念化,因为软件总是以不止一个界面在运作。这些界面存在于机器与机器之间,以及机器与用户之间。正如我将要指出的,还存在另一个层面,即代码的编写者(软件开发者)与其他软件开发者之间的层面。本章的总体目标,是通过为企业编程环境中出现的各种交流形式绘制一幅相当描述性的地图,来回应数字文化中的交流问题。借此,我旨在准确解释软件开发是如何作为一种实践被组织起来的,以及交流如何嵌入这一实践之中。我将展开的这种交流涉及若干物与人。这种交流发生在:
- 机器与机器之间
- 程序员与机器之间
- 程序员与组织之间
- 程序员与程序员之间
作为人与机器持续不断的聚合体(assemblage)的一部分,这三方——组织、生产者与软件的物质阻力——在迭代过程中相互作用,共同塑造着数字媒介;而数字媒介从来不只是过滤器,用约翰·杜伦·彼得斯的话来说,它们是“承载并传达意义的载具”(Peters 2015, 2)。于是,方法论上的挑战就在于理解所有这些部分如何彼此交流,并在这些关系展开的时刻对其加以观察。
在本章中,我主要借助在对企业软件开发者的持续研究中收集的民族志数据。2016 年 8 月,我开始在一家总部位于柏林、拥有六千名员工的大型软件公司 BerlinTech 进行组织民族志研究。在本章发表之时,我已在这家公司沉浸了八十多个工作日——参加会议,观察开发者开发软件,并在办公室厨房里、午餐时或上下班的长距离步行途中进行正式和非正式的访谈。我研究的总体关注点是揭示技术中介的社会性。我将自己的研究置于文化理论、社会理论与媒介理论,科学技术研究,软件研究,基础设施研究,以及软件开发者民族志的框架之内。
正如我在前文提到的,这家公司为第三方——例如社交网站或各种需要嵌入地图的应用——制作关键的地图基础设施。我曾在前端应用开发者中待了两个月,他们构建公司的“消费者”产品——即用户下载到智能手机和台式电脑上使用的应用——目前我则身处后端开发者之中,他们构建车载导航系统并维护路线规划基础设施。我这个民族志项目背后更大的动机,源于这样一种信念:研究平凡的、相当“普通”的软件开发者,能让我们更接近我们的数字基础设施运作的方式。研究日常的软件开发者——那些构建着支撑我们的移动、我们的社会性、我们的消费(不一而足)的基础设施的大批工程师——就是研究人与机器之间的交流在我们日常的、数字联网的生活中如何运作、又如何变化。
在本章中,我尝试剖析开发者之间如何彼此交流、机器如何与开发者交流,以及那些为协助机器之间(代码与代码之间)的交流而发明出来的不完美工具(比如代码审查软件)。
本研究旨在:(1)对数字社会性形成一种在民族志意义上丰富的理解,它(2)聚焦于展开的时刻;(3)立足于开发者、他们构建的代码、以及他们用以交流的软件之间的一种三模态交流方式;并且(4)最后但同样重要的是,考察这三方之间的相互关系。当然,我也意识到,我的田野中还有其他发生交流的场所,尤其是在设计师、管理层与用户之间。程序员使用各种协作管理工具,有些是专门为开发者自身设计的(例如代码审查系统和工作流系统),有些则面向整个劳动力群体(例如电子日历、内联网系统和在线电子表格)。为了本章的主题,我将开发者交流的案例研究收窄到一个工具——Gerrit——它严格关涉一种被称为代码审查的实践。
尽管已有民族志研究考察程序员协作的种种复杂方式,但从交流这一概念出发,对企业中的编程实践进行民族志描绘的工作尚未有人做过。这些话题中的许多在软件工程文献中也已得到广泛讨论,但并非从民族志的角度。
描述 Gerrit
在田野中工作了两个月之后,我的田野日记给我留下了一些挥之不去的问题。我的田野的幸运之处在于,我的报道人并不是一个与世隔绝、与外界断绝联系的部落,而是软件开发者——你可以想见,他们常常坐在电脑前,常常开着各种聊天系统(Skype、Spark 或 Slack),可以即时联系上。这给了我一种永无止境的田野进入感——仿佛我有一条通往田野的生命线,在我离开办公室之后也几乎从未中断。
话虽如此,本章由我在两年时间里收集的各种数据片段构成:进入田野之前的一些田野笔记,田野工作期间收集的笔记,以及最近通过各种聊天应用与报道人进行的在线交流。
我和 Charlie 之间的对话说明了代码审查系统的基本原理:它建立在一种同行评审的文化之上。我目前研究的这个由一百名开发者组成的团队,为导航系统创建路线规划基础设施(也就是计算从 A 到 B 的最快或最优路线的方式)。这些开发者又被分成若干子团队。我直接与之同坐的是电动汽车(EV)团队,由五名开发者组成。他们需要共同解决一个电动汽车特有的路线规划问题:如何为一辆每隔几个小时就必须确保找到充电站的汽车优化行驶路线?在他们的项目最终完成并被部署到车载系统之前,他们的工作会被拆分成许多小的子任务。在项目开始之前(即项目的冲刺[sprint]周期),这组开发者会和他们的经理或产品负责人一起坐在一个房间里,确定完成项目所需完成的子任务。这些子任务被称为工单(tickets)。然后,第二天,每位开发者领取一张工单并开始着手处理。以 EV 团队为例,一张工单可能是,比如说,把电动汽车充电站的库与路线库进行匹配。Maria 会领取这张工单,完成工作,然后把它上传或“推送”(push)到 Gerrit 代码审查系统以供审查。她的同事随后会给她打一个介于 +2 和 −2 之间的分数(其确切含义我将在后文解释)。
我的主要报道人之一 Noah 解释说,代码审查[3]的主要目的,是集体监控一位开发者试图上传到其团队主代码仓库中的每一行代码,是否真的与其他团队成员所编写的代码相契合、能够协同运行。这里有两条主要的交流线索在起作用:一条是开发者之间的交流,既有线下的(例如,开发者常常从台式电脑屏幕上方探出头来,冲着同事喊:“能帮我审一下代码吗?”或者“嘿,你为什么给了我一个 −1!”),也有通过代码审查软件进行的(即以代码审查的形式);另一条则是技术系统自身之间的交流,例如,Noah 的代码行必须与另一位开发者的代码行“对话”,而这些代码行的集合在整个系统中运行时,也可以说必须彼此“对话”。虽然我将在后面的一节中更详细地讨论,但我在此只想强调,在这一过程中,以正确的方式、例如使用正确的语法进行交流,是极为必要的。
在这片田野里待了一年之后(而我对软件如何构建只有潜在的了解),我逐渐认识到,代码审查系统是企业软件环境中固有的一部分——是某种生产流水线中至关重要的一环。它之所以必要,是因为一款软件产品必须在一定的时间框架内交付给用户,软件公司才能在市场上保持竞争力,而交付出去的东西还必须真正能用,不能有重大漏洞或故障。由数十名开发者组成的团队构成的大规模企业软件环境,也需要代码审查系统,以便在大量软件更新的情况下让协作(和交流)变得更容易。Michael 是一位曾在 BerlinTech 工作、后来跳槽到一家小型初创公司的开发者,他解释说,BerlinTech 的代码审查系统是一个很好的例子,说明大公司是如何处理审查流程的。换了工作之后,Michael 和他那个两三人的团队并没有审查流程;相反,团队成员在开始工作之前通过交谈进行沟通,就某件事达成一致,并在整个开发过程中通力合作。在他的情况下,把一项改动合并进整个系统更多地成了一种形式,而不是一种必需。
在非企业的语境中,软件开发者在没有严格截止日期的小团队里工作,他们可能会采用一种非正式的代码审查系统——互相给出反馈,就像一支乐队的乐手们互相交流如何让一首歌变得更好的诀窍和技巧那样。但在企业的大规模软件项目环境中,代码审查系统是一条形式化的、基于软件的装配线。此外,代码审查系统既是监控进入系统构建的代码的一种方式,也成为高层管理者用来监视程序员实际在做何种工作的监视工具。而正如我将在本章后面的一节中解释的,它还成为程序员用来监看其他程序员的“反向监视”(sousveillance)工具。
在 BerlinTech,Gerrit 只是软件开发者所使用的众多代码审查系统之一。公司本身有一千多名开发者,开发者之间的交流以多种方式进行,包括通过代码审查系统,也包括面对面的、每日十五分钟的站会(standup meetings),午餐时间,其他协作会议,以及各种各样的内部平台(指由公司建立、仅供办公使用的平台)和外部平台(指由团队成员建立、用于办公及其他事务的平台)。其中一些(这份清单绝非详尽无遗)包括:公司的内部聊天系统 Yammer(其社交互动功能有限),这是公司处理一切工作相关事务的“官方”内部交流工具;以及 Cisco Spark、Slack 乃至 Skype 聊天之类的协作软件。每个团队根据其所构建的东西,使用不同类型的交流工具,甚至使用不同类型的代码审查系统。对于和我共事的开发者来说,跟踪这些交流渠道是一项令人眼花缭乱、而且常常令人沮丧的任务。有些协作工具是自下而上出现的,由协作者自己发起;有些协作工具则是自上而下、由公司管理层发起的。虽然社会性在这些会议中——在特定的工作小组里,或在各个平台上,连同其各自的特性与权力政治——涌现的方式,与此处交流的主题相关,但为了将焦点更集中地保持在代码审查工具及其内在的交流上,我将不去讨论它们。
回到 Gerrit:这是一个免费、开源的代码审查系统,最初由谷歌编写——而且它并不是 BerlinTech 使用的唯一系统。正如 Noah 所解释的,许多不同团队使用不同代码审查系统的原因,“主要是因为并不是每个人都完成了向 Gerrit 的过渡。有些人偏好其他方式,因为他们的项目很小,或者他们不知道 Gerrit,又或者他们就是不喜欢它”(田野笔记,2017 年 6 月)。
一位团队负责人 Simon 向我解释说:“Gerrit 是我们文化的关键组成部分。如果一个开发者有一段代码,他就把它上传到 Gerrit。你们一起协作,促成一次提交。这不是一场写代码的竞赛,而是努力一起工作,努力传递信息和知识。”(田野笔记,2016 年 8 月)
另一位 iOS 开发者(负责构建 iPhone 应用)Sebastian 用树的隐喻来解释代码审查如何运作:“它就像一棵树,每个写代码的人都在这棵树上添加一根树枝。为了合并他们的改动(树枝),必须先做一些测试。只有经过这些测试之后,树枝才能真正被纳入,成为这棵树的一部分。”(田野笔记,2016 年 8 月)
借用 Sebastian 的隐喻:当一名程序员向 Gerrit 添加一根“树枝”时,其他开发者都能看到它,而这段代码要等待至少两名开发者——外加一个自动化机器人程序(bot)——批准。在 BerlinTech 的前端团队,开发者被鼓励每一到两小时查看一次新进的审查请求,不过一位开发者告诉我,这条规则“反正常常没人遵守,但你的工作确实每二十四小时就会被审查一次”(田野笔记,2017 年 6 月)。Gerrit 系统中的一次审查有五个变量:
−2: Do not submit
−1: I would prefer that you didn’t submit this
0: No score
+1: Looks good to me, but someone else must approve
+2: Looks good to me, approved
(即:−2:请勿提交;−1:我希望你不要提交这个;0:不打分;+1:在我看来不错,但必须由其他人批准;+2:在我看来不错,批准。)
网页开发者 Michael 有一次半开玩笑地坦白说,每逢周五,当他想下班跑去喝杯啤酒时,他就会飞快地过一遍代码审查系统,给所有等待审查的工单统统加上“+2、+2、+2”(田野笔记,2016 年 8 月)。这其中有多少是真的,是个谜;但它暗示了诸如疲劳、天气、一天中的时段以及开发者彼此之间的关系等变量,是如何被计入他们的评分之中的。
交流模型
读到这里,你——读者——或许已开始理解代码审查系统的总体用途,以及 Gerrit 运作方式的一些基本原理。如果我们剖析交流在这一系统中如何运作,就可以开始看到有三种交流模型在起作用。首先,代码审查系统中介着人与人之间的交流,在这里就是编写代码的程序员之间的交流。这种交流模型发生在两个人之间,是对话性的、互动性的。就 Gerrit 而言,开发者基于一种互惠文化相互审查:如果某人审查了你的代码,你就有义务反过来审查她的代码。如果一名开发者请求代码审查,获得审查之后却拒绝回报、今后不去审查别人的代码,这种行为就会被视为反社会的。此外,代码审查也是在对话中完成的。例如,一名开发者可能会写道:“说实话,这整个解决方案看起来有点……凑合(hacky)。你能不能描述一下它是怎么工作的,以及为什么它是一个正确的解决方案?”[4] 在得到问题的答复之前,这位开发者不会批准“提交者”(committer,即提交代码更新/解决方案以供审查的程序员)的代码。代码审查是提交者与审查者之间持续的来回往复,并且必须达到某种程度的相互理解。
此外,开发者两人之间的互动往往通过 Gerrit 这样的系统会更容易一些,因为它把面对面互动的社交压力降到了最低,这或许并不令人意外。Michal 回忆起一种情形:“有一个审查里有 20 多个补丁[修复],评论区里有大量讨论,只在两个家伙之间进行。在我看来,对他们来说,聊一聊(其中一个人是远程工作的)、商定一个解决方案、然后用一个补丁修好,要容易得多。但他们俩都相当内向,所以我猜他们‘更愿意’通过 Gerrit 来处理。”(田野笔记,2017 年 7 月)
正如彼得斯(Peters 1999, 23)所指出的,这种交流模型有时也被界定为“亲密者或同事之间开放而坦诚的谈话。在这里,交流并不仅仅意味着谈话;它指的是一种以亲密和袒露为特征的特殊谈话”。Michael 还补充说,在代码审查期间交流的最佳状态下,两位开发者之间会共享一种“尊重”:当审查者就解决方案提出问题时,提交者会尝试回答这些问题,并修复审查者提到的问题(田野笔记,2017 年 6 月)。这种尊重可以在两位开发者之间形成一种亲密感,两人通过他们的代码审查过程建立起某种融洽关系。
因此,在这种情况下,交流是互惠的,发生在两位开发者之间,并涉及一位开发者向另一位提出的明确讨论和问题。我在前面一节中提到的评分系统(+2、+1、0、−1、−2)也是开发者之间一种更为隐含的交流系统的一部分,每位开发者对每个分数的含义可能都有自己主观的理解,而不会向另一位开发者明确描述这种含义。这类交流也可以意味着一种“观念、思想或意义的……转移或传递”(Peters 1999, 15)。
我问 Michael:“好,让我理一理。如果 Mike 的代码里有一小块是错的,我就不能给他 +2,于是我在某个代码块上写评论,然后 Mike 打补丁,结果还是错的,于是我再评论一次?”Michael 回答说:
嗯,你也可以给——这取决于审查者的风格;我的风格是,“即使有点小问题,我也可以给你 +2,只要我把它标出来,而你以后会改”,因为我做代码审查的主要目的,是让对方将来成为一个更好的程序员。但我知道有些混蛋审查者,看到一小段很糟的代码……比如说,一个他们不认同的变量名,因为它描述性不够,他们就会给提交者 −1,让他们去改。换作我,在那种情况下会给他们 +2,并说“以后把变量名起得更有描述性一些”……但我可以想象另一方会说:“我在乎代码库,我对审查很严格,但另一些人[比如 Michael]放任糟糕的代码通过,还以为别人会去修好它。”而一个“懒惰的审查者”,我猜,会给代码打个 −2 却不解释哪里错了。(田野笔记,2017 年 6 月)
在这个例子中,Gerrit 的评分系统对不同的开发者而言呈现出不同的标准。所谓的混蛋开发者会因为一名开发者忘了给变量提供足够的描述而给出 −1,而 Michael 则选择对这种描述不足网开一面,以鼓励这位开发者下次改进。技术标准在实践中呈现出不同的含义;那些理解 Michael 用他的 +2 所传达的意思的开发者,在收到他给的 −1 时,会格外恼火或惊讶。
广播
第二种模型是广播式的交流模型:代码审查不再是二人之间的互惠交换,而成为一种一对多的表演性行为。开发者的审查本身向一群(通常是)不特定的他人广播着意义。
例如,Gerrit 的运作方式是:每一次审查都会标注审查者的名字。在 BerlinTech,我曾参与的一个开发团队被期望每小时至少进行两次审查。虽然这一标准并没有被坚持下来,但一些开发者会仅仅为了完成每小时的配额而去做代码审查。请注意,此时无论是代码审查评论的内容还是代码审查本身的评分都不重要。相反,单单这个姿态本身就向他人传达了:“我在审查,因此我是这个团队的一员。”例如,如果 Noah 进行了一次审查,他就是在向他的开发者同事以及他的主管传达:他确实是一名有团队精神的成员,确实关心团队项目的质量。
另一方面,我观察到,一些开发者把代码审查当作他们拖延日程的一部分,因为它简单而且“不用动脑”。进行代码审查有助于向团队和老板传达他们正投入地工作着,而在实际上,他们只是在做这种“不用动脑”的工作,以逃避更具挑战性的任务。于是,审查者并没有与提交者进行有意义的对话,而只是飞快地、不假思索地把审查一个个点过去。
正如我前面也提到的,代码审查成为高层管理者用以监视程序员实际在做何种工作的监视工具。Gerrit 的设计方式使得工作对公司里的任何人——包括管理层——都高度透明。它也成为一种反向监视工具——一种让同事们隐含地相互监看彼此工作的方式。仅仅是一位经理在 Gerrit 系统中的在线在场,以及一位同事的在场本身,就向其他开发者广播或传达着:“我在这里,我在看着你。”
交流的代码
代码审查系统中存在的第三种交流形式,是代码片段之间的交流;代码片段本质上是一系列命令或解决方案,它们向一台由其他命令或解决方案构成的机器传达意义。代码可以被视为一种能动者(agent),指挥着计算机的运行。
我前面对交流的两种界定都涉及人的交流。但就代码审查而言,代码必须与其他代码“对话”才能运行。彼得斯(Peters 1999)指出,虽然交流可以意味着某种交换或转移、涉及某种互惠,但这些因素并不一定要发生在人与人之间:“交流可以意味着类似于两个分离的终端成功连接起来的东西,正如电报业中所说的那样。在这里,仅仅是送达——就像投递信件或电子邮件那样——就足以构成交流。”(16)在本书中,我的合著者芬恩·布伦顿在讨论机器之间的这类交流时,对克劳德·香农(Claude Shannon)做了精彩的分析。
为了说明这在代码审查系统中如何运作,请看一段对话节选:一个开发者团队正在讨论他们为某网站开发的一项功能中出现的一个小小的功能故障。这段对话截取自他们之间的一次 Skype 对话(如前所述,开发者经常使用各种聊天系统来讨论他们的问题):
nina: 有一个失败,我觉得不是你造成的,@John——“Scenario: Clicking on map markers and PDC links”(场景:点击地图标记和 PDC 链接)……我检查 Michal 的那次提交时,还是看到它失败。
john: 嗯,当前这次运行是我的提交。看看那之后还剩下什么吧,不过是的,也值得看一看
nina: @Piotr,我看到“And I expand the place panel contents if not expanded”(并且如果地点面板内容未展开,我将其展开)这个步骤是你加的。我在想,你做的改动是不是“Scenario: Clicking on map markers and PDC links”失败的原因。
在这个例子中,John 提交了一项改动(通常称为一次 commit 或 submit),涉及一个侧边面板的功能,而这一改动正影响着他们网站上地图中的各种链接和标记。在这个例子中,John 那次提交里的代码没有与 Piotr 那次提交里的代码形成交流。或许这段代码有一个语法错误——这可能意味着,由于这个错误,这行代码没有与其他代码合并或交流。人类即使在别人说话含糊不清或口齿不清时,或者当一个词是用另一种语言说出时,也能推断出意义;但与人类不同,当一台机器的各个部分通过代码彼此“对话”时,代码必须使用正确的语法来编写。可以说,代码审查过程的主要目的,是让人类(程序员)协助机器(一个应用构建的各个部分)完成它们的交流过程。
代码通过这些合并过程与其他代码交流。我前面提到的后端开发者 Maria 这样解释代码如何互动:“是的,我们总是在弄坏彼此的东西。你所创建的东西会与别人正在构建的其他代码交流。而我们所有人都在同时做这件事。这就像盖房子。盖房子的时候,水管工先做点什么,然后是木匠。这通常不会同时进行,因为他们的工作会相互冲突。但我们确实是在同时做事情。而它确实会冲突。”
人们可以想象一座巴别塔,代码在其中与其他层的代码相互交流。尽管每一行代码、每一次提交都可以追溯到创建它的作者,但即使在开发者离开、休假或睡觉时,代码也必须与其他代码交流。正是这种交流让机器(就我所研究的开发者而言,是一个路线规划引擎)活了起来。
技术系统是极其社会性的。代码审查系统建立在某种看似应当是机械的东西之上,却是一个高度多变的交流过程,这既是因为其技术局限,也是因为在它所处的环境中发展出的交流文化。
理解开发者如何通过代码审查系统彼此交流,可以揭示一个技术系统如何构造合作、交流的标准如何形成,以及人与人之间和人与机器之间交流的种种特异之处。它可以帮助我们理解数字媒介整体上如何影响交流。理解技术的生产者和设计者如何创造他们的产品,可以揭示构造并决定技术设计的文化、政治与经济动机。理解软件的物质阻力与黏滞性,理解它的漏洞、故障与技术依赖,有助于我们理解数字媒介技术本身的某些属性。
本章聚焦于一个案例研究:企业软件开发者中的代码审查过程。我这样做是为了理解数字文化中的交流可能呈现的种种细微差别与形式。虽然我在此提出的交流模型绝非详尽无遗,但我聚焦于程序员与程序员之间的“作为互动的交流”、程序员与组织其余部分之间的“作为广播的交流”,以及“代码之间的交流”——即代码被视为与其他代码之间的一种互动过程的方式。我希望,这一分析能让你——读者——更接近于想象(1)机器(编译器、数据库、处理器、内存、服务器、云)、(2)程序员,以及(3)程序员与机器都在其中运作的基础设施,这三者之间的交流性相互关系。
参考文献
Peters, John Durham. 1999. Speaking into the Air: A History of the Idea of Communication. Chicago: University of Chicago Press.
Peters, John Durham. 2015. The Marvelous Clouds: Toward a Philosophy of Elemental Media. Chicago: University of Chicago Press.
