[译文]一个有责任心的程序员

偶然看到了一篇叫做《A Responsible Programmer》的文章,深有感触,便译成中文与大家分享,Responsible本可以简单地译作“负责”,但“负责”在中文里还有另外一重意思,当动词用,它可以表示“承担责任”。不可否认的是,许多人会害怕这个动词的解释,它让人感到压力山大,似乎自己已经做错了什么事情。为了避免这种误解,我选择了一个绕口的翻译:《一个有责任心的程序员》。

正文如下:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
在过去的几年里,我“品尝”了一些走入屎路的Web项目。这些项目的质量很差,代码、环境、文档以及程序员的士气都很糟糕。我不知道就这类情形而言如何是好,我问自己:“有责任心的程序员会怎么做?”

清晰明了

对一个有责任心的程序员来说,最重要的就是“清晰明了”这四个字。不仅仅要把代码写的清晰明了,文档也要清晰明了,沟通也要清晰明了,当然,自己和项目的愿景也要清晰明了。

编码

编写始终一致的代码

有责任心的程序员的编码风格总是一致的。

一致性能帮助其他程序员阅读和理解她的代码,让他们能更容易地知道接下来的代码会是什么样子。如果她用全大写方式命名常量(如SCREAMING_SNAKE_CASE),他们就知道她会一直使用这种命名方式。再比如,为CSS和HTML中的Attribute命名时,她总是会采取用短横线间隔单词的方式(如dash-er-ized),或者干脆不带短横线。

这些东西很简单,但却很重要。

一致性会给人带来熟悉的感觉,而这种感觉的好处就在于它消除了担心并且增进了信心。

当有责任心的程序员为其他代码贡献代码时,她也会确保能遵循该项目的风格,与其保持一致。不过有时候想要弄明白一个项目的编码风格并是件容易的事儿,负责任的方式是去咨询对方更倾向于何种风格,然后采用之。仅仅发问是不够的,她还会去审阅代码,找到或确立一种风格,一直使用下去。

通过编写始终一致的代码,有责任心的程序员会让程序更容易理解,也更容易维护。

不做快速修复

有责任心的程序员不做快速修复。

当bug出现时,她不是去修复表面症状,而是去修复根源问题。如果一个Event Handler突然开始接收到未命名的事件,正确的修复方法不是去忽略这些未命名事件,而是找出为什么这些事件会在我们不想要的时候出现。她知道修复表面症状只会让根源肇因更加隐蔽。

编写短函数

短函数更容易理解、更容易推断,也更容易测试。写短函数就是负责的表现,老生常谈啦!

从查询分离出命令

命令查询分离(Command Query Separation, CQS)已经在领域驱动设计(Domain Driven Design,DDD)世界中饱受赞扬,其实Bertrand Meyer于1988年就在《Object-Oriented Software Construction》一书中提到了这种风格。好书,读吧!(译者注:中文版为《面向对象软件构造》,有清华大学出版社和机械工业出版社两种版本。)

有责任心的程序员会将她的命令从查询中分离出来,因为她知道这样不仅能简化测试,并且可以多次调用查询而不会引发任何不良反应。

将命令从查询中分离出来,其实也可以这么简单:

// 可以被随时调用,无副作用。

function generateRoute(params) {
return [params.major, params.minor, params.patch].join('/');
}

// 用新的route更新hash。
function updateRoute(params) {
location.hash = generateRoute(params);
}

无情地重构

有责任心的程序员重视“清晰明了”,所以她会在理解了系统变更的情况下无情地进行重构。她知道投入时间让代码更加清晰能够有效的预防bug和未来的各种挫折。

青睐显式代码

有责任心的程序员更加青睐显式的代码,而不是隐式的代码。

哪怕她理解注入元数据编程等高深的概念,她依然喜欢显式的代码多于漂亮的抽象。

对于新进的程序员和将来某一天的自己来说,显式的代码理解起来会轻松很多。

不怕高级技术

在某些情况下,高级技术能让代码变得更加简单,所以当她意识到这一点时,便绝不会回避高级技术。

说穿了,元数据编程以及其他高级函数式编程技术仅仅是在适当的时机应当去使用的工具而已。

