写点什么

结对编程简介

  • 2015-06-02
  • 本文字数:6233 字

    阅读完需:约 20 分钟

结对编程简介

一个由聪明能干的开发者组成的敏捷团队正在努力完成交付。他们遇到了一些意料之外的缺陷,正在努力修复生产环境中发现的缺陷;前端开发的工作量比后端开发更大,因此当前端开发者挣扎着试图跟上进度时,后端开发者反而处于无所事事的状态。可能他们需要更新控制器系统,但是 Brian 是唯一一个能够看懂控制器代码的人,不幸的是他现在正在忙其他事情。这个场景是不是很熟悉?结对编程可以有效地解决这些问题并给这个煎熬中的团队带来更多好处。那么为什么很多团队不进行结对编程呢?

《Pair Programming Illuminated》一书中,Laurie Williams 和Robert Kessler 曾断言:

我们发现很多人不愿意采用结对编程——这需要改变现有习惯并且具备更强的沟通和协作能力……我们知道,如果被强迫采用结对编程,有些人宁可选择辞职。[1]

让团队适应结对编程是一件很棘手的事情,那怎么做才能让你的团队更容易接受结对编程呢?

问题到底出在哪里?

首先我们来思考一下为什么结对编程很难落实,以下是一些原因。

1. 对于团队来说这是个很大的变化

很少有工作实践能像结对编程这样对团队造成巨大影响。在传统的工作中,开发者会“进入状态”:带上耳机打开音乐;手边就是咖啡因饮料和零食。大部分开发者都不能适应在工作中和同事进行大量沟通,他们需要一段时间来适应对话状态!

2. 精神高度集中

这是结对编程有效的秘籍之一:专注、专注、专注!如果你正在结对编程,那就不可能查看 Facebook、浏览网页或者回复收件箱中刚收到的邮件。

3. 疲惫

结对编程需要的专注和紧张程度高于大部分人的日常工作强度。结对编程会把你稍微推离舒适区并锻炼你的专注能力。但是无论你多么擅长结对编程,都会到达极限。Kent Beck 写道“绝大多数程序员每天的结对时间不能超过五或者六个小时。”[2]

4. 大部分成员都没有完全具备所需要的软技能

人类不是生来就有同理心和超强的社交技能的。如果你在工作中和同事交流很少,那你在这方面的技能可能就会弱一些。想象一下,和一个缺乏社交技能的人紧密合作一整天是什么感觉。或者,想象一下作为新手和一个不耐烦的老手一起编程的感觉。结对编程的两方都需要很高的耐心和同理心。

5. 所有的改变都很困难

所有的变更管理专家都会告诉你——要求他人改变做事的方式会立刻激发恐惧反应,人们试图理解改变对他们的影响。

既然如此艰难,为什么我们还要改变呢?

