打破铁三角:新的项目管理角度

时至今日,依然有很多项目受困于项目管理铁三角:范围,时间,和成本。是啊,

  • 必须在2月底完成,因为报税高峰期3月份就来了。必须在10月底完成,因为要撑过双十一的并发量。必须在10。1前完成,因为要国庆献礼。
  • 这些需求都得做,因为被替换的系统已经有这些功能了,好多人在用,没了他们会叫的。
  • 就这些人了,招人短时间内也招不到,再说你们不是说了加人反而会降低开发速度吗?

这些都是现实的困难,很难突破,这也是前面几项被称为”铁三角”的原因。那是否就一点办法没有了?

打破一条规则最有效的方法是推翻它的前提和假设。当我们重新审视铁三角的时候,会发现它至少有四个假设。其中有两个假设比较明显,早早就被人发现并利用了。而另外两个假设则需更进一步的洞察力,敏捷项目管理正是对准了这两个不那么明显的假设。对这四个不同假设的颠覆,导致了截然不同的软件过程管理方法。下面我们依次来看一下。

时间变慢

第一个假设较为明显,即铁三角中的时间是按每周工作5天,每天8小时来计算的。无数的团队发现了这一点,然后毫不犹豫的打破了它。每周工作6天,每天12小时如何?工作吞吐量立即可以提升(72-40)/40=80%。相当于时间的流逝减缓了近一倍。这就是我们常见的加班背后的原因之一。

牺牲质量

第二个假设也不难发现,即铁三角中没有提及质量,尤其是内部质量。其实就算客户和供应商的合同中对质量做出一定要求,由于其难以衡量和验证,以及延时效应,通常也沦为最弱的一种约束。”精明”的团队对此心知肚明,通过拷贝粘贴等牺牲内部质量的方式来快速堆积功能。这就是我们常见的匆忙赶工的产品其代码难以长期维护的原因之一。

对以上两个假设的颠覆导致了不利于团队,不利于客户的开发方法,长期来看都是输家。所幸我们还有第三和第四个假设,对它们的重新审视把我们引导到更加合理的项目管理角度。

关注价值

第三个假设是这样的:铁三角之所以这么引人关注,是因为大家认为只要在固定的范围,时间和成本的约束内完成项目,就是成功的。

这是一个看似合理的假设。然而考虑以下两种情况:第一种是在规定的时间和预算内完成了全部预期的功能,但产品没人用,投向市场没啥反应。第二种是工期超了一点,预算也超了,计划的功能有很多没做,相反根据变化做了点别的,但产品推向市场后反应不错,带来了利润。那么两种情况哪种算是成功呢?

我会选第二种。这么选的还有一个叫JimHighsmith的。他针对这个问题提出了新的三角,他称之为敏捷三角:价值,质量和约束。见下图(摘自Agile Project Managment):

其中传统的铁三角被局部化成一个维度,称为约束。而引入了新的维度,价值和质量。其中价值代表的是利润等正向的因素,而质量代表的是变化的成本。质量越好,意味着变化的成本越低。据此,我们打破铁三角的第一个手段是,关注真正的用户价值,降低变化成本,并为此而调整计划。

提高生产效率

铁三角的第四个假设是生产效率不会发生变化。因此固定其中两个只能调节第三个,铁三角因而是铁的。

这个假设具备一定合理性的原因是短时间内生产效率很难发生突破性的变化。但这不妨碍我们持续去提高生产效率,从而软化铁三角。

这方面有众多的选择,比如通过自动化减少手工工作,通过预防错误避免返工,而这里面最重要的,是持续学习,提升每个个体的效率。我们通常说程序员之间的效率差异会达到数量级的差别。花些时间在沟通交流培训反馈上,是我们即使在最严格的外部约束下,也可以做的,并且是为数不多的手段之一。

其实我们从来就只有两个问题…

做什么和如何做。

对做什么保持关注,就会得到敏捷三角;对如何做保持关注,就会得到持续改进;不思考才会被约束住。


更多精彩洞见,请关注微信公众号:ThoughtWorks洞见

Share

超越培训——比培训多做一点点

培训真的没用吗?

在我跟同事聊起培训的时候,他们对培训的认知大概是这样子:”我们团队成员的架构能力不足,没法落地微服务,你们来给我们上一个DDD的课吧…” 诚然,这种模式在培训市场是普遍存在的,组织斥巨资邀请大牌培训师,上个几天的课,培训师拿钱走人,然后呢,可能就没有然后了。

团队之所以需要一个培训,无非是因为面临自身无法有效解决的问题,亦或识别出潜在的风险(以花钱为目的另当别论)。问题通常源于流程和人两方面,流程的问题最终也能归结到人身上,人的问题又很容易被定义为能力的问题,如此一来团队便寄希望于借助外部力量来提升团队的能力。这种想法没毛病,毛病在于培训往往无法有效解决能力问题,除非培训能够回答以下两个问题:

  1. 如何让学员的认知发生实质性的转变?
  2. 如何让学员将知识有效地转化成技能?

实践证明,单纯的培训很难给出答案,从而产生了培训无用论[1] 的观点。然而,培训真的没用吗?如果没用,为什么一些大厂都在大力推行员工培训呢?

能力建设的团队自治观

思沃内训[2]是ThoughWorks中国区负责人员能力建设的团队,我们同样面临着跟外部培训相似的困惑:培训之后无法保证团队发生实质性的提升。 要改变现状,我们必须要比培训做的多一点,站在更高的视角去看团队对培训的诉求,不难发现团队是希望通过有效的能力提升去解决实际问题,这便升级为一个复杂的能力建设问题。

最理想的能力建设活动应该由团队内部自发组织,一来具备更好的On-Boarding土壤,二来更符合自组织的敏捷团队特征。在ThoughtWorks不乏这样的学习小组。然而,随着公司业务的扩张,新老同事快速更替,能力建设遭遇瓶颈,内训团队便承担起特殊的外部教练角色。

教练本身不会直接着手解决团队面临的问题,教练的主要职责是帮助团队自己解决问题,最终还是要依靠团队自身发力,取之于团队、用之于团队。知易行难,做好这一点呢?带着这些思考,我们落地了一场超越培训的训战

超越培训的训战模式

训战模式的核心思想是培训 + 实战,该模式需要统筹规划培训前、中、后三个阶段,做到训前瞄准、训中调整、训后复审,将单纯的培训变成一个有效的能力建设活动,实现价值闭环。