检查边界

为了不让无效数据进入应用程序的核心,有责任心的程序员在维护系统时总是会检查系统的边界。

这样做可以避免在核心地带进行防御式编程(Defensive Programming),相比其他地方,核心地带更加需要清晰明了的代码。

包装外部服务

外部服务是开发过程之所以耗时的主要原因之一,有责任心的程序员会确保总是将外部服务包装为一个本地接口。这样做能简化对服务的测试和使用。

外部类库

有责任心的程序员永远不会使用她不信任的外部类库。除非有非常重要的原因,否则她绝不会将类库添加到她的代码库里。

当她需要添加外部类库时,她会去了解它。她会去学习如何配置它、如何调用它、使用它的最佳实践是什么、有些什么bug等等……

平衡

代码库可以比作平衡树。平衡树是一种当新条目加入时可以平衡自身的数据结构。修改平衡树会付出高昂的代价,但是好处是可以用最优的途径去访问访问树中的条目。

有责任心的程序员会将她的代码库当作平衡树一样对待。没有经过平衡性的考量,她绝不会添加代码进去。她知道一旦项目失去了平衡,再想要恢复,就只能整个推翻重写了。

随着代码的日渐成熟,代码的平衡性也会随之转变,当发生重大转变时,有责任心的程序员会进行无情地重构,使代码获得最好的平衡。

文档

有责任心的程序员会随着需求的变化来编写和维护文档。每个项目的需求都不一样,但大多数项目都能从系统概述、领域概述、风格规范以及代码注释等等文档中受益。

有责任心的程序员总是会在编码时进行假设,她会将这些假设以代码注释的形式写下来。她用tag来标记这些注释,在需要的时候就可以生成假设列表了。

系统概述

系统概述是囊括了系统中所有服务器的图表和描述信息,包括数据库、队列、Web服务器、外部服务等等。它描述了如何把这些部件整合起来。

领域概述

领域概述是关于系统的核心领域如何工作的图表和高层面的描述信息,包括该领域的主要概念及其含义。

风格规范

风格规范可以简单地参考 Github’s style guide,也可以在其他规范的基础上编写自己的规范。无论选择怎么做,它都值得你写下来。

代码注释

注释以稀为贵,并且应该只用来指出代码的特殊性。

假设也能用注释来表示,可以在假设注释里包含一个标签,以便生成假设列表。例如:

// ASSUMPTION: The list is expected to be small and will
// be entirely loaded from the server
function loadCities() {
}

测试

有责任心的程序员总是在测试!

她并不是为了测试而测试,也不是为了“提高代码覆盖率”而测试,她测试是为了确保代码能如她期望般运行。

她知道诸如JavaScript和Web浏览器这样的动态环境是十分脆弱的,一不小心就会让代码变得毫无意义。

关于如何编写好的测试用例,已经有人写过了,不再赘言。如果你对在动态编程语言中进行测试的优秀技术感兴趣的话,我推荐Sandi Metz的《Practical Object-Oriented Design in Ruby》的最后一章。

环境

有责任心的程序员拥有自己的环境。

在一个项目里,至少需要关心三个环境:生产环境、测试环境以及开发环境。开发机器本身也很重要。

有责任心的程序员可以用一条命令来安装项目环境所需的所有东西,包括数据库、种子数据、代码库、搜索引擎、工具、环境变量、SSH-keys。所有东西!

所以当新程序员进入项目时,她只需要几分钟就能搭建好环境。

这样做的好处还在于她她可以随心所欲地试验,而不用担心会不会毁掉开发环境、会不会需要很长时间去调试环境等等鸡毛蒜皮的问题。

她的个人开发机器也总被完美地配置。当学到了新技巧时,她会立即用到工具集和配置里。

她会为突发状况做好准备(自动的!)。假如硬盘挂掉了,她只需买一块新的,然后安装配置文件,几小时内就能搞定一切。

想要做到这一点,就需要经常备份配置文件。她会将无需保密的内容保存到Github上,将机密的内容(譬如SSH账号信息)保存到其他位置。

持续集成和部署

