先说两句

这个易燃易爆的话题,其实俺是不敢写的。在工程师队伍里滥竽充数了几年,俺觉得自己还没被清理和淘汰出去,已经谢天谢地了——不赶紧回去提高姿势水平,居然还在这里装大尾巴狼,大言不惭地讨论如何评估程序员,其心可诛啊。

那为何俺还要冒码农之大不讳,在这里妄议是非,大放厥词呢?是因为俺发现,在日常工作中,对于一些非技术向的小伙伴们,由于对工程师文化了解并不多,要么难以寻找到合适的技术伙伴,要么在工作中与工程师难以保持稳定的沟通节奏,对于这些小伙伴,俺愿意把俺知道的分享出来,肤浅也好,片面也罢,总之是多了一点参考,希望能有所帮助。


1. 对技术的分析和判断力

技术没有先进与落后之分,只有适用与不适用。如果你经常听某个程序员对你说 “xxx 很先进,比 yyy 好多了,应该用 xxx 就不会有这些问题了”,“xxx 非常强力,BAT (此处可换为任何一个公司名) 的 yyy 项目以前用的是 zzz,现在都改用 xxx 了” 那么就要对他的判断力打个问号了。


下面是一些包含更多价值的例子,

  • “xxx 虽然在 aaa 方面不太好,但比 yyy 更适合我们的项目,因为我们眼下更需要 bbb 和 ccc,将来如果在 aaa 方面出了问题,我们可以做这样的调整: 1... 2... 3...”
  • “我们之所以不用常规方案 xxx,而是用更激进一点的 yyy,是因为我们的项目在 aaa 和 bbb 等方面没有那么强的约束,虽然损失一些 ccc,但是可以获得更高的 ddd 和 eee”

如果你发现一个程序员,行走都把某个特定的平台/工具/技能/编程语言挂在嘴边,“xxx 就是好啊就是好”,你就会知道他不仅有选择上的局限性,也会在技术判断中不可避免的因为已有的积累产生偏见,正所谓“手里握着锤子的时候,满世界长得都像钉子”,一般这种程序员,俺称之为“信徒式程序员”。

2. 对待预估任务时间的态度

诚实是一个重要的品质。相比起对他人的诚实,对自己的诚实就更难了。

举个例子,你答应了两个礼拜后交付一个版本,可是因为某些原因,一个礼拜过去之后,你发现自己还需要两个礼拜,这时你会如何选择呢?

诚实的态度是,承认自己的时间预估是不准确的,要么砍掉一部分计划,按期交付,要么保证功能的完整性和质量,延期交付。如果一方面拍胸脯保证能按时交货,另一方面罔顾负荷与节奏,过度地挤压,就是不诚实的表现。这样短期内能获得更好的 KPI,但工程质量,团队士气都会受到打击,长远看得不偿失。诚实余额不足的协调者,惯用这种伎俩,通过各种手段,汲取和消耗组织的能量来为自己的 KPI 充电。更糟的是,这会使组织对团队的能力做出有偏差的判断,进一步放大问题,以致走上一条不归路。

正确地预估任务时间,是一项需要经年累积才能有一点点成长和收获的技能。任何一项任务,有经验的开发者给出的不是一个拍脑袋的日期,而是包含以下诸要素的整体判断:

  • 完成核心功能需要的时间预估
  • 完成次级功能和周边工具链的时间预估
  • 系统集成,稳定化,性能优化的时间预估
  • 预留的缓冲周期

有经验的程序员对计划中的弹性点保持敏感,计划会随着实际进展不断调整,不会刻板地拘泥于原计划。他们的计划会尽量做到诚实且忠实地反映实际的进展情况。如果突发情况造成了计划外的影响,能及时地去做出调整,并向需要的人更新状态。

3. 为自己的工作建立明确的边界

所谓“明确的边界”,就是能尽早地建立明确的头脑模型,尽早摸清楚 (在你负责的领域内) 什么必须做,什么可以做,什么不能做,什么做不了。

有明确的边界会带来很多显性和隐性的好处。最重要的好处是,大家的需求关系明确化、协议化,不再依赖私下的潜规则,会节省后续大量的沟通成本。其次,愿意为自己的工作范围建立明确的边界的程序员,对边界内的代码质量通常会有强烈的责任感和主人翁意识,他们会比其他人敏感和熟悉得多,在他们的地盘上,他们能彻底的说了算。相关系统内如果出了问题,让其他人来可能要修两三天,换他来可能凭着对相关代码的熟悉度闭着眼睛就说出几个可能的问题点。