接下来,我们会讨论到底是什么支撑你克服这些障碍。结对编程有很多好处,我们来看看你能获得什么回报。

  • 更高质量的代码

    如果每行代码在编写的同时都在被审查,代码质量就会急剧提高。由于审查者完全参与到代码的编写过程中,因此代码审查的质量也会提升。类似 Alistair Cockburn 和 Laurie Williams 所做的研究,其他研究也对比了结对编程和单人编程产生的代码,发现结对编程产生的代码缺陷更少,设计更良好。在 Cockburn 和 Williams 的研究中,结对编程产生的程序“普遍比单人编程产生的程序短 20%,这表明前者的代码更优雅、可维护性更高。”[3]

  • 更高的“巴士指数”

    “巴士指数”是一种表示团队的知识、经验和代码拥有权共享程度的方法——如果有人离开(也就是被巴士撞了),我们中有多少人可以顶替他的位置?如果你的团队巴士指数是 1,那就意味着团队中某人是不可或缺的——如果他突然离开,你的项目就有大麻烦了。结对编程可以让你的巴士指数等于团队成员数——每个人都可以在任何时间接手任何任务。

  • 更强的团队凝聚力

    和同事整天在一起工作可以让你更好地了解他们,从而更加理解他们,增强团队凝聚力。

  • 更高的工作满意度

    大多数程序员最后会发现和同事分担编程任务可以让自己更轻松——当他们习惯之后。他们不再需要自己承担所有责任,并且可以互相帮助。

  • 更高的效率

    是的,没错,结对编程比单人编程的效率更高。这确实有点违反直觉,两个人写一份代码怎么会比两个人分别写两份代码更快呢?

    1. 当你和其他人一起讨论的时候,可以更快地解决问题。队友会帮助你把精力聚焦在问题上,并且能帮你搞定一些你自己不确定或者不熟悉的领域的问题。你花费在常见问题、研究和查找代码语法上的时间会减少。
    2. 更少的缺陷意味着更多时间用在创建新特性而不是修复 bug 上!因此,效率更高。在上面提到的 Williams 和 Cockburn 的研究中,结对编程花费的人时只增加了大约 15%,远小于从修复 bug 上节约的时间(bug 也减少了 15%)。因为在代码编写完成之后修复 bug 需要花费更多的时间,因此编写同样代码,结对编程的总时间更少。
  • 更容易维护的代码

    当两个人一起编程时,他们需要在方法、数据结构甚至是变量和函数名上达成一致。这会减少其中一方随意编写代码的可能性。结对编程者也更有可能选择更加标准的语法、格式以及类似 TDD 这样的最佳实践。

  • 更有助于成员发展

    结对编程是软件开发中学习新技能最快的方法之一。除了语言和技术,结对编程者还会共享很多其他技能,从解决问题的思路、算法到键盘快捷键和调试技巧。没错,你可以通过阅读他人的代码来学习他们解决问题的方法,但是和他们一起工作可以让你更加清楚他们的思考过程。

  • 更高的团队灵活性

    能让人们快速地掌握技术和编程领域意味着他们可以以最小的代价从一个团队转移到另一个团队。这种灵活性对所有人都有好处。如果一个项目突然需要外援,负责人可以从其他团队“借”资源并让资源快速发挥作用。类似地,如果开发者想学习一些新东西,或者想改变工作节奏,可以申请转移到其他团队。团队可以以最小的损失来满足这些申请。

  • 更少的会议

    如果团队成员整天都在和其他人沟通,信息就可以快速流动,因此很少需要用会议来讨论事情。这对于大部分开发者来说都极具吸引力,比起坐在会议室讨论,他们更喜欢实际操作!

读到这里,希望你已经充分意识到结对编程的价值。当你和其他人讨论结对编程的时候,可以直接引用这个列表中的内容。一定要把这个列表摆在最显眼的位置,遇到困难的时候就提醒自己回报是什么。

所以,如何进行结对编程?

下面我会介绍一些减轻痛苦的方法,能够帮助你更好地推行结对编程。当你向开发者们推行新工具或者新技术的时候,要根据实际情况选择合适的方法,结对编程也一样。首先我们来看看 Gina Green 和 Alan Hevner 的研究。

Green 和 Hevner[4] 研究了为什么优秀的编程工具和技术经常会被程序员拒绝。调查了企业软件的开发者之后,他们总结出三条推行新技术或者新工具的准则:

  1. 让他们自己选择何时使用

开发者希望能够自由决定结对编程的时间。千万 * 不要 * 命令或者强制他们结对编程。如果你这样做,他们会很不高兴、不爽、不理睬你,甚至会反抗你。结对编程是优秀软件开发者的思想结晶,并不是源于项目负责人或者流程控制专家。成千上万的程序员在看到结对编程的好处之后会自愿地接受它,这是唯一一种真正可行的结对编程推行方式。
2. 指导他们正确地进行结对编程

建立清晰明确的结对编程标准。结对编程并不是两个人坐在一起,一个人编写代码并偶尔问另一个人问题。结对编程的意思是两个人要非常专注于同一段代码或者同一段思想,同时只有一个人打字。你需要向团队成员介绍如何正确进行结对编程,比如:

  • 让稍差一些的队友“主导”编程,即使他们需要很多指导。
  • 共享控制权——两个人都能控制键盘和程序设计。
  • 意见出现分歧的时候要有礼貌地讨论。
  1. 鼓励他们(尤其是作为他们的领导!)