与传统培训方式不一样的是,我们在训前做得更加充分精确,为训中留有足够的时间和空间,实现课程快速迭代,后期结合至关重要的训后复审,通过实战来内化知识。该模式的核心指导原则是:跟团队保持紧密连接。基于这些创新的想法,辅以4个关键步骤来完成训战:

教练在前期深入团队,分析团队现状,准确定义问题,为团队量身定制解决方案。培训交付期间,通过教练引导技巧深度激发团队成员的思考和讨论来颠覆或加强他们固有的认知。最后,围绕训战计划来促进团队的知识转换。

下文我将通过实践案例对训战模式做一个全面的阐述。这是一个服务于海外知名大企业的业务团队,前期高质量交付赢得客户的信任,促成了更多业务合作机会,团队规模亟需扩充。此时,原本新人占比大的现状伴随着扩充继续加剧。如何提升团队开发人员能力、保证敏捷技术实践的良好落地成为团队即将面临的一大难题。

定义问题 – 深入团队

问卷或访谈的方式呈现出来的很可能是冰山上半部分的景观。为了探索下半部分,我在前期深入团队内部获取团队日常工作状态、技术栈选型以及人员的相关情况,并出了一个初步的分析报告:

基于分析报告,跟TL达成初步方案是上OOBootcamp五抓手(OO、Clean Code、Simple Design、Refactoring、TDD)。有了五抓手这把枪,不能着急开火,我需要弄清楚团队对这些实践的实际的落地情况。通过参加团队的代码评审以及详细的代码库扫查,我果然收到了惊喜 — 代码库测试覆盖率高达90%,代码分层、模块化都不错(似乎已经做的很好了)。

当前代码库的良好状态离不开团队的对Clean Code的重视,再加上团队刚刚对原本业务代码量不大的代码库做了较大规模的重构。即便状况良好,团队依然非常渴望掌握工程技术实践的最佳姿势,尤其是TDD。

基于这些调研分析,我对问题域重新划重点:

  1. 团队成员Second Tier入职时间偏短,相关敏捷技术实践掌握深度不够,担心影响后期交付质量。
  2. 技术实践在后期Ramp-up保持最佳姿势一致性有难度,存在辜负客户期望、降低客户信任度、难以保持标杆形象的风险。

设计方案 – 量身定制

不难看出此次能力建设活动属于风险预防性质的。虽然没有太紧迫的痛点,但团队已经暴露出一个关键的信号 — 团队已经在尝试的过程中产生困惑,渴望得到解答,并通过实践掌握最佳姿势。该信号给了我一个方向:借助大量的实践操练和充分的思维碰撞来加强训战的效果。基于此,我搬出了承载了五抓手的法宝OO Bootcamp[3],并一切为8,每周3次,每次晚上2~3小时,形成了非常6+1的两周拉锯战模式。

依赖于口口相传的OO Bootcamp在课件标准化上沉淀颇少,这也给了我充分的空间让我去设计训战方案,对于训的设计,我重点兼顾了两点:

  1. 定制化调整。针对团队的真实情况做适当的定制化,并做好在交付的过程响应变化的准备。
  2. 螺旋化共创。在课程中能够不断激发思考,试图让大家经历困惑、解惑、疑惑、再解惑的螺旋化过程。做到学员共创 Over 讲师讲解

交付培训 – 认知转变

本环节的核心目标是:通过持续调整,辅以螺旋化共创过程,诱发认知转变。 要引发螺旋式的认知转变,最重要的一点是:放慢步伐,以学员讨论、答疑解惑为核心宗旨。因为参与这次训战的成员特殊性(TL & Second Tier),讨论的焦点主要被我引导向价值层面(Why),通过操作层面(How)的冲突来激发讨论,并在How与Why之间螺旋交替冲击,最终回归到Why上,讨论的重点也大多聚焦在团队日常工作中面临的问题上。

有意思是,当大家对价值层面理解达成一致后,在操作层面的最佳实践往往都是无果而终(By Experience),我们对最佳实践虽然未曾有明确的定义,经过这样频繁的思维碰撞,团队往往能找到一些方向。比如TDD,做Story的时候,第一步是从业务视角去做Tasking,将Tasking可视化作为一个DoD[4],严格根据Task来编写测试用例,做到测试先行,并通过Pair来刻意练习。

铺设好明线,我在辅线上也做了一些必要的工作 — 跟团队做深入交流,了解他们当前面临的痛点,设计新的案例,尝试抛出一些引子,引发团队成员共同思考。比如如何在后端MVC架构下做TDD。

部署计划 – 技能转换

我认为一场好的训战应该由体验、反思、抽象、行动四个部分组成,相辅相成,并且能够形成一个闭环。在培训过程中,需求驱动、编码实践就是一种体验,在体验的过程中引发思考和讨论,最理想的情况下是学员自己能够从思考和讨论中抽象总结得出结论,并将结论付诸行动得以验证。

在文章一开始我就提到,能力建设最终要靠团队自身发力,主动权必须交还给团队,否则一旦教练离场,打回原形的风险很大。通过培训颠覆认知只完成了一半的工作,另一半的工作是将这些新的认知在实践中去验证。要打好下半场,就需要搬出核心法宝 — 训战计划。
训战计划类似于一个计划,它具备三个重要特征:

  1. 符合SMART[5]原则,难度适中
  2. 跟项目工作内容息息相关
  3. 学员自己拟定并认可签字

作为教练,我协助团队成员去制定有效的训战计划。有了训战计划,就一定能够兑现吗?理想情况下,团队成员的能够足够自我管理,并落实好计划。必要的时候,借助一些轻量的管理机制和有效的激励机制,比如,组建分队、队长责任制、公开承诺发布等,另外对计划完成后进行奖励等。
作为特殊的外部教练,我需要持续重点做的事情有:

  1. 培养团队内部教练,保证后期的可持续发展。
  2. 训战计划执行期间,响应团队的诉求,帮助团队解决执行过程面临的阻碍。
  3. 定期回访,跟踪训战计划的落实情况,了解团队的困难,并记录团队的变化。

训战的核心要素

训战的复杂度远超越了培训,既要大处着眼,用全局的视角统筹训和战,也要小处着手,紧抓各个环节,尤其是训战计划的落地跟踪。一场优秀的训战,除了方案设计、课程内容和呈现形式上的创新,还需要借助团队管理和激励的手段。综合来看,决定训战成功与否的几大核心要素有:

  1. 一致的期望
  2. 专业的培训
  3. 承诺的计划
  4. 严格的跟踪

一致的期望

在训前方案设计阶段,一项至关重要的举措是跟Stakeholder和团队成员对训战模式的期望达成一致 — 不仅仅是一场讲完就散的培训课程:

  1. 对于学员,要做出源于追求卓越的自我Commitment。
  2. 对于Stakeholder,要提供资源来促成训战计划落地,比如识别潜在内部教练,提供训练道场支持等。

