code-first vs product-first
8 min read

code-first vs product-first

作为程序员,如果你不关心怎么写好代码,那就没有什么要关心的了。就着好代码这个问题聊聊普通程序员最好的状态,也是一段时间以来自己对程序员这个职业的一些理解和思考。
code-first vs product-first
Photo by Alexander Andrews / Unsplash

引子

关于王垠的40行代码,他自己说:

当我死后,如果有人想要知道什么是我上半生最重要的“杰作”,也就是这 40 行代码了。它蕴含的美,超越我给任何公司写的成千上万行的代码。

问题来了,一个凝聚半生功力的40行代码是好代码?

  • 是好代码,CPS 的功能是明确的,但是他用美感、精简、巧妙、触类旁通的方式做到了,这是顶尖论文的独立思考和研究,当之无愧好代码。
  • 也不是好代码,尽管代码如此精巧但是对我没有什么实用价值,我甚至都不理解这段代码,也没有动力去了解。

评价王垠的40行代码是不是好代码,就类似评价代码片段一和代码片段二哪个好,站在不同的立场你会得到不同的答案。

# 代码片段一
def fib_iterate(n):
    """ 迭代实现的fib
    """
    if n <= 1:
        return 1

    a, b = 1, 1

    for i in xrange(2, n+1):
        a, b = b, a+b

    return b

# 代码片段二
def fib_recursive(n):
    """ 递归实现的fib数列
    """
    if n in (0, 1):
        return 1
    else:
        return fib_recursive(n-1) + fib_recursive(n-2)

有一位骨灰级程序员说过这么一句话:“作为程序员,如果你不关心怎么写好代码,那就没有什么要关心的了。”,这话咋一看是正确的,但是大师的高深之处就在话不全说————“写好代码”的客观标准是什么?这个标准不光影响到程序员产出代码的好坏,同时也会影响程序员自我状态甚至影响自己作为程序员的价值观。

受到文章《 Code-first vs. Product-first 》的启发,我打算就着上面的问题聊聊普通程序员最好的状态,算是之前写的两篇文章《avoid wishful thinking design》、《关于 X-Y 问题的思考》的一个拓展和总结,也是一段时间以来自己对程序员这个职业的一些理解。

另,这篇文章是我自己作为一个普通程序员的思考和理解,不一定对。每个人都有自己的观点和想法,虚心接受讨论来迭代我自己认知的版本,But I'm Benevolent Dictator for Life, BDFL。

好代码的标准

我非常认同文章《 Code-first vs. Product-first 》的观点:

I call this my rule of good code: If the product doesn’t work well, the code is not good.

精巧的代码、完备的测试、优雅的架构、高效的算法、先进的技术等等无一不是好东西(我们统一用高精尖来指代),它们不光是解决问题的利器也是自身能力的直接体现,这些都是一个技术人员不懈的追求。那么我们来推演一个问题:具备上述东西的代码就是好代码吗?

首先代码存在的价值和意义在于它能够高效地帮助人们解决问题,否则它就是一段符号记录无论它是否精巧漂亮。一段精巧漂亮甚至用上了全宇宙最高精尖技术的符号记录,如果这段符号对于他人而言没有任何帮助,那它的意义就渺小很多也就无法称作“好”,更何况大部分好代码的的语境都是工程学,那么好代码的判断依据应该是能否很好地解决问题而不是高精尖。解决问题大多是以交付产品的方式来完成,产品可以是硬件、软件、也可以是文档甚至可以是任何形式的记录,代码是构建、构成产品的方式之一,所以我们可以将产品的好坏与否作为判断代码好坏的标准。

再者我们来看看好产品与高精尖的关系,高精尖写出来的代码一定是好东西但这跟好产品没有必然关系,不是高精尖写出来的代码也可以是好产品,举个例子洛阳铲 v.s. 遥感卫星,都是解决考古问题,洛阳铲跟卫星相比肯定不算高精尖,但到科技发达的如今洛阳铲还是被当作考古工作者基本功之一,相信从考古工作者的角度来看洛阳铲肯定算得上是个好产品。我们再细致看看洛阳铲这个产品,以下是摘录自维基百科的介绍:

常见的洛阳铲呈半圆筒形,长20至40厘米,直径5至20厘米,装上富有韧性的木杆后,可打入地下十几米,通过对铲头带出的土壤结构、颜色和包含物的辨别,可以判断出土质以及地下有无古墓等情况。洛阳铲的制作工序有20多道,最关键的是成型时打造弧度,需要细心敲打,稍有不慎,打出的铲子就带不上土。这种铲子只有洛阳附近的五家探铲厂生产,而且至今只能手工制造。目前,洛阳铲已不再是考古界的专有工具,在建筑、公路、铁路、矿山等领域里都发挥了重要作用。特别是在地基灌桩和地质勘探等方面,洛阳铲已是必不可少的工具。洛阳的探工曾用洛阳铲为宜洛煤矿成功地打过百米的深孔。

根据上述的介绍不难看出,一把看似简单洛阳铲也有不简单的东西,制作工序、弧度打造等等都凝结无数的优秀的技艺,这算得上是洛阳铲产品的高精尖。通过洛阳铲这个例子我们可以简单的对好产品和高精尖的关系进行提炼:高精尖不一定能推导出好产品,但好产品一定有高精尖

所以,代码好坏的判断标准不是高精尖与否能判断,而是作为代码的代表(即产品)是否良好的帮助解决问题才是好代码评判的标准。

程序员的思维模型

我认为程序员追求高精尖是一种与生俱来的 code-first 思维惯性造成的————认为技术可以解决问题而有意无意间忽视技术之外的东西。对于这个问题可以尝试从思维模型的转换进行适当的纠偏,查理·芒格在《穷查理宝典》中提到的多元思维模型我觉得是一种很好的理性思考方式,它利用多模型联合形成的 Lollapalooza 效应来思考和决策,这其中需要注意的关键是使用这些思维模型不是为了证明某个机会而是为了证伪某个机会。普通程序员大多绕不开技术选型、技术决策、架构设计等等问题,为了避免 code-first 引发的不良影响,在思考和决策这些问题的时候可以从多个维度来思考问题,以产品或者方案能否更好的解决问题作为评价标准行程最终的方案或决策。

The best programmers I know are product-first, but actually have more coding knowledge than the coding-first programmers. They know when to use the chainsaw vs the hand saw vs the chisel. When you need to really get something right (usually the deeper in the stack you are) vs. when you can fake it and just move quickly. When it’s better to just write a normal for-loop rather than a custom iterator. These choices and tradeoffs are what becoming a great programmer is all about, and the ultimate feedback mechanism is how well the product works.

程序员其实一直在研发质量和研发速度之间做 tradeoff,不管不顾先上了再说很容易把自己的代码或者产品变成“缝合怪”,过度追求良好的设计或者高精尖之类的事情又会引发 over-engineering 的问题,所以建立自己的多元思维模型来思考和决策以应对这个问题是十分必要的。

程序员最好的状态

  • 普通程序员最好的状态是通盘无妙手,而不是一子定乾坤
  • If the product doesn’t work well, the code is not good
  • 高质量的代码 ⇏ 好的产品,好的产品 ⇒ 高质量的代码

References

  1. Code-first vs. Product-first
  2. 王垠的「40 行代码」真如他说的那么厉害吗? - 知乎
  3. Benevolent dictator for life - Wikipedia
  4. 洛阳铲 - 维基百科,自由的百科全书
足迹