那些年,我见过的那些“废柴”

在我们的日常工作中,和其他人一起合作在所难免。与三观未知的他人朝夕相处往往不啻于一场冒险。那些传说中行云流水般流畅的合作似乎仅存在于书本中,现实世界中的合作则常常难以契合,大多互相掣肘,不得通畅。毫无疑问,在众多的项目中,与我合作过的很多同事都令我大开眼界并深受启发,并在或长或短的合作中受益良多。作为对比,同样有很多同事(我把一起工作的人们都成为同事,而并不特别区分内部外部,比如团队上的其他合作方也可以视为同事)则从相反的方向令我印象深刻。

我仔细回想,如果整理出一个“我最不希望与之合作的人之特质”的清单的话,一来或许可以警示自己不要成为这样的人,二来潜在地也可以让具备这些特质的人从中受益。古语有云:有则改之,无则加勉,此之谓也。

  • 无法根据事情的重要/紧急程度划分优先级而导致自己疲于奔命的
  • 只知道抱怨而不着手解决问题
  • 能说不能做的
  • 固步自封,不思进取
  • 急于撇清责任,将自己置身事外
  • 缺乏责任感,将问题归类到自己无法的力量的

不会化分优先级

在一个团队中,效率最低的当然是那些什么都不干的人。不过可能与大部分人的直觉相反的是,什么都做的那个人效率是倒数第二低的(如果不是最低的话)。这样的人被巨大的backlog支配,深陷其中而无法自拔,各个未完成的任务可能还会互相影响,直至崩溃。很多时候,这些人手头的工作甚至都不是被分配的,而是他们自己揽上身的。

如果你认为所有任务都很重要,也就意味着所有任务都重要。具体来说,这样的做法有很多潜在的问题,对于个人和团队都有很大坏处:

  • 个人成为信息孤岛
  • 由于太多并行任务,无法真正完成某一项任务
  • WIP(work in progress)队列变的无限大
  • 成为团队的瓶颈

正如《凤凰项目》中描述的场景,那个Superstar成员成为了团队中最大的瓶颈。当那个Superstar的带宽被完全只用之后,所有的在队列中的工作都需要进入等待状态,而这个曲线是呈指数态势增长的。

一个优秀的团队成员,需要在某种程度上遵循UNIX哲学中的一条原则:每次仅完成一件事,并将其做到最好。当然,这并不妨碍一个团队成员在很多方便都有优秀的技术专长,重点是:在每次任务重都专注的做好某一件事。

最有意思的是,在这种情况下,即使这位同事的主观意愿是好的,个人能力是出色的,但是从外部来度量整个团队的产出的话,其效率会低于平均水平中等,但是任务分配合理的团队。也就是说,在策略上有缺陷的事实上是在帮倒忙

祥林嫂式的抱怨

在我早年的一个项目上,在一个产品的研发进行到某一阶段后,团队进行了一次类似于Bug Bash的活动:收集产品中潜在的设计缺陷(包括可用性以及功能性的设计)。有一位同事从各个方面提出了近30条发现的“问题”,但是几乎没有给出一条有用的建议。基本上就是一副:这个产品是个彻头彻尾的垃圾,而我也不知道怎么能把它变得更好的心态。后来团队只好草草结束了这个有始无终的设计缺陷收集,而重新开始做一些Up Front Design

在工作中这种人是非常容易招人厌恶的。一方面他们往往散发着浓郁的负能量,看着什么都充满怨念,另一方面,他不愿意或者不能够提出任何有效的改进方法。

应该注意到的是,提出问题 – 特别是不需要自己去费力解决的问题 – 是很容易的,而能想到可能的解决方案则相对困难。更进一步,想到一个直观的方案很容易,而给出多个选项,并对比各自的优劣则很困难。最后,如果你想要真正解决问题,或者让工作实际有所推进,那就需要尝试多做一些困难的事情(比如罗列并对比可能的方案,并给出可行的计划),并尝试简化他人的工作。

眼高手低

事实上,业界有很多坐而论道的大神。言必称高内聚、低耦合,动辄S.O.L.I.D,对各种编程范式更是如数家珍。但是具体到动手的时候,要么顾左右而言他,要么勉强写出几行未必能通过编译的代码,而内容则不忍卒读。

遇到这种情况,我会在他用鼠标哆哆嗦嗦的在文件列表里逐个找文件的时候把键盘抢过来,然后确保不让他碰键盘。如果心情好的话,我会规劝他多动手写一些代码。

要解决这个问题,方式其实并不复杂。胡适说:多研究些问题,少谈些“主义”。要我说,应该多写写业务代码,少谈些理论。我们都知道,在实践中,用TDD写个FizzBuzz是一回事儿;用相同的方法和原则把复杂的业务逻辑抽象并归类,则完全是另一件事儿。

这些人往往会混淆了知道能做到间的界限,知与行并不统一。正如那个著名的画马的漫画所要表达的那样:

大部分情况下,我们缺少的不是用简笔画画出几个圆圈,而正是那些被轻视的细节。无论如何,我们的各种理论最终还是要体现在可以真正执行的软件代码上。

Talk is cheap, show me the code.

Linus Torvalds

一些可供参考的常见的技巧是:

简而言之,坐而论道,不如作而行之。

致命的舒适区

这种人痛恨变化,这种情感可能来自于过往项目中引入新技术之后的负面的体验,或者纯粹的对新鲜事物兴趣的缺失,又或者二者兼而有之。总之你从他们口中经常听到的是诸如:“为什么不用redux”(因为redux我比较熟),或者为什么要用“Material-UI”(因为我不会)。事实上,这种情况甚至会发生在那些曾经热切而激进的技术人员身上。