专业的培训

教练需要对领域知识具备一定的深度,深刻理解正、反模式的利弊,拥有丰富的实战经验。同时对于教练引导能力也提出了较高的要求,推荐实施以学员为中心的共创式教学。另外,还需要具备对实时反馈的响应力,能够快速调整优化设计。

承诺的计划

学员基于培训的内容,结合实际项目中遇到的问题,亲自挂帅拟定恰当可行的训战计划,并立下”军令状”,最终做出公开承诺、告示”天下”,若能借助管理激励机制形成彼此轻量的竞争态势会取得不一样的效果。

严格的跟踪

训战的效果取决于训战计划是否合理以及能否有效执行落地,后期严格的跟踪尤为关键。首先,可以在团队内部培养教练,来帮助成员解决执行过程中遇到的问题,同时敦促计划的推进。其次,在流程管理和奖惩机制上,Stakeholder的关注、必要的激励以及恰当的惩罚技巧都会影响跟踪效果。至于如何操作,团队因地制宜即可,推荐正向激励。

写在最后

训前瞄准、训中调整、训后复审这种基于业务团队的训战模式,通过4个看似很平凡的关键步骤,围绕着训战计划来促进行动学习,帮助团队将知识转换成技能,有效地实现价值闭环。

培训到底有没有用,我们给不出一个标准的答案,我们能做的是探索更高效的能力建设模式,尝试比培训多做一点点。

注释

  1. 培训无用论,参考文章《然而培训并没有什么用》
  2. 思沃内训团队,ThoughWorks中国区负责人员能力建设的团队,相比于其他外部培训机构,内训团队的优势在于深耕ThoughtWorks,充分理解ThoughtWorks文化。
  3. OO Bootcamp,全名为“面向对象训战营”
  4. DoD, Definition of Done
  5. SMART
    • Specific
    • Measurable
    • Attainable
    • Relevant
    • Time-bound

更多精彩洞见,请关注微信公众号:ThoughtWorks洞见

Share

7个你需要知道的结对礼仪

结对编程远远不是两个程序员坐在一起写代码那么简单。 — 鲁迅(没有说过)

结对编程

结对编程可能算是比测试驱动开发更具有争议的敏捷实践了,事实上,仅有很少的团队可以很好的实施它并从中受益,对于更多的团队来说,即使在践行敏捷的团队中,也常常会分为旗帜鲜明的两个阵营。提倡者往往会强调结对编程在“传递领域知识”,“减少潜在缺陷”,“降低信息孤岛的形成”等方面的作用;而反对者则认为结对编程在很多时候都是在浪费时间:开发者在实践中很多时候都难以聚焦,容易产生分歧,另外个人的产出往往也难以度量。

这篇文章不打算讨论结对编程对效率的影响,也不讨论要不要进行结对编程,当然也不会涉及以何种力度来执行结对。这里的假设是团队决定采用结对编程,但是对于如何实施存在一些疑虑;或者已经在采用结对编程的团队里,发现很多时候结对编程并没有很好的发挥作用,需要一些更有实践意义的指导。

结对编程远远不是两个开发者坐在一起写代码那么简单。作为一种科学且充满趣味性(才不是)的工程实践,事实上它是有一些基本原则的,团队里的开发者需要正确的实施这些原则,结对编程才有可能为团队带来实际的受益。

假设你找到了另一个程序员,并且已经准备好一起来编码实现一个具体的业务需求。在开始着手开始结对之前,你首先需要setup环境。

硬件设置

工欲善其事,必先利其器。首先你和你的peer需要一个大的外接显示器和有一个可以调节高度的桌子(当然也可以用纸箱子DIY一个低配版)。这一点往往被初学者忽视,而事实上它可以直接决定结对能不能作为一个可持续的团队工程实践。如果你的颈椎长时间处于不舒服的状态,你的注意力很快会退散,精神会变得难以集中,而一个处于病态的身体是无法支撑长时间的编码工作的。

在开始之前,请将屏幕调整到舒适的高度,以不仰头不低头为度(身高不一样的两个人可以通过调整椅子的高度达到基本一致)。此外还要注意看屏幕的角度,如果你需要抻着脖子才能看清楚屏幕,那么当时间稍长一点时,你的颈椎也会非常吃力。因此,如果条件允许的话,你和你的peer可以使用双屏来进行结对。

当然,还有一些常见的其他关于硬件准备的细节,比如:

  • VGA/HDMI转接头
  • 充足的电源
  • 键盘/鼠标转接头
  • 便签和笔

纸和笔永远是你(们)的好朋友,在实际动手写代码之前,请拿出纸笔来将要做的事情划分成更细粒度,可以验证的任务列表,贴在显示器的下边缘。最后,另外记得将手机调成震动模式,利人利己。

软件设置

硬件准备好之后就可以进行软件的配置了。软件问题远比硬件复杂,因为大部分开发者都有自己钟爱的工具集,小到curl/wget,大到Vim/Emacs,不要期望在这个问题上和peer达成一致,这是可遇而不可求,可望而不可即的。

根据我自己的经验而言,高级一些的IDE比如JetBrains出品的Intellij,WebStorm等都可以随意切换快捷键集合(keymap)。如果你和peer就快捷键的使用上无法达成一致,在轮到你输入代码的时候,你可以切换到自己熟悉的Keymap,反之亦然。

在Intellij/WebStorm里,你可以通过ctrl+来切换各种设置,比如选择3就可以切换不同的Keymap,然后在下一步的窗口中按照自己的喜好进行切换预设的Keymap。某项目的王晓峰(Vim党)和张哲(Emacs党)尤其擅长此技,他们两人结对时,可以做到在抢键盘的瞬间将keymap切换到自己的挚爱而对方无察觉的地步。

这种技法事实上仅仅对于结对双方都有很高超的键盘操作能力的前提下,也唯有这种场景下,双发可以互不妥协。对于另一种场景(可能在实际中更为常见),比如结对一方键盘技巧和操作效率低下,影响结对流畅程度的场景,则需要效率低下的一方自己摒弃陋习(使用鼠标而不是键盘),快速赶上。

和别人结对之前,你需要至少熟悉一个IDE/编辑器,比如通过纯键盘的操作完成

  • 按照名称查文件
  • 按照内容搜索
  • 定位到指定文件的指定行/指定函数
  • 选中变量,表达式,语句等
  • 可以快速执行测试(可以在命令行,也可以在IDE中)