谈到环境,不能不提持续集成。如果某个项目没有应用持续集成的话,那么这个项目就是不健康的。

持续集成服务器就像其他服务器一样,仅仅是台可以用一行命令就能安装设置完毕的服务器而已。

有责任心的程序员会配置和维护好持续集成,就像她维护其他环境一样。

脚本

为了能够使环境持续集成,有责任心的程序员会去学习如何编写脚本。

脚本并不仅仅能用来保证环境总是最新,还能自动化简单的任务,在生成代码、测试、重构、重命名、安装和自动生成列表等等方面都十分有用。

有责任心的程序员会宣称:“我从来就没干过重复的体力劳动!”

编写脚本可以完成她想要的任务,而不用非得记住完成这些任务所需的指令序列,从而让她能专注于更加重要的事情。而且脚本还能当作可运行的文档。

工具

有责任心的程序员熟悉她的工具。她总会试着更深入地了解它们,也会用更好的工具来替换它们。

但她不会因为时髦而更改工具。

命令行就是一个非常强大的工具,脚本语言和脚本编辑器也是。

版本控制

有责任心的程序员使用版本控制来和其他程序员(以及未来的自己)沟通。她知道清晰明了的提交信息能帮助她和其他人理解系统中发生的一切。

她会“修剪”她的提交。当她对代码库做了一些更改之后,她会确保她会使用诸如git add –patch这样的东西来单独提交这部分更改。她还知道如果她错误地提交了一些东西,她会更改提交信息或者通过git commit –amend来添加漏掉的文件。她还会使用git rebase –interactive或git reset来更改提交历史的内容。

项目

做主

有责任心的程序员对她的项目做主,她绝不会允许代码里出现“坏味道”。

有时候她进入了一些已经走向屎路的项目,她会发现这个目标很难达成,但不管怎么说,这个目标是值得认真对待和付出的。所有项目都至少需要有一个人对代码做主负责。当人们开始像局外人一样讨论代码时,这个项目就真该去死了。

如果有责任心的程序员决定为项目做主负责,她会确保在她有权在她认为必要时做出决定。没有权力,就没有责任,就这么简单。

预估

有时候项目需要预估,虽然大多数时候不需要,但是有时候就是需要这么做。

有责任心的程序员知道该如何预估。

她知道预估仅仅是一个猜测,一个包含了所有任务(无论这些任务有多么琐碎)的猜测。她知道总会有一些小概率事件(地震啊、陨石撞击啊、断电啊),一旦发生,就有可能需要无比漫长的时间才能搞定。

当然,还有种小概率事件,那就是项目居然在预估的时间内完成了!

因为知道项目可能需要无比漫长的时间才能完成,她就会非常小心,不轻易许诺,她很清楚她的预估仅仅是猜测。

别按他们说的做

有些人不认为这是有责任心的程序员的标志,但我却不这么想。

当有责任心的程序员被告知去做某事,她会试着找出真正的问题所在。她会用几种不同的方式来做。她会坐下来细细思量这个“任务”,找出更简单的方法或者更好的方法来解决问题,让问题彻底消失。她会发问,让问题对她来说更加清晰明了。为什么这是个问题?为什么你要这样做?为什么?为神马?歪虾米?

有些人可能不喜欢这样,于是会告诉她“就他妈这样做!”。她也会如法炮制的回复:“就他妈这样做,你他妈自己来!”。不过通常她会更有礼貌一些,她会很委婉地说:“我不理解你的问题,所以,我不是解决它的最好人选,请找其他人代替吧。”

她相信她的工作就是去理解做什么以及为什么做,生命苦短,不混日子!

如果她感到她确实无法在某个项目里做一个有责任心的程序员,那么负责任的做法就是离开。

总结

回到开头的那个问题,“有责任心的程序员会怎么做?”,我想我已经找到了答案。

在一天将要结束的时候,有责任心的程序员会浏览一遍提交日志,她看到了她完成的任务列表,如此美妙。她看到每次提交都伴有很好的描述信息。她可以git blame代码,看到每一行署有自己名字的代码都非常易读。她回顾她的工作,感到无限自豪。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

发表评论

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