前不久我推荐老板看《黑客与画家》这本书,他看完后觉得一个合格的程序员都应该读一读《黑客与画家》。我并不否认《黑客与画家》在我心目中的地位,毕竟这本书从头到尾我也读了 6 遍以上了。但是今天我想推荐《程序员修炼之道 - 通向务实的最高境界》,这本书在笔者心目中的地位并不亚于《黑客与画家》。原文连接: https://step-by-step.tech/posts/the-pragmatic-programmer
我甚至想把它作为回流技术团队的培训手册,不过在此之前,我们先来了解一下这本书。
《黑客与画家》其实是以杂文的形式,从较为宏观的角度去描述程序员(或者说黑客)这份职业。书呆子在信息时代有什么优势?黑客到底是更接近工程师还是更接近艺术家?在这本书都有所提及(关于《黑客与画家》可以参考3.times { p '黑客与画家' })。
而《程序员修炼之道》,则会具体到一些相对微观的层面,比如一个程序员在日常工作中要如何保持务实的心态,应该活用哪一类的工具,方法,什么才是真正的敏捷,开发者该如何把本职工作做得更好,拥抱工作中的变化。个人以为只要是程序员,在职业生涯不同阶段,每次重读定会有不一样的感悟与收获。
如果是给一个刚毕业正处于迷惘期的年轻人做职业指导,我会毫不犹豫地推荐他阅读《黑客与画家》,看完之后他可能会知道自己是否真的适合当一个程序员。而如果是培训团队中的开发人员,我会建议他们人手一本《程序员修炼之道》,这本书会帮助他们成为更好的开发者。
作者是有着超过 40 年开发经验的“老程序员”,假设 5 岁就开始写代码,现在都已经 45 岁了,彻底打破了程序员是青春饭这个魔咒。此书便犹如业内声望颇高的长者的谆谆教导,你会因在工作中贯彻书中的提示而受益匪浅。
简单来说,这是一本“务实”之书。里面有大概 53 个主题,以及 100 条提示,基本都是围绕“务实”二字展开。实用主义无论在哪个行业都有举足轻重的作用,邓小平同志不也说:“不管黑猫白猫,会捉老鼠就是好猫”。那这里就围绕“务实”来做一些简单的概括。
等到十月国庆一过,回流技术团队成立就该满两年了,感觉时间过得是真的快啊,不知不觉就两年了。这两年里面,需求像狂风暴雨般袭来,技术团队其实面临了不少的压力。公司许多内部人员都会觉得我们的开发力量不够强大,毕竟他们什么都想开发。
然而我却下意识地“维持小而稳定的团队”(提示 84),在外界的干扰下,我几乎每个月都怀疑这么克制是不是对的。直到最近重读《程序员修炼之道》,才想起来原来作者也有类似的想法。
团队应该保持稳定,小巧,团队的每个人都应相互信任,互相依赖。
50 个人就不算是团队,那是部落。
在某种程度上还是给了我一剂“强心剂”。得益于精益的团队,务实才成为可能。
因为我们人手有限(到今天为止也只有 7 个人),为了能够更好地保证产品质量,我们都是“尽早测试,经常测试,自动测试”(提示 90)。虽然目前自动化测试只在服务端实行,不过得益于它们的存在,产品的质量还算可以接受。尽量做到“每个 Bug 只找一次”(提示 94),测试人员花在回归上的时间少了,就能有更多精力去测其他关键的功能点。
这些年了解过一些失败的项目案例,发现许多项目失败的原因基本就这些因素 - 项目时间过长,办公室政治,需求变动频繁等等。其中项目时间过长,上线时间遥遥无期,严重打击了开发人员的士气,而导致项目失败的案例就比比皆是。因为开发人员能力不足导致项目失败的情况其实很少。
为了避免团队陷入这样的窘境,我们始终“在用户需要时交付”(提示 88),几乎每周都会发一个版本。差不多两年过去,团队基本是这个节奏,渐渐养成了快速响应的习惯,小步快走。
个人以为这也是一种期望管理策略,当你发版间隔很长的时候,势必会把那些在等待新版的人(可能是公司的高管,又或者是重度用户)期望值拉高,时间间隔越长往往期望值越高。结果就是期望越大失望越大。要能“取悦用户,而不要只是交付代码”(提示 96)。
我们每周都会有新版本,可能会有新功能,但是也可能只是修复几个 bug。甚至也有可能我们只修复了一个 bug,就发版本了,但是暗地里在做一些重构方面的工作。重构代码是高层不愿意给时间你去做的工作,但却很重要。实际上以明修栈道,暗渡陈仓的方式去做重构,大有好处。修一个 bug 也是修,其他时间就偷偷做重构,毕竟不影响发版节奏,高层一般也不会说什么,开发者也不用面临太大的压力。
我们老板想法太多,经常有新需求。
好巧,我们老板也是这样呢。今天说想要多开个直播间,明天可能说要上新的品类。需求多了自然就觉得开发力量不足,前面也提到了他们什么功能都想要。这是两难局面,大力扩招我觉得目前来看有点治标不治本,或许我们可以采用别的策略。
本书中提到一种叫作“曳光弹”的策略,“使用曳光弹找到目标”(提示 20)也是我们经常采用的方式。你可以把它简单理解为用代码构筑的原型。与一般的原型不同“曳光弹”是实际可以运行的程序,就是一个实验性的项目,可能一开始会很简陋,但是它的优势在于开发快,可以快速出一个试用品,用来验证某种需求的可行性。最后“曳光弹”中的代码可能会被抛弃掉,也可能渐渐转化成功能更加完善的产品。
我们经常用这种方法来验证需求的可行性,特别是上头来了一个大需求,而这个需求可能会消耗掉一个月以上的研发时间。书中也有提到“不要冲出前灯范围”(提示 42),当一个功能研发时间太长的时候,往往不确定性就高,失败的可能性也很大。所以要及早测试需求的可行性,不断接收反馈,毕竟“无人确切知道自己想要什么”(提示 75)。提前有个最小可用版本就能够在一定程度上降低这方面的风险,跟高层(用户)一同探讨需求可行性,渐渐地可能会得到一个更好的解决方案。“程序员帮助人们理解他们想要什么”(提示 76)。如果最终能够确认一个需求是伪需求,起码对公司来说是个好事情。
编码谁不会呢?
这又是个很有意思的话题了,编码对于程序员来说是基本功,基本上谁都会。不过有些地方只要稍加注意,可能编码这个事情便能上升到艺术的范畴。
首先我还是建议“尽早崩溃”(提示 38),这是最近跟新来的 Ruby 小伙伴讨论的事情,起因在于他在代码里面加了一段rescue StandardError => e
来捕获异常,这能够避免系统崩溃。不过在一些场景下,这种做法往往会让问题难以定位,你会误以为代码运行得很好,等到发现问题的时候可能已经为时已晚,直到用户投诉才能发现问题所在,与其这样把问题掩埋在深处,倒不如一开始就让系统崩溃,开发者能尽快着手修复问题。
在编写 Ruby 代码的过程中,我们还是坚持为编码写测试,“测试是代码的第一个用户”(提示 67),可以用测试来驱动代码的实现,帮助思考的同时也有利于回归。得益于测试用例,我们能够做到“尽早重构,经常重构”(提示 65),毕竟开发过程中总会发现之前一些之前设计/编码不当的地方,有测试在就可以大胆重构。这可以让系统保持正交性,“消除不相关事物之间的影响”(提示 17),也能适当给代码解耦,“解耦代码让改变更容易”(提示 44)。
把上面这些提示贯彻到日常的编码工作中,项目堆积技术债务的速度也会缓慢一些(技术债务无法避免),项目也更容易被接手。“不要放任破窗”(提示 5),其他同事也不会忍心去弄坏已有的代码。
要说《程序员修炼之道》这本书好在哪,那我觉得还是“常读常新”。笔者第一次阅读此书的时候,它还是电子工业出版社出版的第一版,当时还是大学生的我读完之后其实很多东西都无法感同深受。直到参加工作之后,慢慢把里面的原则应用进去才发现获益匪浅。最近又拿起来读一遍(之前读了几遍已经记不清了),才惊讶地发现回流项目之所以目前还算健康,还真少不了它潜移默化的影响呢。