熟常基本Shell技能和常用命令行工具的使用,可以完成诸如

  • 文件搜索
  • 网络访问
  • 正则表达式的应用
  • 查找替换文件中的内容

等操作,这样在结对时可以大大提高效率。这些都是稍加练习就可以掌握的技能,并没有多少技术含量在内,而且学会了可以收益很久。

当知识不对等时

好了,铺垫了这么多,终于到了正题部分。最理想的结对状态是,双方的技能水平相当,知识储备基本类似,可以非常流畅的进行交流,在结对过程中可以完全专注在需要解决的问题本身上,讨论时思想激烈碰撞,编码时键动如飞,不知日之将夕。这种场景下完全不需要任何技巧,随心所欲,自由发挥即可。与此对应的另一种场景是双方都没有任何储备,技能也无法胜任,这种情况我们需要在项目上完全避免。

这两种极端的情况之外,就是不对等的场景了,这也是现实中最为常见的case:很多时候,结对双方会有一个人比较有经验,而另一个人则在某方面需要catchup。比如一个老手带一个新手,或者一个擅长业务的开发和另一个该领域的新人结对等。

一般而言,需要双方有一个人来做主导,另一个人来观察,并在过程中交互,答疑解惑,共同完成任务。与传统的教与学不同的是:结对需要的是两个智慧头脑的碰撞,而不是单方面的灌输。因此观察者不是单方向的被动接受,主导者也并非完全讲述。事实上结对是一个会有激烈交互的过程。

主导者

对于主导者来说,千万不要太投入,而无视peer的感受。这种场景非常常见,我自己有时候也会不自觉的忽略掉peer,自顾自的写代码,很多时候把peer当成了小黄鸭。这时候你的peer会有强烈的挫败感,也很难跟上你的节奏,从而影响结对的效果。作为主导者,需要更耐心一些,不断的和自己的peer交互。

另一个极端是,主导者太热心的coach,而忽视了给新人实际锻炼的机会。这时候需要主导者给peer更多的实践机会:比如在带着新人编写了一个小的TDD循环(红绿重构)之后,可以抑制住自己接着写的冲动(我知道这个非常困难),然后将键盘交给你的peer,让他模仿你刚才的做法来完成下一个。

有时候,当你看到peer正在用一个不好的做法来完成任务时,你可以即使让他停下来,并通过问问题的方式来启发他:

  • 还有更好的做法吗?

如果peer仍然在迟疑的话,你可以进一步提示:

  • 你觉得XXX会不会更好?

一个实际的例子是,你们在写一段JS代码来迭代一个列表,你的peer正在用for循环来操作一个数组,而你可以提议使用Array.map。有些时候,你的peer会给你一些惊喜的回答!他的回答甚至比你预想中的更加出色,你也可以通过这种方式来向他学习。

观察者

另一方面,作为观察者而言,结对毋庸置疑是一种特别好的学习机会,你应该抓住一切可能的机会来向你的peer学习。包括快捷键的使用,命令行工具参数的应用,良好的编程习惯等等。保持你的专注力和好奇心,比如你看到peer神器的通过快捷键删除了花括号(block)中的所有代码,或者将curl的返回值以prettify过的样式打印到控制台,或者通过命令行merge了一个PR等等。

在实践的时候,可以采取Ping-Pong的方式来互换主导者和观察者的角色。比如,A写一个测试,B来写实现,A来重构,然后换B来写测试,A来实现,B来做重构等等。开始时,可能会由一个人来主导,随着合作越来越顺畅,你们可以提高交换的频次。

保持专注

在选定了要两人一起解决的问题之后,你们需要一起完成任务划分。这样可以确保你们可以永远关注在单一任务上,避免任务切换带来的损耗。

在做完一项任务后,用mark笔轻轻将其从纸上划掉(或者打钩)。千万不要小看这个小动作的威力,它既可以将你们的工作进度很好的表述出来,也可以在任何时候帮助你们回到正在做的事情上(特别是在吃完午饭之后),另外这个微小的具有仪式感的动作是对大脑的一个正向反馈,促进多巴胺的分泌(代码写的这么开心,还要什么女朋友?)。

很多时候,我们需要暂时搁置争议,保持前行。

无法统一的意见

如果你遇到了一个固执己见的同事,而不凑巧的是你也是一个难以被说服的人,那么如何处理那些无法避免的争论呢?特别是那些没有对错之分的技术问题。比如那种编程语言更适合Web开发,比如如何践行TDD(比如自顶向下的TDD和自底向上的TDD)等等。

有时候,我们会非常坚持自己觉得对的东西,觉得那就是真理。挑战这个真理的不是傻就是二,但是用不了多久,我们就会发现,换个角度好像也说得通,特别是在和其他人结对,并突然意识到以前的那个完全无法接受的做法似乎还是有几分道理的。

在我刚做完的一个前端项目中,做技术选型时我自然的选了更早项目中使用的scss module,而团队里的另一个同事则提议使用styled-component。我们谁也没有说服谁,最后写代码的时候就有两种风格。直到有一天,我在代码库里看到了用styled-component写的很漂亮的组件,我自己尝试着把相关的scss重写成styled-componet,结果发现确实比单独的scss文件要更好维护一些,而且也不影响既有的测试。

我突然意识到,我所坚持的只是一个假的“真理”,先前的坚持和做技术选型时的理由就变得很可笑:那只不过是为了使用自己熟悉的技术而编造的理由而已。保持open mind是一件知易行难的事情,希望大家在争辩时能念及这个小例子,可能会少一些无谓的争辩。

对于这种难以统一意见的场景,我建议可以将其搁置,先按照某一种提议进行,知道发现明显的,难以为继的缺陷为止。往往你们会发现一条比较折中的路,或者一个人被另一个人说服。

棘手的任务

即使很有经验的程序员也会遇到新的领域,或者在熟悉的领域遇到新的困难。有些情况下,作为结对的两个人都对要完成的主题没有头绪。这时候非要挤在一起反而会降低速度,无助于问题的解决。

一个好用的实践是,两人分头研究,并严格控制时间。比如Time box 30分钟。不过很可能在30分钟后,你们中至少有一个人已经对要怎么做有了头绪,如果30分钟还没有头绪,则可以求助团队其他成员。

比如我在最近项目上遇到了Kerberos认证的问题,我和peer都没有接触过,在经过20分钟的独立spike之后,我发现了一篇细节很丰富的,看起来很靠谱的技术博客,而我的peer则在内部github上找到了另一个团队的可以工作的代码(虽然代码质量不是很好)。我们最终决定copy+paste,然后做重构的方式继续前进。而那篇技术博客则是一个很好的课后学习的资料。