大多数情况下,是他们没有勇气走出“舒适区”。他们误以为目前已经熟练掌握的技术永不过期,且是解决手头问题的最佳方案。然后现实是,没有什么是不变的。技术很快会过期,通常比我们想象的要快很多。

在我入职ThoughtWorks的时候,RoR是西安办公室的主流,前端的Backbone+Jasmine算是新的技术,而两年后一些团队开始零星的试点Angular1.2bowerPhantomJS等,而如今这些技术都去哪儿了呢?React+ReduxGraphQL在很多场景下确实可以简化前端的工作,不过谁又知道下一个breaking change正在何处默默酝酿呢?

固步自封相对的另一个极端是追逐一切新奇的事物,这样的做法亦不足取 – 它会浪费你大量的时间和精力在那些可能永远不会涉及的技术上。

尽管如此,我觉得作为开发者至少可以做的是:对新技术保持好奇和新鲜的态度,同时与其保持一定的距离。你未必需要在下一个项目中就采取Github Trending上的明星框架,但是花一些时间来保证自己了解其与同类产品的优劣对比,以及主要的应用场景等可以使你不至于在做技术决策时过于盲目和偏颇。

后端返回的数据不对

在有明确的前后端分工的团队中,前端开发负责界面的实现,同时消费后台API返回的数据,并可能做一些可能的数据格式化等;后端则负责于下游服务的交互,并组织数据供前端呈现。这种工作模式下的一个极端的情况是前后端仅仅通过契约来协作,一端对于另一端完全忽略并视之为黑盒。表面上来看,这种隔离在可以带来一些益处:前后两端的进度相对独立,互不影响。不过我始终怀疑这种机械的割裂真的可以带来它所承诺的好处。

不过其带来的问题往往非常显著:由于延迟的集成导致延迟的价值交付。更严重的是后果是人们会对于团队作为整体为结果负责这一根本问题的忽视,当出现问题时则往往互相指责。我听到太多次前端开发抱怨:“这个是后端API的问题”,或者“这个问题是后端没有处理网络超时所致”,而理所当然的将问题简化为“别人的问题”。

“这是后端API的问题”这个描述本身是没有问题的,但是它不应该作为一个问题的结论,恰恰相反,它应该是进一步探索的开端:一个更系统的,更端到端的解决问题的方案的开端。这个描述可以指导物理上分离的两组同事一起面对问题,并找出适合当前架构的方案。

历史遗留问题 Legacy problem

我常常看到有人抱怨自己工作的遗留代码如何如何糟糕,添加新功能如何如何困难等。当你尝试challenge他为何对这些问题不做出行动的时候,他会告诉你这些都是历史原因 - 这段代码本来就是这样写的。

在实践中,这种情况往往和其他一些症状并行发作:

  • 不了解业务(没有意愿理解业务)
  • 不了解技术决策(可能由于系统中缺乏诸如ADR的记录等)
  • 重构能力欠缺
  • 高层次的自动化测试缺失

这种情况和“这是后端的问题”本质上可以算作同一类,都是尝试将自己置身事外,并将问题归因到另一些人(即使所谓的历史遗留代码就是他们自己写的)。如果说在某些情况下,比如后端是另一个团队,甚至是另一家公司提供的代码,“这是后端的问题”尚可作为一个借口的话,那么“历史遗留问题”的说法则是完全是无稽之谈。

这样的说法刻意的将自己描述成对糟糕现状无能为力的受害者,就好像是说,假如有一个理想的起点 – 比如让我从新开始写 – 他就一定可以做的比现在好。但是我们都知道,这种假设是未必成立的。事实上,当你决定要写点代码出来的那个时刻起,代码和架构就已经在准备腐坏了,除非你花费足够多的时间和精力去将其不断完善和修葺。而这正是事物的本性,并不随着人的客观意志为转移。

因此,压根不存在历史遗留问题这回事儿,它们只是普通问题。解决问题的第一步,永远是直面问题,认识到所谓的历史遗留问题是和我们将要开发的新需求,或者要修复的线上bug,以及刚刚sign off的卡上的一个微小变更并无二致。

简单来说,我们可以像故事墙那样维护一个技术债务板,并定期维护,按照工作量和价值来划分优先级,然后按部就班的将其消除。

我在很多遗留项目上工作过,有一些是接手时就已经存在了很长时间的老代码,另一些则是从头开始写但是随着需求的增加和改变而逐步腐化的。我发现行之有效的方法就是用对待老旧代码那样对待自己新写的代码 – 建立测试以形成安全网,做适度的重构(小到重命名一个变量,大到删除一个模块),并让代码比之前变好一点点。

当然,这需要整个团队每个成员都对代码质量有相类似的理解和足够的动手能力,同时也需要持续的投入心血和精力来维系。

小结 Summary

本文列举了一些我在各个项目中遇到的各种不靠谱的同事,包括内部和外部的一起工作的人们。甚至我自己在不同阶段也可能展现出这里列举的某些类型的特质。

  • 无法根据事情的重要/紧急程度划分优先级而导致自己疲于奔命的
  • 只知道抱怨而不着手解决问题
  • 能说不能做的
  • 固步自封,不思进取
  • 急于撇清责任,将自己置身事外
  • 缺乏责任感,将问题归类到自己无法的力量的

正如上面讨论过的,解决问题的第一步永远是承认并正视问题。唯有又勇气和魄力做到这一点,才可以接着讨论如何解决它们。如果仅仅列出问题而不讨论解决方案,那么我自己就变成了上述的“祥林嫂”式了。好在这些问题都可以通过技术手段消除(和上述问题依次对应)。

  • 按照价值决定优先级
  • 通过刻意训练保持动手能力
  • 抱怨之外,要顺带提出自己的观点(有备选方案更佳)
  • 保持好奇心
  • 通力合作而非互相指责
  • 正视问题,并逐步解决

参考