云服务器

程序员自我修炼(五) - 代码命名

2017-12-25 15:44:46 0

一个程序员的代码反映其能力,而一个程序员给代码命名的水准则反映其修为和内涵。 一段程序,如果抛开字符串,标点符号和留白,剩下些什么东西?剩下的就是命名。

可能大家还不知道命名的重要性到底有多大,我举一个具体的例子。比如说这段代码:

function formatter(params) {
  const result = joi.validate(params, formatterSchema, { allowUnknown: true });
  if (result.error) throw result.error;

  const value = result.value;
  value.tag = helper.app.getAppTag();
  value.flag = value.flag || new Flag();
  if (value.method === 'get' || value.method === 'head') {
  value.flag.set('etag', value.flag.has('etag') !== false);
  }
  value.description = mustache.render(value.description, helper.doc)
  registeredFormatters.push(value);
}

如果我们把字符串用 s 表示,标点不变,名字用 n 取代。 然后这段代码就会变成这个样子:

n n(n) {
  n n = n.n(n, n, { n: n });
  n (n.n) n n.n;
  n n = n.n;
  n.n = n.n.n();
  n.n = n.n || n n();
  n (n.n === 's' || n.n === 's') {
 n.n.n('s', n.n.n('s') !== n);
  }
  n.n = n.n(n.n, n.n);
  n.n(n);
}

如果通过看上面修改后的例子的话,可能大家会觉得连代码最基本的逻辑都看不明白了。由此可见,代码的命名何其重要!

那么,什么是好的命名呢?

  • 首先,避免使用繁琐的组合词。
一旦你发现你的代码编写过程中开始使用类似 getUserNotFinishedViewHistory 这样的组合词,代码一定是开始出现了问题。这时候,要么你需要重构上下文中的代码,要么你需要把这些堆砌的词藻挪到其他上下文中。(比如上面的例子,作为参数是个不错的思路。)
  • 其次,要学会表达你的意图,而非陈述事实。
比如:
if (getPermissionsByUser(user).contains(getPermissionObject('can view', board)) {
  // see user's permission contains 'can view' permission for the given board
  ...
}
这段代码啰啰嗦嗦陈述一大堆,意图其实是:
if (user.canView(board)) {
  ...
}
写程序的过程其实就是好比在和别人沟通的过程。这个别人,可能是你的同事,也可能是未来的自己。怎么样把一件事情说清楚其事很考量一个人的能力的。代码写的好的程序员一般都是生活中很好的沟通者,至少是很好的文字沟通者;但写的不好的程序员,沟通能力肯定很差。

我们经常看到,代码写的不够好的时候,往往会出现注释来解释代码的意图。这是因为我们使用了拗口的,让人难以理解的表达方式撰写代码,自己都觉得别扭,所以需要一段文字来补充。然而,写注释和写代码的人的思维是高度一致的,如果说我能够用注释表述清楚我想说的话,那么我就肯定会用代码反应我的思想。因此,好代码往往无需注释。

  • 最后,好的名字要有一定的抽象度,它不该只着眼现在,还能面向未来。
大部分代码不是为了存活一天,或者一个月而存在的,它们往往会在代码库里停留无穷无尽的时间,直到被重构,或者生命期结束。你不想需求稍微改变一下,连变量或者函数的名字都改变吧?在命名的时候适当地做些抽象,使用些修辞的手法,大有裨益。

那些弥久历新,朗朗上口的名字,大都有这个特点。比如 pipe,stream,flow,socket。不管什么语言,只要有人写下a.pipe(b),我们就立刻理解其意图,因为 pipe 将一类共通的任务抽象出来,并用生活中我们耳熟能详的东西比喻,所以其弥久历新。

 

上一篇: 无

微信关注

获取更多技术咨询