无论你想做什么改变,都需要清楚地表达出来,并且要不断重复。即使你感觉自己像台坏掉的录音机,也必须不断重复直到完成改变。因此,要明确地表达出你想让大家进行结对编程(同时不要把它变成命令)。如果你是领导那就更有效了,只要不断重复,开发者一定会听进去。

记住这三条准则之后,我们来看一些推行结对编程的方法。

方法一)细胞分裂

这种方法适用于你已经拥有,或者可以招聘到经验丰富并且非常热情的结对编程程序员。我们叫他们结对专家。你至少需要 2~3 人来推行结对编程。具体方法如下:

  1. 组建一个队伍,一半是结对专家,一半是结对新手(团队中没有结对编程经验并且愿意参与的人)
  2. 最初,所有的代码必须由一个结对专家和一个结对新手结对完成。需要频繁更换结对目标。
  3. 当新手开始适应的时候,你可以放宽专家 - 新手结对这个要求,但是至少要保证团队稳定发展三个月,或者直到结对新手都“转换”为结对专家。这个过程至少需要三个月,一定要有耐心。如果你很快就停止,那新手的经验无法牢固掌握。
  4. 现在你有两倍的结对专家了。如果你还有许多需要转换的结对新手,可以把团队一分为二并加入结对新手组成新团队。确保在每个团队中专家的数量都大于等于新手的数量,然后继续执行步骤 2。

这个过程开始很慢,但是会呈指数增长。从一个团队开始,到第一年底你就会拥有八个团队,到第十五个月就会拥有十六个团队。到那时,你就很容易在团队中推行其他技术实践,比如测试驱动开发和持续集成。这些技能会快速传播到整个团队,因为大家都会对彼此负责。

注意:频繁更换结对目标也被称为“无序结对”。这样的好处是知识可以在整个团队中传播。此外,这样做也可以避免让两个人之间建立太深的感情,从而难以和其他人结对。Kent Beck 喜欢每隔几个小时换一次结对对象,但是一天一次就足够了。门罗创新公司会每周更换一次结对对象。

方法二)从零开始

如果你没有任何经验丰富的结对编程程序员,那就只能从零开始了。但是你还是可以遵循一个具体的方法。下面是 Laurie Williams 等人在《Pair Programming Illuminated》中推荐的方法。[5]

第一步是从团队中找出一个声望高并且愿意协助你进行改变的开发者。选择一些候选人并向他们解释你想做什么以及为什么要这么做。记住你的好处列表(上文提到过)。如果他们不能做出决定,可以让他们参考一下列表中的好处。如果他们拒绝帮助你,那也要让他们保持开放的心态,不要变成你的敌人,然后询问下一个候选人。

当你找到认同你的开发者之后——我们叫他 / 她“结对支持者”——就可以进入下一步了。在这个阶段,结对支持者开始逐渐向组织中的其他人介绍结对编程的思想。最好的方式是向其他程序员提供帮助,协助他们完成工作或者进行一对一帮助。这样,结对支持者就可以不动声色地和其他程序员建立起结对关系。如果这种关系进展顺利,结对支持者就可以和队友讨论结对编程及其好处,并评估队友对于结对编程的态度。这一阶段的目标是发现组织内和你想法相同的人。

当你有一批可以接受结对编程的人之后,下一步就是和所有人进行公开的讨论。列出一个暂时的自愿性质的结对编程计划——包括最初有多少对开发者和尝试多长时间。因为需要一段时间来适应,所以最好尝试三个月或者更久。让大家公开讨论他们对于结对编程的疑虑,并探讨如何解决他们的问题。和他们讨论评价标准,什么样的结果会让大家相信结对编程是一件值得长期坚持的事情?讨论如何收集数据从而可以验证结果是否符合标准。最后询问有多少人愿意参与。如果可能的话可以加入物质奖励,从而让结对编程者在一个理想的新项目上开始工作。

