概念完整性之项目中的代码风格

By | 07/14/2014
这篇文章写的

我当程序员有一段时间了。

我热爱编程,但我时常感到沮丧。

身为一个“完美主义者”,我将编程视为创造,我总是希望站在软件构建基础上审视我的代码。我认为自己在构建完美的软件大厦,这幢大厦从上到下,由内而外,散发着美。人们驻足于外而惊叹不止。而步入其中,更是觉得赏心悦目,如鱼得水,感觉一切都是那么熟悉。
这是我希望构建的软件工程。

但是生活总是不尽如人意。

在参与几个项目的过程中,我发现了两个常见的现象:
1. 在不清楚现有代码逻辑的情况下,就着急写代码。
2. 甚至于更严重的问题是,在不清楚现有代码风格的情况下,就着急添加代码。

一个真实的例子是,为了让全国人民喜迎世界杯,我们需要添加一个世界杯赛程的管理页面。我们决定在一个现有的基于DJANGO的管理项目上实现该需求。这个任务交给了B君。我对B君解释了这个项目的结构(层次)以及可能的着手点,典型的是现有代码封装了一个DAO层。或许由于该项目的DAO层抽象的不够好(好吧,这是我实现的),他又另外接入(实现)了一套DAO层。这样,看起来就像是两个独立的项目(尽管DJANGO有APP的概念,但从项目结构上我还是这么认为),只是因为这两个都是使用DJANGO才把它们集成在一起。这感觉极其别扭。

bugs-fixed

“极其别扭”并不能否认一段代码的价值,但最近有新的情况发生。我们将数据库部署为集群架构后,DAO层的数据库连接方式需要由单点改为集群。我发现我需要去修改一段完全陌生并且与项目结构格格不入的代码。我要重新学习这份我已经很熟悉的代码! 我感觉我像一个勇士,在未知的道路上,披荆斩棘!

我无意谴责,但请容我一一道来:
1. 我知道你的时间很紧急,今天的需求,明天甚至下午就要看到效果。但我听到的最多的一句话就是“这个功能我只需要加一行代码就能实现”,尽管我用“你知道这行代码需要用多少时间去维护/重构吗”也不能阻止你继续“高效”地完成需求。
2. 我知道你急于展示自己对业务的理解有多深,自己的编码能力有多强。你迫不及待地提交了一个补丁,你知道我在review代码的时候内心有多少只“草泥马”奔腾而过吗?我几度试图用一个理由来说服这么做的人:学习成本(我失败过,但也成功了几次)。任何不愿意熟悉现有代码风格而自成一套的人,都会给这份代码加上一种代码风格。就像美国人来到中国不习惯汽车方向盘在左边而自己在右边装了个方向盘一样。无限制的添加代码风格会让这份项目杂乱无章,增加后来者对这个项目的学习成本。 借用我们总监的话说,在没有对现有代码十分把握之前,新增的代码都是不可信任的。

长此以往,会出现一种情况: 有很多人知道这个项目的某个功能,但却没有一个人能够完整详细地向新人介绍这个项目。任何试图重构代码的人都会发现自己“有心杀贼,无力回天”。满屏“臣妾做不到”的画面感啊。

为何相比起代码逻辑,我更看重代码风格呢?代码逻辑或者反映了业务逻辑,或者反映了抽象处理,这些都可以由某个个人完成。而代码风格能够很好地反映这个项目团队的状态。一个项目如果出现不同的变量/常量命名方式,这对项目而言可不是赞美之词。严格地代码审查能很大程度上避免代码风格出现“百家争鸣”。
(TODO: 附上python的代码风格)

这些问题出现的主要原因在于:不愿意花时间读代码。自顾自地往现有项目上添加代码实现功能,可能能够加速需求的完成,这通常被许多人冠以“敏捷开发”。这是不负责任的,敏捷开发并没有放任代码满目疮痍。此时种下的代码就像病毒一样,在你试图重构代码的那一天,它们蜂拥而至,杀得你片甲不留。

概念完整性,这是《人月神话》中我最希望达到的目标。也是该书的主旨。很多程序,一眼就能看出来这是某个人写的,这并不可怕,可怕的是,很多时候,程序一看就是经了好几个人之手。两个函数实现了同样/类似的功能;都是变量但一个变量是所有都大写字母而另一个都是小写字母;这个变量在每个文件中都被定义了;甚至于三元操作符是否用空格风格和函数的开括号是否换行……我觉得一个好项目的基本要素是:其中的每个项目成员都可以说,是的,这是我们的风格,我能轻易地看懂代码。

当然,对于这两个问题,是完全有可能避免的,并且成本并不高。那就是,与原作者交流,不厌其烦地与他讨论。为什么会在这里使用常量?为什么这个逻辑分支要如此划分?为什么这个函数要放在这个模块内?为什么要用类型名而不是数据表名来区分不同数据类型?不断地沟通有利于达到思想的共识,这对于项目管理和团队管理是绝对的百利而无一害的。

虽然不能自诩为“老手”,但还是希望“新”程序员们(初次接触该项目或者该需求的人)能够做到几点,
1. 翻翻《代码大全》,里面的内容都已经是老生常谈了。《代码大全》不是一本快速提高编程能力的书籍,但绝对是专家级程序员修炼的内功心法。
2. 花点时间阅读身边那些你认为“程序写的比我烂”的同事的代码,他会在代码里写明他所栽过的跟头。(当然,他也可能挖了一个坑等你跳下去)
3. 思考如何将需求与现有项目完美融合,让你的代码成为原有项目的一个部分,而不是“像一把尖刀,插进别人的心脏。”,如果真的格格不入,那就新增一个项目吧。

最终,我还是重构完了数据库连接的代码,并不费力。感谢上帝。但这只是我所接触的最简单的一种情形,有更多复杂的情形发生在你需要对可能重复的逻辑进行重构时,到那时,祝你好运。而我,只希望世界杯赶紧结束,才可能放弃维护这份代码。


PS:我最近在收集各种好坏的代码风格,欢迎留下你的吐槽。

发表评论

电子邮件地址不会被公开。 必填项已用*标注