工作快满 1 年了。在刚从 CUHK 毕业的时候,我还满怀悲壮地表示在中文大学饱受摧残,各种 assignments projects 所写的代码已经超过了整个在武大的四年。而现在,wc -l 显示的数字已经可以让我十分蛋定,这一年的代码量已经超过了过去所有学生时代的总和。回过头来看一年前写的代码,真是惨不忍睹,恨不得把当时的自己拉出去暴打一顿。确实走了很多弯路,但我也因此收获颇丰。

感触之一就是怎样编写漂亮整洁的代码。我曾经说过,我是个完美主义者,写博客的时候我要检查以防出现错别字,写代码的时候我会特别注意变量命名是否规范,甚至代码缩进是否对齐。这大概已经属于强迫症的治疗范围了。在现实项目开发中,整洁漂亮 意味着用最少的代码,实现完整的业务功能,同时代码是易于理解的。然而随着时间流逝代码不断被修改,系统设计的整体结构则逐渐衰弱。编码从严谨的工程堕落为随性地胡乱砍劈。不重构,软件就会慢慢腐烂。这一切是如何发生的呢?

归根到底,还是源于软件开发人员惰性。懒惰是天生的,例如 sofish 举例过的一段代码——

if(condition_a) {
    var str = condition_a.trim().replace(/^{(\w+)}$/, function(match){
        // ...
    });
} elseif(condition_b) {
    var str = condition_b.trim().replace(/^{(\w+)}$/, function(match){
        // ...
    });
} elseif(condition_c) {
    var str = condition_a.trim().replace(/^{(\w+)}$/, function(match){
        // ...
    });
} else {
    var condition = defaultValue;
        str = condition.trim().replace(/^{(\w+)}$/, function(match){
        // ...
    });
}

如果又有新的 condition_d,懒人复制粘贴一下就搞定。你可以同样改成 switch,但本质上都是在写重复的代码。DRY 原则,即 Don’t Repeat Yourself,是编写高质量代码毫无疑问最重要的原则,重复是所有邪恶的来源。上面的代码可以稍作修改

function dry(condition) {
    condition = condition || defaultValue;
    condition.trim();
    return condition.replace(/^{(\w+)}$/, function(match){
        // …
    });
}
 
if(condition_a) {
    dry(condition_a);
} elseif(condition_b) {
    dry(condition_b);
} elseif(condition_c) {
    dry(condition_c);
} else {
    dry();
}

将重复的逻辑提取出来,抽象为一个独立的函数,看上去就干净漂亮很多。所以抽象是一个很重要的能力。说一个差劲的程序员懒惰,并不是指他不情愿编码,事实上,他正不遗余力的敲打键盘;懒惰体现在不愿意思考,不想碰架构优化现有的系统。

为什么需要架构?

架构是当事情变得复杂之后必须考虑的问题。如果你的桌上有 2 本书,那么你怎么摆放其实没关系,你随手翻翻也能很快找到你想要的段落。如果你有几百本书,那么你就需要一个书架了。如果是一个图书馆,那么就更需要一个合理的规划,将书本分门别类,编号,建立索引,方便查找。软件开发是一样的道理,你得知道系统将要到一个什么样的规模,提前做好各方面的约定。例如选用一套开发框架,指定团队的代码规范。

约定优于配置

这是 maven 最核心的设计理念,很多语言框架都将其思想发扬光大。遵循约定虽然损失了一定的灵活性,不能随意安排目录结构,不能随意进行函数命名,但是却能减少配置。更重要的是,遵循约定可以帮助开发人员遵守构建标准。

例如 Yii 的典型项目结构是:

