迷思
首发于迷思

你要避免的软件开发模式

做软件开发十数年,见识了形形色色的开发者,和各种各样的奇葩软件开发模式。本文跟你侃侃这些软件开发模式及其特点。

IDD(IDE-Driven Development)

大巧在所不为,大智在所不虑。

-- 荀子 天论

IDD,也就是 IDE 驱动开发,几乎是初学者步入软件开发殿堂的必经之路。IDE 为开发者屏蔽了很多细节,并且几乎不用配置(相对于 vim / emacs / sublime)就可以使用代码自动补全,代码跳转,搜索,以及签入签出等软件开发中将会使用到的几乎所有工作。

然而,它带来的危害也是显而易见的,陷入 IDD 开发模式太深,开发者离开了 IDE 便像无头苍蝇一样,几乎不知道怎么读代码,甚至不太会写代码,不懂怎么编译,不会自动化完成常见的任务(比如 android 项目从编译到打包到 apk 分析),甚至连基本的 git 操作都无法完成。而这些被屏蔽的细节都是软件工程师的基本功,就像弹钢琴的基本指法一样,是必须修炼好的。试想一下,如果你只会在 IDE 里读代码,离了 IDE 的跳转就不知道怎么追溯代码的脉络,那么有的代码你只能通过 browser 阅读怎么办?不读了?如果你只会在 IDE 里写代码,有天你只能 ssh 到服务器上写代码(表笑,有很多公司这么做,也有很多场合需要这么做),你难道就不写了?

此外,IDD 开发者如果不能及时从对 IDE 的极度依赖中抽身而出,很容易转化成下一类开发者。

  • 适用人群:初学者
  • 舒适指数:五星
  • 危害指数:四星
  • 解决之道:学会任意一个 shell 下的编辑器

DDD(Debugger-Driven Development)

合格的程序员的代码是一行行写出来的;不合格的程序员的代码是一行行调出来的。

-- 某子 程序员的自我修养

DDD,面向调试器开发,是 IDD 依赖到一定程度的必然反应。这种开发模式的典型表现为:写出来的代码不知道对不对,从头到尾设置无数个断点,然后进入到调试模式,一个断点一个断点跟踪。发现一个问题,解决一个问题(也许引入一个新的问题),直到所有断点走数遍,所有遇到的问题被消灭,抹一抹头上的汗,心里骂上一句:妈的,这段代码老子(娘)终于调通了!

DDD 是非常浪费程序员生命的一种开发方式,它让我们把有限的时间精力都浪费在无穷地瞎忙活之中。因为断点过于唾手可得,程序员会变得懒于思考,懒于设计,甚至写完了代码都懒得自己看一眼 —— 大手一挥,无数个红色的断点就设置好了,反正出了问题我调就行了呗。

其实很多 concurrent 的问题,靠调试器是无法复现和解决的,更要命的是,DDD 还容易使程序员陷入 tunnel vision —— 我们太过于关注眼前的那一点点状态,而忽视了全局。

  • 适用人群:入门者
  • 舒适指数:四星
  • 危害指数:五星
  • 解决之道:多花时间思考和设计,使用 TDD(Test Driven Development),如果非要追踪状态,合理地使用日志(log)而非断点

PDD(Print-Driven Development)

王好战,请以战喻。填然鼓之,兵刃既接,弃甲曳兵而走。或百步而后止,或五十步而后止。以五十步笑百步,则何如?

-- 孟子 梁惠王上

看到 DDD,做嵌入式开发的 C 程序员笑了,我们没有那臭毛病 —— 大部分嵌入式开发的场景,要么设断点太麻烦(需要 remote debugger),要么无法设置(比如说很多内核态的代码),所以我们的代码都是写出来的。不过,这部分程序员大多自发聚集起来,立起一个山头:PDD,也就是面向打印开发。其开发逻辑有如下面的代码:

// ...some awesome logic...
printf("haha, hit 1");
// ...some more logic
printf("!!!!!! hit 2");

if (awesome_check(awesome_state)) {
    printf("####### condition captured")
}

PDD 和 DDD 相比,是旗鼓相当,半斤八两。PDD 开发者加入的代码,和 DDD 开发者设置的断点一样,头疼医头,脚疼医脚,哪里的状态不对了,或者和预想的流程不一致,先不考虑设计上是否有缺陷,为什么会出现这样的结果,而是不管三七二十一,加个打印(设个断点)看看状态是什么。如果没抓对位置,那么就继续细化,直到很被动地找到原因为止。

  • 适用人群:入门者
  • 舒适指数:三星
  • 危害指数:四星
  • 解决之道:多花时间思考和设计,合理地使用深思熟虑过的日志(log)而非用完即扔的打印信息