张弛有度

注意力是一种非常稀缺的资源,普通人很难全神贯注在某件事情上超过30分钟。一旦超过这个时间,大脑就开始偷懒,开小差。这时候一个短暂的break可以让大脑得到很好的休息。人类的大脑有一个非常有趣的特性,就是它的后台任务处理能力 — 而且后台处理能力好像远远强大于前台。你可能会在去冲咖啡的路上,突然灵光一闪,那个困扰你多时的问题有了思路,而此时此刻的你的大脑明明在想如何用咖啡机冲一份拿铁。

如果遇到一个难以理解的bug,或者在设置测试环境是遇到了困难,休息一下很可能帮助你找到解决问题的新角度。为了避免长时间纠缠在冥思苦想中,你和你的peer可以采取比如番茄工作法之类的时间管理工具:

  1. 从Todo列表中找出下一个任务
  2. 设置一个不可中断的25分钟,开始工作
  3. 时间到了之后,休息5分钟
  4. 重复2-3,4次之后休息15分钟

这里有一个在线工具可以直接使用 ,你也可以用手机的闹铃工具。

结对轮换

如果结对的对象长期固定的话,pair本身又会变成新的信息孤岛。比如A和B长期负责订单模块,而C和D则一直在写门店管理,那么毫无疑问,一段时间后,A和B就不知道C和D在做什么了,不论是领域知识还是技术实践,都很难得到有效的知识传递。当一个团队规模变成10+之后,这还可能演化成更为严重的项目问题。

因此需要定期或者不定期的轮转,比如一周轮换一到两次,A和C来写订单,B和D来写门店管理,这样可以保证领域知识,工程实践,工具的使用等等知识都很好的在团队内部共享。

在一些场景下,团队采取前后端分离的方式进行开发。前端和后端的技术栈选择大相径庭,每一端都有不同的约定和复杂的配置,这会对结对轮换的实施造成障碍,而且短期来看还会影响开发效率。如果团队再大一些,DevOps可能会独立出一个小组来负责,这将导致结对的轮换更加困难。

在实践中,我发现让不同角色的团队成员轮换结对所带来的好处(伴随着短期阵痛的)远胜过知识的隔离带来的坏处。团队中的前端开发如果花费一些时间和DevOps一起结对,他会对系统的整个架构更加清楚;而后端开发和DevOps结对则可能让他意识到代码中的潜在缺陷和解决方法(比如会话外置,缓存策略等)。

尊重

作为一个最小单位的团体活动,你常常要站在你的peer的角度来看问题。如果你不愿意和某一特性的人结对,那么首先不要让自己成为那样的人。比如你讨厌只闷头写代码,不理会peer有没有跟上的那种结对方式;又或者你不喜欢和用鼠标完成又低效又别扭操作的人一起写代码(我在和这样的人结对的时候,都需要费很大力气抑制自己,才不会从peer的手中把鼠标抢过来扔掉),那么首先让自己不是那样的人。

除此之外,尊重还体现在很多其他细节中。当你不得不中断结对而去做其他事情时,务必让你的peer知道。而且在离开之前,你应该表示歉意,不要凭空消失,然后若干分钟后又凭空出现,没有人喜欢和一个不靠谱的人工作。比如10点30分的水果时间到了,你看到有人拿着你喜欢吃的桃子从厨房方向走了回来。你可以示意peer暂停一会,然后去厨房拿点水果,记得给你的peer也带上一些。

另一方面,当你的peer回来之后,你需要及时和他catchup,告诉他你正在做什么,已经做到了哪一步等等。快速的将他带入到上下文中。

控制情绪

情绪是一件非常微妙的事情,它具有很强的传染性。当你们的工作任务收到各种blocker,被各种其他事情干扰而导致进度难以推进时,一定要注意自己情绪的控制。如果你的peer一直在旁边唉声叹气,或者抱怨连连,你会变得非常沮丧,并且很难集中精力在积极解决问题上。

你可以通过积极的寻求外部帮助,或者将blocker更快的可视化出来,让团队了解,并提供可能的帮助。

课后练习

和你的peer完成了充实而卓有成效的一天之后,你需要总结一下自己记录的知识点,这是一个绝佳的提升自己能力的方法。通过实战,发现自己的缺点,并通过近距离观察别人如何解决该问题,最终会以很深刻的印象记录下来,这时候针对性的查漏补缺是可以取得非常好的效果。

比如你已经习惯使用grep来做搜索,结果你的peer娴熟的awk技巧使你打开眼界,你可以在课后专门学习一下这个工具的各种选项,并尝试熟练应用。或者你们在代码库中探索到webpack的一些特殊配置,它可以良好工作,但是你不是很明白背后的原理,这些都可以放在结对结束之后自己消化。花一些额外时间来更新你的技能可以让你在第二天的结对中更加得心应手,也可以更好的融入到结对编程带来的快乐中。

这些结对的基本礼仪,都是一些微小的细节,做好了可以让和你一起工作的人比较舒服,也会帮助你自己建立一个更加高效的工作环境。

小结

在这篇文章中,我总结了一些有关结对编程的常见的问题和解决方法。在开始进行结对之前,首先需要确保硬件设施正确setup,这样可以保证大家可以在很轻松舒适的环境中工作。在软件设置上,保证效率的前提下,可以有不同的偏好设置。当能力不对等时,恰恰是结对编程最能发挥作用的场景,不但对于观察者来说是绝好的学习过程,对于主导者而言,也可以从coach过程中看到一些不同的东西。

在结对编程过程中,你们需要始终保持专注,可以通过任务拆分的方式来帮助一直关注在单一事项上。此外,应该有定期的休息,让紧张的情绪得到缓解。为了避免大尺度上的信息孤岛,团队还需要定期的进行Pair的轮换。

总而言之,通过这些方法的使用,可以有效的促进工作效率,促进个人成长为前提,并和可以形成很好的团队氛围。


更多精彩洞见,请关注微信公众号:ThoughtWorks洞见

Share

如何驱使行为改变

职权不是决定因素

绝大多数工程师对于变革有种无力感。这种无力感源于这样的想法:我不是管理人员,没有足够的职权,无法改变自己的组织。当这种感觉足够强烈的时候,它作带来的挫败感会使我们失去进一步行动的能力。

然而这种无力感无论是中层管理者、执行副总裁甚至首席执行官都会存在。论及变革,没人具有足够的权力。这是因为变革中最核心的问题不是改变组织的结构、战略或文化,而是改变人的行为与意愿——改变人的工作方式以及在工作中所关心的内容。 职权的确会让某些事情变得容易,有些大范围的变革还必须巧妙借助职权的力量——比如涉及组织结构调整的改变,但它不一定是变革成功的决定因素。