projectName/
   index.php                 Web 应用入口脚本文件
   assets/                   包含公开的资源文件
   css/                      包含 CSS 文件
   images/                   包含图片文件
   themes/                   包含不同风格的主题
   protected/                受保护的应用文件,主要代码在这里面
      components/            包含可重用的用户组件,自定义类等等
         Controller.php      所有控制器类的基础类
         Identity.php        用来登录认证的 'Identity' 类
      config/                包含配置文件
         main.php            Web 应用配置
      controllers/           包含控制器的类文件,MVC 中的 C
         SiteController.php  默认控制器的类文件
      data/                  包含示例数据库
         schema.mysql.sql    示例 MySQL 数据库
      extensions/            包含第三方扩展
      messages/              包含翻译过的文本,适用于多国语言支持
      models/                包含模型的类文件,MVC 中的 M
         LoginForm.php       'login' 动作的表单模型
      tests/                 包含测试脚本
      views/                 包含控制器的视图和布局文件,MVC 中的 V
         layouts/            包含布局视图文件
            main.php         所有视图的默认布局
            column1.php      使用单列页面使用的布局
            column2.php      使用双列的页面使用的布局
         site/               包含 'site' 控制器的视图文件
            index.php        'index' 动作的视图
            login.php        'login' 动作的视图

又例如 Yii 中对于 action 通配符的规范,XyzController.php 中若有一个名为 actionEdit() 的方法,那么体现在网页 URL 上,就是是除去 action 前缀的动作函数名。即 http://www.mydomain.com/xyz/edit

更多的规范还包括变量、函数和类使用驼峰命名风格,即每个单词的首字母大写并连在一起,中间无空格。变量名和函数名第一个单词全部小写,而类的首字母需要大写,例如:$basePath, runFunction(), LinkPager。对 private 变量和函数来说,以下划线作为前缀,例如 $_actionList

当然还有数据库的规范——

  • 数据库表名和列名都使用小写命名。
  • 名字中的单词应使用下划线分割 (例如 product_order)。
  • 对于表名,你既可以使用单数也可以使用复数。但不要同时使用两者。为简单起见,推荐使用单数名字。

如果风格统一,那么代码将是有规可循的。我们可以根据命名了解结构,根据结构理解构建的代码原理。团队的合作将是无缝的,多人 debug 也将没有障碍。

我之前做的一个项目,就是因为缺乏遵循规范,而花费了大量时间和精力去做适配不一致的接口参数,各种变量名称的转换占了整个项目代码的很大部分。亲自动手写好一个站点并自己进行代码维护,理解其中的弊端,经历无数次的捶胸顿足痛定思痛,才知道最终如何改进才算架构“合理”。

关于重构

进度预估实际上是比较困难的一件事情。每当 Leader 问我这个模块要几天搞定时,我都支支吾吾。因为有时需要对旧代码进行改造,或者说重构,而这些工作对于功能上没有任何产出效益。在版本发布的重压下,快速迭代只是我个人的一个期望而已。

软件开发已经进化为软件设计。在设计当中应当注重简约的原则,少就是多。按照一定的设计模式来构建,总能达到事倍功半的效果。例如使用继承、多态等面向对象手段,还有广泛采用的工厂模式等等。又例如每个函数都简单到仅仅 3 到 4 行长,函数的缩进层级不多于三层,每个函数只做一件事,可复用,同时充分解耦。

好的代码需要打磨。一个优秀的程序员,总能保证每一次 commit 仓库里的代码比上一次更好。

关于技术布道

Fenng 曾经谈过关于 技术布道 的一些经验,其实就是“用影响影响影响”。那些大牛们孜孜不倦地对外传递大公司的动态、新的技术趋势以及他们自己对技术的思考感悟,用自己的影响力去影响一部分具备影响力的人,再促使这部分人自发的去影响更大的目标群体。一些人之所以更牛是因为他们专注于自己做的事情,认为它是重要的,满怀热情,所以他有动力去优化自己的工作。相比之下更多的人只不过是在应付。

我没有那些令人景仰的牛人的魅力,我所能做的,只是把自己所知道的总结出来,教给和自己合作的开发者,让他们也能在技术上有所提升,这样合作起来也会更轻松。我想这是件令人愉快的事情。

参考链接:
MVC架构导致的词汇表分裂
每一件意义重大的小事——读《代码整洁之道》