原文转载自 Antirez
翻译:江宏
在编程界的传说中,一个 10x 程序员可以完成普通程序员十倍的工作量。所谓普通程序员,可以想象是一个擅长他/她的工作,但没有 10x 程序员那样神奇能力的人。更好地描述「普通程序员」的说法是它代表了专业程序员里平均的编程输出水平。
编程社区对于这种动物是否存在有两极分化的看法:有的人认为根本不存在,有的人却认为不仅存在 10x 程序员,如果你知道怎么寻找的话,甚至能找到 100x 程序员。
如果你认为编程是一个「线性」学科,很明显 10x 程序员存在的可能性看起来确实不符合逻辑。跑步者如何做到比另一个跑者快 10 倍?或者说一个建筑工人在相同的时间内如何做到其他人十倍的工作量?然而,编程是一种很特殊的设计学科,即使当程序员不参与架构上的实际设计时,在实现一个产品时,仍旧需要对实现策略进行设计。
所以如果程序的设计和实现不是线性能力,那么在我看来,工作经验、编程能力,知识储备,辨别无用组件的能力等都是非线性的优势,它们以乘积的方式在产品开发中发挥作用。当然,当程序员能同时负责软件的设计和实现时,这种事半功倍的现象就更多了。一个任务越是「目标导向」,潜在的 10x 程序员就越有空间利用她/他的能力以比别人少很多的努力达到目标。当手头的任务更僵化,对开发工具及实现方式有很多限制时,10x 程序员在更短的时间内完成更多工作的能力就被削弱了:它仍然可能利用对「局部」设计的把控来做的更好,但却无法根本上改变到达目标的路径,包括把设计规范的某些部分彻底去掉,以大大减少工作量却达成几乎同样的目标。
在作为程序员工作的二十年里,我观察过很多和我一起工作的程序员,由我指导以达到既定目标,如为 Redis 和其他项目提供补丁。正是在这些协作过程中,很多人认为我是很高效的程序员。考虑到我远非工作狂,我就以自己为参考来谈谈如何快速开发。
以下是我认为对编程效率影响最大的几点特质。
纯编程能力:完成子任务
程序员最明显的优劣势体现在实现程序的一个部分的子任务中,包括函数,算法或其他任何东西的实现。令人惊讶的是,根据我的经验,非常有效地使用基本指令式编程工具以实现某些东西的能力并不像大多数人认为的那么普遍。在一个团队中,有时我观察到非常不称职的、甚至简单的排序算法也不知道的程序员能完成的工作却比理论上应该很强在实践中却很弱的大学毕业生要多。
经验:模式匹配
我所说的经验指的是已经探索过的一系列重复性任务的解决方案。经验丰富的程序员经过积累最终知道如何处理各种子任务。这不仅能提高效率,也是防止设计上的错误的强大武器,这些错误往往是简化设计的最大敌人。
重点:实际时间 VS 假设时间
不看质量光看编程花费的时长是毫无意义的。内部和外部因素都可能影响你的专注程度。内部因素是拖延症、对项目缺乏兴趣(不喜欢的事情你一定无法全身心投入)、缺乏锻炼、睡眠不好或很少等。外部因素是频繁的会议、工作环境不佳、经常被同事打断等等。很自然,提高专注度,减少中断对于提高开发效率有不可忽视的作用。有时为了集中注意力,需要采取一些极端措施。比如我,通常只在固定时间收发电子邮件且只回复重要部分。
学会取舍:通过干掉 5% 来获得 90%
当人们不愿承认一个非根本的目标造成了很大一部分设计的复杂度,或者因为一个根本功能和一个非根本功能之间存在取舍压力而造成更重要的目标难以达到时,复杂度就产生了。对设计者而言,认识到设计中难以都实现的那些部分非常重要,也就是说,付出的努力与收益不一定是成正比的。在项目中为了获得最大收益,就需要专注于能在有限的时间内完成的最重要的部分。例如,在设计消息代理 Disque 时,我意识到通过只尽力(而不是绝对)保证消息的顺序,项目的其他方面都可以得到实质性的改进:比如可用性、查询语言以及客户端交互、简洁性和性能等。
简洁性
这是一个显而易见的观点,这一点至关重要。为了理解简洁性,有必要检查复杂度都是如何产生的。我认为复杂度的两个主要驱动因素是不愿意进行设计上的牺牲,以及设计活动中错误的积累。
仔细考虑设计的过程,每一次错误选择都使我们离最优解决方案更远。一个最初的错误当遇到错误的人时,不会导致这个系统的重新设计,而会导致设计另一个更复杂的方案来应对这个错误,因此,这个项目就随着每个错误的出现而变得更加复杂和低效。
简洁性可以通过在脑子里进行“概念验证”的推理来实现,这样可以让程序员设想大量的简洁的设计,然后动手实现看起来最可行和最直接的方案,随后再靠经验和个人设计能力改进设计,并为子级设计找到合理的方案。
然而每当需要一个复杂的解决方案时,都有必要花很多时间思考如何避免复杂度,只有在考虑过各种替代方案后都没发现更好的选择之后再继续朝那个方向走。
完美主义,或者说如何牺牲生产力并引入设计偏见
完美主义有两种类型:一种是让程序的可量化性能达到最优的工程师文化,另一种是人格特质。我认为这两种情况下完美主义都是程序员实现快速交付的最大障碍。完美主义和对他人评价的恐惧会导致设计偏差,导致选择不当,仅根据心理或无关紧要的可量化参数来改进设计,却从未考虑诸如程序的健壮性,简洁性,及时交付能力之类的事情。
知识:一些理论会有帮助
在处理复杂的任务时,关于数据结构,计算的根本局限性,适合特定任务的重要算法等的知识将会对找到合适设计的能力产生影响。并没有必要在各方面都成为一个超级专家,但知道一个问题的多种潜在解决方案是必须的。例如,接受设计上的牺牲(接受一定错误率)并了解高概率地估计集合大小的方法,可以避免设计出复杂,缓慢和占用大量内存的从流数据中计算唯一元素数量的方案。
底层:了解机器
即使是在使用高级语言时,有很多程序里的问题都是由对计算机完成特定任务的方式产生误解造成的。因为所使用的工具或算法存在根本问题,这甚至可能导致项目需要从头开始重新设计和实现。掌握好 C 语言,理解好 CPU 如何工作以及搞清楚内核如何运行、系统调用是怎样实现的,可以避免在后期出现严重的意外。
调试技巧
花费大量时间找 Bug 是很常见的事。如果你善于逐步获取 Bug 状态以用理性的步骤修复,并且编写代码的时候注意尽量简化以减少 Bug,就可以大大提升效率。
在我看来,以上这些特质对输出产生 10 倍的影响并不奇怪。它们使得好的实现可以从一个可行的模型和比替代方案简单数倍的设计开始。有一种强调简洁性的方式,我喜欢称之为「机会主义编程」:在开发的每一步中,选择实现对用户有最大影响并需要最少努力的功能。