从2007年开始,国内很多软件企业开始尝试采用敏捷方法,其中不乏有中高层领导以行政命令推行敏捷方法的做法。我曾经在敏捷中国大会上碰到一位朋友,他跟我讲了他们公司的故事:他们公司里负责研发副总裁听说了敏捷方法之后,对于测试驱动开发非常感兴趣,认为这是提高软件质量的好方法。于是在公司内要求所有的研发人员都必须要开始采用测试驱动的方法进行编程,并制定了相应的考核制度。而最后的结果是,研发人员为了应对考核指标,写了很多无用的测试,花了额外的时间不说,对软件质量的提高并没能带来实质性的帮助。最后纵使在报告上有不错的测试覆盖率统计,绝大多数人——包括那位研发副总裁自己——都不认为这次变革是成功的,因为人们的工作方式和内容并没有真正地发生改变:他们并没有变得更注重质量,也没有采用自动化的方式来保证软件质量不受破坏。

比起职权我们更应该学会影响他人,驱动他们在行为上发生改变 。无论是否具有职权,成功地驱动变革都不是件容易的事情。拥有职权仍然需要小心使其发挥作用,没有它也不意味着我们完全被束缚了手脚,不能采取任何行动。关于职权在变革中的作用我们将在下一章讨论,在那之前首先需要讨论的是成功驱动变革的核心因素——如何驱使行为改变。

什么可以带来行为的改变?

有一种可以带来行为改变的方法,其主要模式可以表述为“分析—思考—改变”:

  • 针对特定问题向人们展示数据或者分析结果;
  • 通过数据或者分析的论证影响他们的思考方式;
  • 借由新的思维方式带来行为模式的改变。

这种方式天然受到工程师的喜爱。作为工程师,我们接受过严格的逻辑思维训练。我们相信数据以及理性的分析,并愿意根据分析结果调整自己的行为。我们理所当然地认为这是最合乎情理也是最客观理性的方法。不过令人意外的是,变革管理大师John P. Kotter的研究表明,“分析—思考—改变” 这种方式很少能真的发挥效果。他说对于“只对数据感兴趣的工程师”可能会有效果,但以我个人的经验来说,哪怕是对工程师,这招也没那么管用。

理智的局限

工程上的很多问题我们虽然知道优劣之分,但是难以量化和度量。比如Ruby到底比Java和.NET在研发效率上快多少?RESTful的架构风格比SOA(Service Oriented Architecture)在开放性和扩展性上好多少?采用结对编程的方式和不采用结对编程的方式在代码质量上有多少提高?我们明确地知道Ruby比Java和.NET的开发效率高、RESTful比SOA有更好的弹性、结对编程产出的代码质量更好,但是一旦论及多少和数量,却不是那么容易能够给出明确的答案。

那么我们要如何改变Java和.NET程序员的思维,让他们认为Ruby是值得尝试的?要如何改变具有多年SOA经验的架构师的思维,让他们相信RESTful是更好的选择?要如何改变从没有结对经验的项目经理,让他们理解结对并不是浪费时间和金钱呢?

此外,分析结果对人们思维的改变,远没有达到我们想象的那种程度。哈佛大学商学院Andrew McAfee教授富有洞鉴地指出:我们通常会高估新技术带来的效果和影响,大约三倍,而低估已有技术和方法的效能,大约也是三倍,只有在新旧技术相差十倍的时候,我们才会有明显的改变意愿。换句话说,如果我们希望发生的改变没有在某方面带来十倍以上的提升,人们的思考方式不会因为我们的分析而发生明显的变化。所以当你希望重构代码结构以获得更好的架构时,当你希望更换不同的数据库以获得更好的开发效率时,通常不会受到特别热烈的响应——这些改变虽好,但是远没有十倍以上的差距。

最后,也是最重要的,分析结果的确能够改变人的思维,但却很少能够有效地改变人的行为方式。比起思维,情感更能驱动人们作出行为的改变,而很少有分析结果能真正地打动人心,建立情感上的纽带。

几年前在推广Ruby的时候,我和几位同事组织过厦门Ruby用户组,期间我分享过一个主题:从面向对象技术发展的历史来看,为什么Ruby是更好的面对象语言。会后有位朋友私下找我沟通,他说:“从你提供的资料和分析,我或许相信Ruby这门语言有它的根源和发展;但是我实在无法想象在企业应用的开始中去使用它,因为我是企业级Java开发人员啊。”

这番话很有代表意义,Java对于这位朋友而言,与自我认知有关。他和Java有更深的感情联系——这是定义我的角色和身份的技术。所以他虽然能在思维上认可我给出的资料和分析,却很难真的作出改变。

感受带来改变

那么什么才是带来行为改变更有效的方法呢?答案是:目睹—感受—改变。

照John P.Kotter的话讲,这是“大多数在变革中取得成功的组织都会采用模式”。其模式可表述为:目睹是指通过一些戏剧性的、引人注意的情景或可视化展示(visualization)来帮助人们发现问题;在看到问题之后,引发人们情绪和感受上的冲击,让他们开始从内心深处作出反映,削弱那些阻碍变革的情绪,比如自满、愤怒、怀疑或恐惧。增加紧迫感、乐观或者信任等有益于变革的情绪;这些正向情绪开始改变原有的行为,或者强化新的行为模式。

这种模式常常会产生较深远的影响,除了能够带来行为改变之外,在这个过程中所产生的戏剧性的、引人注意的情景或是可视化展示的手段会被广为流传,对越来越多的人产生影响,它所产生的效果是非常惊人的。这里我有两个案例要和大家分享。

第一个例子是戏剧化的展示。

我曾经帮助某客户团队实施自动化测试。在这团队里,从部门领导到团队成员,普遍认为他们所处理的系统功能点杂、业务流程多变,实施自动化测试会有很高的脚本编写成本。此外,这家公司有独立的测试部门,但是由于这个团队做的是内部运营系统,测试部门并没有给予足够的重视和配合,反而是一再降低他们系统的测试优先级。从测试部门获得帮助几乎是不可能的奢望,所以所有人都认为自动化测试是不可行的, 但是他们愿意给我一个机会。