BDD(Bug-Driven Development)

以管窥天,以蠡测海,以莛撞钟,岂能通其条贯,考其文理,发其音声哉。

-- 东方朔 答客难

看到 BDD,也就是问题单驱动开发,相信大家都相视一笑。本来这里我想用 TDD(Ticket-Driven Development),更接近我的原意,为了不和 Test-Driven Development 混淆,故而只好改成 BDD。这可能是我们最熟悉的开发模式了 —— 在一个业务稳定的软件公司(甭管规模大小),勉力维护现有的代码,小心地添加新功能是多数程序员的主要职责。在这些公司里,与其说我们是工程师,不如说我们是补锅匠。看不懂代码?没关系,只要你会读日志(出错信息);解决不了问题?不打紧,能找到 workaround 把问题绕过去也可以,更有甚者,遇到神问题,看不懂,想不明,解不了,还没有 workaround,大笔一挥:not reproducible,就把问题关了,几个月半年后,说不定自己已经去补别的锅了。

BDD 开发者修的都是防御之道,一手华丽的 defensive coding skill,堪比仙女座的星云锁链,把系统的每寸肌肤防得滴水不漏。如果你看到一段代码,函数 A(a, b, c) 调了函数 B(c),即便参数 c 在 A 的入口进行了详细的检查,在 B 中也还会再度详细检查(哪怕 B 只有 A 调用),那么这代码一定是 BDD 开发者开发的。

BDD 开发者的视野往往很窄,所学所用皆局限于已有的系统,由于系统并非自己所写,阅读代码又是就着问题去追根溯源,所以对系统的理解会比较狭窄。这并非程序员能力不足,相反,能做 BDD 开发往往都是很有经验的程序员。然而,他们被公司的需求所局限,整日被 ticket 追逐,疲于奔命,在工作中无法有效提升,渐渐迷失在一个又一个犯罪现场,眼界变得越来越狭窄。

  • 适用人群:业务稳定的公司里的『高级程序员』
  • 舒适指数:二星
  • 危害指数:四星
  • 解决之道:自己主导一个项目的开发,或者,跳槽

RDD(Rat-race-game-Driven Development)

From day to day, we programmers dreamed of being an expert inside the team/company; however, when that day really comes we trapped ourselves.

-- 程序君 Programmer’s dilemma

These walls are kind of funny. First you hate ’em, then you get used to ’em. Enough time passes, gets so you depend on them. That’s institutionalized. They send you here for life, that’s exactly what they take. The part that counts, anyways.

-- Red, The Shawshank Redemption

RDD,老鼠赛跑驱动的开发,是指那些整个职业生涯都在原地打转的开发模式。Rat race game 是『富爸爸穷爸爸』中的经典例子 —— 老鼠在环形的笼子里拼命地奔跑。

每个程序员都在努力地成为他所在领域的专家。成为专家的代价是巨大的,我们需要付出经年累月的努力,才能爬到峰顶,带上「专家」的帽子。然而,成为「专家」往往意味着一条路走到黑 —— 一来之前的累计的惯性实在太大,掉头的机会成本太大;二来你的雇主因此而付你更高薪水,所以你只能在这个方向上不断前进。

我们知道,软件是个工程的活儿,并非科学。科学的路上走得越远,打出的装备越稀缺;而在同一家公司或者同一个行业里搞软件的,走得越远,就有越多的路是重复再走。你可能精于 chip verification,于是从第一份工作到第 n 份工作,干的都是 verification 的活,直到有天惊闻这个职位被砍;你可能是web 桌面化的好手,extjs 玩得风生水起,公司依赖你的技能开发产品,直到有一天,这个产品没人用了,你到市场上一看,你的 extjs 九段的功力,比不上玩 react 才刚刚两段的水平受欢迎。

RDD 就像 Red 口中所述的那些高墙。当你沉浸在 RDD 中不能自拔时,悄悄地,你曾经引以为豪赖以生存的能力成了你生存下去的最大障碍。

  • 适用人群:大公司里的『专家』
  • 舒适指数:五星
  • 危害指数:四星
  • 解决之道:在公司里换不同的团队,或者,跳槽去更有挑战的公司

以上写了这么多,总有一款符合你。你有没有找到自己心仪的开发模式?如果没有,恭喜你;如果找到了,别慌,有则改之,无则加勉即可。

编辑于 2016-04-13

文章被以下专栏收录