充满各种潜规则的系统非常脆弱,如果你发现一个程序员总在焦头烂额地处理沟通事务,往往就意味着隐患已经浮现出来了。缺乏边界意识的程序员,往往伴随着对代码较低的责任心。他们不把自己工作的代码看做是“自己的”,自然也就不会尽心尽力地去好好维护。

有种流行的说法是,应该通过某种形式的“轮换”,把程序员打造成“可轮换的”螺丝钉和多面手,以降低人员流失带来的风险。也许这一方式对其他行业会很有效,但至少在游戏行业,我发现,被这样轮换的程序员,这样来过几次之后,确实是对彼此的系统更熟悉了没错,但他们变得不再像之前那样“精心地”照料自己原本负责的那片代码。因为被 n 个人按自己的思路修理过之后,他们已经失去了“对那片代码的爱”,他们逐渐慢慢地从“园丁”变成了“游客”。随着时间的推移,没有人对这个模块内部的所有可能状态了如指掌,曾经被精心照顾的花园慢慢地变成了废弃的垃圾场。每个人改到这里都是无奈地捂着鼻子赶紧弄完了事,只要不要弄出新的问题就谢天谢地。这种腐化通常是加速而且不可逆的,从工程角度来讲,这往往预示着这一堆代码的废弃。更残酷的是,程序员们纷纷发现在这个项目里无法积累真正的领域相关经验,成为专家,还有什么比天天围着一辆二手车的不同部位反复修理又得不到成长更糟糕的事呢?他们唯一合情合理的选择,就是拂袖而去,或是准备以温和一点的方式拂袖而去。

程序员对代码的爱是一个项目里最稀缺的资源之一,不要忽略它,更不要粗暴地碾碎它,要通过创造稳定的环境和氛围去创造它,培育它,这样的代码库才能成为肥沃的土壤,带来源源不断的回报;否则就会变成一个摇摇欲坠、四处冒烟的,靠巧合来得以运行的庞然大物。

4. 对“异端”的相容度

「托利得定理:测验一个人的智力是否属于上乘,只看脑子里能否同时容纳两种相反的思想而无碍于其处世行事。」

这句话有三层递进的意思:

  1. 具有包容性。能够理解矛盾各方的情势,对盲点敏感,不容易被蒙蔽。
  2. 具有批判性思维。能用理性和逻辑等工具去分析问题,形成自己的判断,不盲从。
  3. 具有人格独立性。依本性从事,不存偏见。

这三样对于程序员来说,都是比较重要的软素质。寸步不让,主导意识强烈的程序员,往往有着惊人的自信——要注意这种自信有时会成为双刃剑。在讨论中展现出不必要的自信,往往在令人屈服的同时,促使对方从“奉献者”转变为“打卡者”,降低整个团队的战斗力。

5. 对每一项提交记录 (日常工作成果) 的态度

有经验的开发者从一个程序员的提交记录里,能读出太多的东西:

  • 对于高素质的开发者,你能不费太大力气就能顺畅地读出他近期做了哪些方面的工作;在哪些点上曾遇到了困难,选择的解决方案是什么;当他权衡和折衷时,考虑的最多的是什么因素;在一段时间内,贡献相对均匀 (DPS 能保持在相对稳定的节奏)
  • 而相对的,如果你在提交记录里看到不少 “临时方案”,“暂时先注掉”,“先跑起来晚点再改” 这样的句式,或者提交信息简短到像发电报,或者提交一大堆代码却不写提交信息,那么这样的程序员的实际贡献意愿和实际产出结果就要打个问号了。

查看一个程序员的 commit history,一眼扫过去,如果除了 “完成了xx功能” “修复了 xx bug” 等信息之外,还有一些 “改善了 xxx 的内部结构,方便后期维护”,“简化了 yyy 的接口,降低了跟 aaa 和 bbb 的沟通负担”,“自动化或移除了 zzz 的操作,省去了跟 ccc 的额外沟通和确认的步骤” 你就可以知道,这个程序员不仅业务能力过硬 (勉强能完成任务的程序员,是很难有余力去操心这些事的),而且对项目也有足够的责任心和爱心,愿意把自己的真正心血奉献给项目,而不是想方设法总是凑合和应付,“先弄出来再说,哪管之后洪水滔天”。

其实,这也是最快的考察工程师团队的一个方法——一个团队的做事方式,效率,甚至是士气和状态,从 commit message 上能读出大量的细节,而不少信息是从平常的交流里无法提取和判断的。

6. 对待交付的态度