其他建议

除了推行结对编程,还有一些需要思考的内容:

  • 并不是所有人都适合结对编程

    事实是组织中有些人可能永远不会加入。你可以选择:

  • 如果他们愿意的话指导他们

    一个优秀的教练可以帮助团队中的成员处理恐惧和困难,帮助他们找到解决方法。

  • 给他们一些不需要结对编程的任务

    或许你可以给他们分配一些单人编程也可以完成的任务。

  • 接受损失

    做好心里准备,有些人会选择离开。愿意接受结对的新人可以代替他。

  • 把结对编程加入招聘流程

    在第一次面试候选人的时候和他进行一个简单的结对编程练习是一个好办法。让专家观察候选人,判断他们是否具备和队友沟通的能力。通过测试的候选人还需要和多个队友进行一整天的结对编程,然后再决定是否聘用。

  • 确保有足够的奖赏

    如果你奖赏单人行为和单人成就,那其实会影响结对编程模型,并鼓励人们继续单人工作。因此,必须重构你的奖励体系,关注团队而不是个人。

  • 你可能需要重新排列办公桌

    结对编程需要一个长条办公桌,让他们挨着坐并且有足够的活动空间。每个结对办公桌需要放置两个大显示器、两个键盘、两个鼠标和一台电脑。尽量避免筑墙,每个人都需要说话,他们不需要安静。合作的嗡嗡声将会给你的团队带来活力。

  • 提供娱乐设施并允许休息

    很多人都发现,在结对间隙放松几分钟非常有帮助。乒乓球桌是个不错的选择,可以实现短暂的激烈运动,并且非常有趣。

  • 牢记变化管理曲线

    无论要做出什么改变,都需要准备好面对暂时的性能下降。如果大家都知道你已做好心理准备,那曲线就会缓和一些。

  • 调整组织的整体期望

    当你庆祝结对编程带来的好处时,别忘了让组织中其他人学会尊重结对编程并且不要期望电子邮件能够得到立刻回复。可以使用其他方法来实现外界和你的团队之间的信息流通,比如使用站立会议时间,或者指派一个团队领导 / 敏捷教练来收取外界的请求并在适当的时间传达给团队成员。

分布式团队

工作地点不一致的团队怎么办呢?他们能获得结对编程的好处吗?当然可以,只要他们愿意付出一些额外的努力。有许多工具可以帮助程序员共享屏幕和音 / 视频,从而创建一个虚拟的结对环境。可能需要一些尝试来判断哪些工具最适合你的技术栈。虽然视频是可选的,但是我很推荐视频——获得肢体语言和表情反馈可以极大地帮助你理解队友的状态。比如说,他保持沉默的原因是因为感到疑惑吗?他在思考吗?还是他起身去休息了呢?经验丰富的远程结对编程者Joe Moore 的博客是学习远程结对的好地方。让团队短期共同工作也是一个好办法——比如一次或者两次冲刺——这可以让他们在远程结对之前适应结对编程。

结论

结对编程对于所有软件开发公司来说都极具价值。它可以显著提高质量和速度,甚至可以提高开发者的工作满意度。为了获得这些价值,需要非常谨慎小心地把结对编程引入到你的团队中。避免命令和强制要求,要不断鼓励和奖励他们。这项强大的技能会在日复一日的练习中逐渐显现出威力,让你的团队慢慢发现它的作用并达成共识。最后,别忘了,结对编程不适合所有人,所以要想好如何回应那些拒绝结对编程的团队成员。

作者介绍

Melinda Stelzer Jacobson是一名敏捷教练,坚信生产力和成功源自快乐的成员和重视信任、尊重和沟通的团队。她的信念源自 15 年的软件开发经验,包括电信、银行、科学设备、网站和互联网程序。Melinda 住在旧金山,曾获得敏捷专家认证、敏捷开发者认证、ICAgile 专业敏捷教练认证、DAD 黄带和创新游戏合作架构师认证。在业余时间她会收养可爱的流浪兔,这样它们就不会被安乐死。

引用