经过调研之后,我觉得数据驱动的功能测试非常适合这个团队的现状。经过了不到一周的准备,我迎来了第一次进度展示。为了帮助团队树立信心,并强调测试成本并没有想象中的那么高,我设计一个略有戏剧性的场景:在展示会当场把针对一个流程的测试,扩展为针对八个流程的测试——而这个改动仅仅涉及测试数据,没有任何测试代码的变化。也就是说,在2分钟内,测试案例个数提高八倍(当然,基数是一个自动化测试案例,这没什么可骄傲的)。没有行业数据、没有理论分析、没有特殊工具,就像变魔术一样提高八倍。

最终的结果也颇具戏剧效果,团队里除了产生了乐观的态度和对我的信任之外,我还收到一张速写。画了一个胖子站在投影幕布前面,幕布上整屏幕翻滚着测试执行日志和弹出的测试用浏览器。画的作者跟我说,当时他看到这一幕感到非常震撼,从来没有想过自动化测试可以凭空出现一般突然多出很多。此后我也在这个团队之外的地方听到了这个故事,与之相伴的是,很多实施自动化测试成功的案例。

第二个例子是没那么戏剧性的可视化展示。

很多年以前,那个时候微软刚刚推出WPF(Windows Presentation Foundation),我所在的一个团队就采用了这个技术,为某客户开发新一代客户关系管理系统。由于WPF在当时还是比较年轻的技术,很多实践都不是很成熟,我们做了很多的探索。一段时间以后,团队感觉到测试覆盖率偏低。不是测试报告上展示出来的数值低,而是根据缺陷的修复时间和缺陷的泄漏数量得到的一个直观感受。当时团队里有人有这样一个议论:因为WPF本身有很多自动生产的代码,同时很多交互功能以及样式渲染与WPF API绑定过死而难以测试。那么WPF最高测试覆盖率到底是多少?如果在WPF上最高测试覆盖率只能做到40%,那么我们的测试覆盖率还是很高的呢。毕竟我们使用了MVP(Model-View-Presenter)模式,对于可测试性还是有很大帮助的。

这是一种典型的自满情绪,这种情绪对于变革的推进是非常不利的。因为在这种情绪支配下,行为惯性很大且非常不容易接受其他建议。于是我们做了一个很简单的可视化展示,把当前团队的测试覆盖率写在一张卡片上,然后把这种卡片悬挂在团队最显眼的地方。如果我没有记错的话 ,初始数据是32%。然后有意思的事情就来了,这个数据当时是全办公室的最低值。毕竟其项目都是Web项目,以当时的能力要做到100%也不是不可能的。很多其他组的同事路过的时候,都会询问一下原因——毕竟这个数值实在太低了。可能是问得人多了终于有些同事受不了,开始反思32%是不是我们能做到的最好结果?答案当然是:不是,很多新的技术和技巧被发明出来用以改善WPF下的测试问题。几个月以后这个组的测试覆盖率接近60%。

有意思的是很多年后Android开始流行,另外一个项目组再做Android项目的时候遇到了类似的问题,也是测试覆盖率较低。他们准备放弃的时候,有人给他们讲了这个故事,特别提到了当时我们组挂在外面的那个测试覆盖率卡片。只不过讲故事的人说:我记得看到的数字是百分之五十几,所以你们做到这个数字也该不难吧。

“分析—思考—改变”与“目睹—感受—改变”最大的差异就在于,前者着眼于具体问题的分析和解决,而后者注重建立情感上的联系。成功的变革最终都会解决一些具体问题,但单刀直入式地从解决问题开始,并不一定是驱动人们作出行为改变的最佳方式。而当人们在情感上建立联系之后,往往会作出更有效的分析,也更容易接受思维上的改变。

在这个过程中最核心的步骤是感受, 通过情感上的冲击消除不利于改变的情绪而提升变革的意愿。变革的意愿越强烈,成功改变行为的几率就越高。有两种感受与改变的意愿密切相关:信任感与紧迫感。所以驱动行为改变最重要的步骤是获取信任、确立愿景以及提升紧迫感。


更多精彩洞见,请关注微信公众号:ThoughtWorks洞见

Share

细说API – 文档和前后端协作

在上一篇文章——《细说API – 重新认识RESTful》中介绍了如何理解和设计RESTful风格的API,现在我们来聊聊如何有效的呈现API文档,以及前后端协作的方式。

我经历过一些没有文档的项目,前后端开发者坐到一起口口相传,或者有些团队用 word、pdf 来编写 API 文档。API 文档的缺乏给前后端协作带来困难,在缺乏专门工具的情况下,编写和维护文档是一件工作量巨大的事,人工处理也非常容易出错。

本文将会介绍三种方案来解决前后端协作的问题:

  1. 基于注释的 API 文档:这是一种通过代码中注释生成 API 文档的轻量级方案,它的好处是简单易用,基本与编程语言无关。因为基于注释,非常适合动态语言的文档输出,例如 Nodejs、PHP、Python。由于NPM包容易安装和使用,这里推荐 nodejs 平台下的 apidocjs。
  2. 基于反射的 API 文档:使用 swagger 这类通过反射来解析代码,只需要定义好 Model,可以实现自动输出 API 文档。这种方案适合强类型语言例如 Java、.Net,尤其是生成一份稳定、能在团队外使用的 API 文档。
  3. 使用契约进行前后端协作:在团队内部,前后端协作本质上需要的不是一份 API 文档,而是一个可以供前后端共同遵守的契约。前后端可以一起制定一份契约,使用这份契约共同开发,前端使用这份契约 mock API,后端则可以通过它简单的验证API是否正确输出。

基于注释的 API 文档

apidocjs 是生成文档最轻量的一种方式,apidocjs 作为 npm 包发布,运行在 nodejs 平台上。原理为解析方法前面的注释,使用方法非常类似 javadoc 等程序接口文档生成工具,配置和使用都非常简单。因为只是解析代码注释部分,理论上和编程语言无关。

安装:

npm install apidoc -g

在需要输出文档的源代码中添加一个一个注释示例:

最小化运行:

apidoc -i myapp/ -o apidoc

即可在 apidoc 中输出静态的 html 文档目录。如果指定配置文件 apidoc.json 可以定义更多的操作方式,也可以自定义一套 HTML 模板用于个性化显示你的 API 文档,另外在输出的 HTML 文档中附带有API请求的测试工具,可以在我们生成的文档中尝试调用 API。

使用 apidocjs 只需要添加几个例如 @api、@apiname、@apiParam 等几个必要的注释即可,值得一提是 @apiDefine 可以定义变量避免重复书写,@apiGroup 用来对 API 分组,@apiVersion 可以再生成不同版本的文档。

基于反射的 API 文档

apidoc 的缺点是需要维护一些注释,当修改源代码时需要注意注释是否同时被更新。不过如果你使用的是 Java、.Net 等强类型语言,就可以利用强类型语言的优势。