有经验的程序员明白,提交功能的那一刻,只是交付的开始。这一点具体请详见这一篇:不要说谎 (Don't lie.),这里就不多说了。

7. 对待技术欠债的态度

一个快速前进的团队不可避免地会留下或多或少的技术欠债,这是敏捷所要付出的最大成本之一。并非所有的技术欠债都需要偿还,它们中相当一部分实际上会随着开发风向的变化被直接风干和丢弃。有经验的程序员会时常为自己的日常工作留出处理技术欠债的时间,他们会及时查遗补缺,趁着手头任务的余温,补上因为快速开发而遗漏的东西,同时果断抛弃那些越积越重的包袱,尽量轻装上阵。

如果你观察到一个程序员总是乐于做新东西,他的提交记录里缺乏对已有系统的梳理和重构,那说明他更适合作为突击队员,还不能适应作为一个组织者的角色。

8. 对待人员流失的态度和处理方式

有经验的程序员永远不会故作惊讶,对同事或下属的离职假装出惊讶的样子。他们总是“Work for the best, prepare for the worst”。他们在过去的经历里吃过亏,明白“靠山山会倒,靠人人会跑”,所以早在一个生力军加入自己负责的团队之前,他们就会计划好此人一旦离开时的善后处置工作。他们不会轻易让自己的团队没有原则地进人,也就不会让自己负责的业务因为某一个人的离职变得失控。

但这绝不是在说他们对人员流动无所谓,不会主动捍卫自己团队成员的利益。正相反,他们会重视每一个做出贡献的成员,竭尽所能地为他们争取应得的尊重;他们会把哪怕只贡献过一行代码的离职同事都仔细地整理出来,放在 Credits 里的合适位置,以确保他们的工作得到认可;即使某些成员在自己负责的团队内表现不佳,当这些成员离开时,他们尊重个体的选择,并仍愿意给予力所能及的最大的帮助,因为他们清楚地知道,同一个人在不同的环境下,也有可能激发出完全不同的能量。

进阶阅读

读完这一篇以后,如果觉得俺写的水分太多没什么卵用的话,可以移步这里,读一下这篇进阶读物,“What makes a good lead programmer”。


嗯,差不多就是这些吧。对于还在寻觅中的小伙伴,希望这些文字能够帮助你更好地判断,锁定和捕捉适合自己的野生程序猿 O(∩_∩)O~~ 而对想多了解一下工程师的小伙伴,也希望能促进几分彼此的理解和包容 <( ̄︶ ̄)>

不说了,我先去搬砖了~~

Gu Lu
[2015-11-05]


[注]


[2015-11-07] 补:

有同学提到,

有些地方不敢苟同,技术还是分先进和落后的,例如百度推送和个推

这里俺说明一下,“推送和个推”是技术,“百度推送和个推”是百度对这个技术的理解和实现。用后者的质量来衡量前者的好坏,是常见的误会。当然了,新的技术总会逐渐取代老的技术,这个是发展的必然,所谓“技术没有先进落后”,着眼点在于“平等而不含偏见地”对待各种技术,以“是否适用具体情况”来择而用之。

Comments
Write a Comment

Tags

游戏开发   随笔   Programming   C/C++   优化   Unity   C++   知乎   游戏设计   比特币   Unity3D   区块链   软件开发   引擎设计   系统架构   Production   idtech   中国文化   加密货币   项目管理   Bitcoin   游戏评论   资源管理   资源流水线   效率   道德经   网络   方法论   模板编程   Lua   Oculus   GDC   渲染   VR   PerfAssist   Unity MemoryProfiler   BCH   经济学   信息过载   行业报告   字体   Productivity   图形   网络编程   Dice   协程   EMC   Premake   测试   中间件   Game Engine   新手引导   Methodology   CI   命令行解析   goroutine   ndk   Ethereum   nanomsg   自动化   Scripting   摘录   Debugging   同步技术   cppcon   C++模板   DOOM3   技术评估   Unity GC   C++11   学习方法   Surface Pro 3   Engine Evaluation   CRT   文化   Blockchain   笔记   golang   图形编程   多线程   ETH   Blockchain Computing   Bitcoin Cash   cppcon14   Bitcoin SV   Visual Studio   Unity Coroutine   跨语言可变参数列表   团队协作   货币   Deployment   Visual Assist   工程改进   Michael Abrash   exp   开放世界   域名   虚拟现实   系统重构   slua   遮挡剔除   完美转发   协作式调度   Modern C++   类型推导   Memory Debugging   个人成长   小故事   BTC   暴雪   产品   历史   错误处理   Unity Profiler   MOD  

知识共享许可协议
本作品由Gu Lu创作,采用知识共享Attribution-NonCommercial-NoDerivatives 4.0 国际许可协议进行许可。