[1] Williams, Laurie and Robert Kessler, Pair Programming Illuminated , Addison-Wesley, 2003, pp 9-10

[2] Beck, Kent, Extreme Programming Explained: Embrace Change, 2nd Edition , Addison-Wesley, 2005, p. 42

[3] Williams, Laurie and Robert Kessler, Pair Programming Illuminated , Addison-Wesley, 2003, p 38

[4] “Perceived control of software developers and its impact on the successful diffusion of Information technology” Carnegie Mellon special report

“The successful diffusion of innovations: guidance for software development organizations” IEEE Software

[5] Williams, Laurie and Robert Kessler, Pair Programming Illuminated , Addison-Wesley, 2003, pp 53-54

查看英文原文: Introducing Pair Programming


感谢邵思华对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群)。

2015-06-02 01:552998

评论

发布
暂无评论
发现更多内容

虚拟办公、虚拟展会、虚拟偶像,RTE+XR 还能做什么?

声网

人工智能 vr Metaverse

架构实战营模块6课后作业:小程序电商业务微服务

胡颖

架构实战营

不用找了,这本书帮你完全搞定Spring Cloud Alibaba

胡弦(关注公众号架构随笔录)

分布式架构 spring cloud alibaba

【死磕Java并发】-----Java内存模型之从JMM角度分析DCL

chenssy

11月日更 死磕 Java 死磕 Java 并发

.NET Core 中对象池(Object Pool)的使用

喵叔

11月日更

Python中的控制流:break和continue

Peter

Python 控制流

Electron常见问题 48 - Electron 获取本机 MAC 地址

liuzhen007

11月日更

网络安全之浏览器端的威胁要塞防御

喀拉峻

网络安全 安全 信息安全

linux总结10大危险命令

入门小站

Linux

架构实战 - 模块四

唐敏

「架构实战营」

测试左移实践介绍

刘冉

TDD 自动化测试 测试驱动开发 测试左移 ATTD

“零信任”的世界,让女性更安全

脑极体

Python Qt GUI设计:QMainWindow、QWidget和QDialog窗口类(基础篇—10)

不脱发的程序猿

PyQt GUI设计 QMainWindow QWidget QDialog

18 K8S之存储卷简述

穿过生命散发芬芳

k8s 11月日更

如何设计高性能高可用存储架构

天天向上

架构实战营

在线等比数列项数生成器

入门小站

工具

[Pulsar] Delayed message原理

Zike Yang

Apache Pulsar 11月日更

Android C++系列:Linux文件系统(一)

轻口味

c++ android jni 11月日更

完善Django的MVT框架开发,记得添加路由哦~

老表

Python django web开发 11月日更 博客系统

☕【Java技术指南】「技术盲区」看看线程池是如何回收和维持运作线程的核心技术体系

洛神灬殇

Java 线程池 11月日更

用户任务三步法:教你读懂用户

石云升

11月日更 产品创新

阿里云 EventBridge 事件驱动架构实践

阿里巴巴云原生

阿里云 云原生 事件驱动 事件驱动架构 EventBridge

元宇宙、区块链和潘家园

脑极体

今日谈:BoltDB数据库,一款纯Go实现的KV数据库

Regan Yue

Go 语言 11月日更

Serverless 下的微服务实践

阿里巴巴云原生

阿里云 Serverless 微服务 云原生 SAE

又谈mysql,面试官问表结构设计要注意啥?

微客鸟窝

MySQL 11月日更

redo Log 的持久化过程

卢卡多多

Redo Log 11月日更

一份数据的6种Plotly画法

Peter

数据分析 可视化

前缀和后缀运算符有什么区别?

devpoint

JavaScript 11月日更 前缀运算符 后缀

Prometheus Exporter (二)Windows Exporter

耳东@Erdong

Prometheus exporter 11月日更 Windows Exporter

[ Kitex 源码解析] 函数式编程

baiyutang

golang 微服务 Go 语言 11月日更

结对编程简介_语言 & 开发_Melinda Stelzer Jacobson_InfoQ精选文章