在这个领域最好用的文档工具当属 swagger,swagger 实际上是一整套关于 API 文档、代码生成、测试、文档共享的工具包,包括 :

  1. Swagger Editor 使用 swagger editor 编写文档定义 yml 文件,并生成 swagger 的 json 文件
  2. Swagger UI 解析 swagger 的 json 并生成 html 静态文档
  3. Swagger Codegen 可以通过 json 文档生成 Java 等语言里面的模板文件(模型文件)
  4. Swagger Inspector API 自动化测试
  5. Swagger Hub 共享 swagger 文档

通常我们提到 swagger 时,往往指的是 swagger ui。而在 Java 环境下,可以通过 Springfox 来完成对代码的解析,再利用 swagger 生成文档,下面我们给一个简单的例子看怎么给一个 Spring boot 项目生成文档。

首选加入依赖(gradle 同理):

全局配置:

我们的 controller,需要定义一些必要的注解来描述这个 API 的标题和解释,我们返回的 user 对象是一个简单 value object,swagger-annotations 包下面提供了很多注解可以满足更多的定制需求。

然后访问你的 context 下的 /{context}/swagger-ui.html 页面,你会看到一个漂亮的 API 在线文档。swagger 的文档上能看到具体的字段定义和 Model,如果修改了 Model,再次编译后则可以自动反应到文档上,这也是反应了强类型编程语言的优势之一。

基于契约的前后端协作

在过去的开发中,往往是后端开发者占主导,像上面的两种方案中,直接注释、反射通过生成 API 文档。

但前后端分离后让合作方式发生了变化。传统的方式往往是服务器开发者完成了 API 开发之后,前端开发者再开始工作,在项目管理中这样产生时间线的依赖。理想的情况下,在需求明确后,架构师设计,前后端应该能各自独立工作,并在最后进行集成测试即可。

后端开发者可以根据文档实现接口,最后按照文档联合调试即可,甚至通过契约生成 API 调用和数据承载的 VO (Value Object),减少工作量。如果 API 的提供者想做的更为完善一些,可以使用契约文件来验证实际 API 输出输出是否合理。

契约测试

当我们使用契约文件来提高前后端协作开发的体验,其中很重要的一部分就是契约测试,关于契约测试,我们一般指的是 Martin Fowler 提出的概念 —— “消费者驱动的契约”

简单来说,就是前后端开发者协定好后,由消费者驱动,通过编写 API 调用层相关的代码,可以直接生成契约文件。由于一个 API 可以被多处消费,所以消费者驱动可以更好的管理契约的变化(如果 API 验证契约时不能通过,说明契约被破坏了,可以在 CI 上马上反应出来)。

(Pact 契约测试模型)

写契约测试的博客非常多,就不展开赘述了。我把契约测试放到了前后端协作这个部分,是因为契约测试的前提是建立在前后端良好的协作下实现的。“契约测试”关注的是契约,而不是测试。

实际工作中,退一步说,制定好契约就可以完成基本的开发工作,对契约测试、验证可以让前后端协作变得更为可靠。如果你现在还没准备好使用契约测试的话,也不必焦虑,手动定义契约可以让前后端协作先运行起来。

而如果你恰好使用了 Spring boot 全家桶的话,不妨看看 Spring cloud contract。

使用 Swagger Yaml 契约

前面在讲 swagger 的时候,提到了Swagger Editor,使用这个工具可以通过编写 API 定义文件(Yaml格式),它提供线上版本,也可以本地使用。

后端通过生成 API 定义文件,就可以进一步完成生成 HTML 静态文档、模拟 API 数据等操作。

前端开发者可以通过 swagger 的 node 版本 swagger-node 自带的 mock 模式启动一个 Mock server,然后根据约定模拟自己想要的数据。 关于在前端使用的 mock server,实在太多,而且各有优劣,在附录中有一个清单以供参考,不再赘述。

使用 RAML 契约

使用 Swagger Yaml 契约或者 Pact 契约都能在一定程度上完成契约测试、生成文档、mock 等工作,但是我们在实际工作中发现这些工具和平台的契约规则并不相同。

Swagger 在生成文档上非常优秀,然而在契约测试上不及 Pact,反之亦然。

随着引入微服务和开放的互联网项目越来越多,前后端协作的问题越来越明显,而解决上述问题的工具和技术并不通用。好在业界早已认识到这个问题,于是一些组织提出了 RestFul API 统一建模语言 (RESTful API Modeling Language),也就是 RAML。

围绕着 RAML 这一标准,构建出 API 协作的工具链,设计、构建、测试、文档、共享。

其他前后端协作实践

中心文档服务器

在一个大型的团队中,可能会有几十个以上的项目同时提供了 API,这种情况下如果每个应用都各自提供API文档就会变得很难管理,如果将 API 文档绑定到应用服务上会带来一些无意义的损耗。可以使用一个集中地服务来存放这些文档,类似于 github 的私有仓库,swagger 同样也提供了类似的服务 – swaggerhub.com

即使不使用 swagger ,我们可以构建出 HTML 文档然后每一次输出部署到一台静态服务器,也是非常容易的事情。

  1. 如果是开源或者对外的 API,可以借用 GitHub Page 来创建我们的文档服务
  2. 针对团队内部,诸多云服务商均提供了静态服务器,例如 AWS 的 S3

管理契约文件

既然是契约文件,就不应该是API提供者或者消费者单独拥有的,即使只有一个调用方,至少是前端、后端共同拥有的。

那么契约文件应该怎么放呢?

我们之前一直放到API的代码仓库中,然后给所有的人添加了权限。后来发现这样做非常不方便,于是单独增加了一个管理契约文件的 git仓库,并使用 git 的submodule 来引用到各个涉及到了的代码仓库中。

将契约文件单独放置还有一个额外的好处,在构建契约测试时,可以方便的发送到一台中间服务器。一旦 API 契约发生变化,可以触发 API提供的契约验证测试。

附录:API 文档工具清单

  • 使用或调研过的,API 文档/契约生成工具
    1. apidoc
    2. swagger
    3. blue sprint
    4. RAML
  • 使用或调研过得 mock 工具清单
    1. wiremock
    2. json-server
    3. node-mock-server
    4. node-mocks-http
  • HTTP 请求拦截器
    1. axios-mock-adapter
    2. jquery-mockjax
  • 契约/API 测试工具
    1. Spring Cloud Contract
    2. Pact
    3. Rest-Assured

更多精彩洞见,请关注微信公众号:ThoughtWorks洞见

Share