学而不思则罔,思而不学则殆。
过去的程序员忍者使用这些技巧来磨练代码维护人员的头脑。
代码审查大师在测试任务中寻找它们。
新手开发者有时比程序员忍者使用得更好。
仔细阅读它们,找出你是谁——忍者、新手,还是代码审查员?
许多人试图遵循忍者之路。很少有人成功。
简洁是智慧的灵魂
尽可能缩短代码。展示你的聪明才智。
让微妙的语言特性指导你。
例如,看看这个三元运算符 '?'
// taken from a well-known javascript library
i = i ? i < 0 ? Math.max(0, len + i) : i : 0;
酷,对吧?如果你这样写,一个遇到这行代码并试图理解i
的值的开发者会过得很开心。然后来找你,寻求答案。
告诉他们,越短越好。引导他们走上忍者的道路。
单字母变量
道藏于无言。只有道才开端良好,完成良好。
另一种缩短代码的方法是在所有地方使用单字母变量名。比如a
、b
或c
。
一个短变量会像真正的忍者消失在代码中,就像森林中的忍者一样。没有人能够使用编辑器的“搜索”功能找到它。即使有人找到了,他们也无法“破译”a
或b
名称的含义。
…但有一个例外。真正的忍者绝不会在"for"
循环中使用i
作为计数器。任何地方都可以,但这里不行。环顾四周,还有更多异域字母。例如,x
或y
。
如果循环体占用了 1-2 页(如果可以,可以更长),那么一个异域变量作为循环计数器会特别酷。然后,如果有人深入研究循环,他们将无法快速弄清楚名为x
的变量是循环计数器。
使用缩写
如果团队规则禁止使用单字母和模糊名称,请缩短它们,创建缩写。
像这样
list
→lst
。userAgent
→ua
。browser
→brsr
。- …等等
只有真正具有良好直觉的人才能理解这样的名称。尝试缩短所有内容。只有值得的人才能维护你的代码开发。
高瞻远瞩。抽象化。
大方形无角
大器晚成
大音希声
大象无形
在选择名称时,尝试使用最抽象的单词。比如obj
、data
、value
、item
、elem
等。
-
变量的理想名称是
data
。在任何可能的地方使用它。事实上,每个变量都保存数据,对吧?…但是如果
data
已经被使用了怎么办?尝试value
,它也是通用的。毕竟,变量最终会得到一个值。 -
按类型命名变量:
str
、num
...试一试。年轻的初学者可能会想——这样的名字对忍者来说真的有用吗?当然有用!
当然,变量名仍然表示某种含义。它说明了变量内部的内容:字符串、数字或其他内容。但是当外人尝试理解代码时,他们会惊讶地发现实际上没有任何信息!最终无法更改你经过深思熟虑的代码。
可以通过调试轻松找出值类型。但是变量的含义是什么?它存储哪个字符串/数字?
如果没有良好的冥想,根本无法弄清楚!
-
...但是如果不再有这样的名字呢?只需添加一个数字:
data1、item2、elem5
...
注意力测试
只有真正细心的程序员才能理解你的代码。但如何检查这一点?
其中一种方法——使用类似的变量名,例如date
和data
。
在可以的地方混合它们。
快速阅读这样的代码变得不可能。当出现错别字时...嗯...我们卡住了,是时候喝茶了。
聪明的同义词
可言说的道,不是永恒的道。可名之名,不是永恒的名。
为相同的事物使用类似的名称,让生活更有趣,向公众展示你的创造力。
例如,考虑函数前缀。如果函数在屏幕上显示消息,则以display...
开头,例如displayMessage
。然后,如果另一个函数在屏幕上显示其他内容,例如用户名,则以show...
开头(例如showName
)。
暗示此类函数之间存在细微差别,而实际上没有。
与团队中的忍者伙伴达成协议:如果 John 在他的代码中使用display...
“显示”函数,那么 Peter 就可以使用render..
,而 Ann 使用paint...
。注意代码变得更加有趣和多样。
...现在是帽子戏法!
对于具有重要差异的两个函数——使用相同的前缀!
例如,函数printPage(page)
将使用打印机。函数printText(text)
会将文本放在屏幕上。让不熟悉的读者仔细考虑类似命名的函数printMessage
:“它将消息放在哪里?是打印机还是屏幕上?”。为了使其真正闪耀,printMessage(message)
应该在新的窗口中输出它!
重用名称
整体一旦被分割,部分
需要名称。
名称已经足够多。
必须知道何时停止。
仅在绝对必要时添加新变量。
相反,重复使用现有名称。只需向其中写入新值即可。
尝试在函数中仅使用作为参数传递的变量。
这将使识别变量现在中确切内容变得非常困难。而且还不知道它来自哪里。目的是培养阅读代码的人员的直觉和记忆力。直觉较弱的人员必须逐行分析代码并跟踪每个代码分支中的更改。
该方法的高级变体是在循环或函数的中间用类似的东西秘密地 (!) 替换该值。
例如
function ninjaFunction(elem) {
// 20 lines of code working with elem
elem = clone(elem);
// 20 more lines, now working with the clone of the elem!
}
一位希望在函数的后半部分使用elem
的程序员会感到惊讶……只有在调试期间,在检查代码后,他们才会发现他们正在使用克隆!
在代码中经常看到。即使是对经验丰富的忍者,也是致命有效的。
下划线用于娱乐
在变量名前面加上下划线_
和__
。如_name
或__value
。如果您知道它们的含义,那就太好了。或者,更好的是,仅为了娱乐而添加它们,而没有任何特定含义。或者在不同的地方有不同的含义。
一石二鸟。首先,代码变得更长且更难读,其次,其他开发人员可能需要花费很长时间来弄清楚下划线是什么意思。
聪明的忍者在代码的一个位置放置下划线,而在其他位置避开它们。这使得代码更加脆弱,并增加了将来出错的可能性。
表达你的爱
让每个人都看到你的实体有多么宏伟!诸如superElement
、megaFrame
和niceItem
之类的名称肯定会启发读者。
确实,一方面,写着一些内容:super..
、mega..
、nice..
但另一方面 - 这没有带来任何细节。读者可能会决定寻找隐藏的含义,并冥想一两个小时的带薪工作时间。
重叠外部变量
在光线下,在黑暗中什么也看不见。
在黑暗中,在光线下可以看到一切。
在函数内部和外部使用变量的相同名称。很简单。无需努力发明新名称。
let user = authenticateUser();
function render() {
let user = anotherValue();
...
...many lines...
...
... // <-- a programmer wants to work with user here and...
...
}
一个跳进render
的程序员可能会没有注意到有一个局部user
遮蔽了外部user
。
然后他们会尝试使用user
,假设它是外部变量,是authenticateUser()
的结果……陷阱启动!你好,调试器……
到处都是副作用!
有一些函数看起来好像不会改变任何东西。比如isReady()
、checkPermission()
、findTags()
……它们被假定执行计算,查找并返回数据,而不会改变它们之外的任何东西。换句话说,没有“副作用”。
一个非常漂亮的技巧是除了主任务之外,还向它们添加一个“有用的”动作。
当你的同事看到一个名为is..
、check..
或find...
的函数改变了一些东西时,他们脸上茫然惊讶的表情——肯定会拓宽你的推理界限。
另一个惊喜的方法是返回一个非标准结果。
展示你的原创思维!让checkPermission
的调用返回的不是true/false
,而是包含检查结果的复杂对象。
那些尝试编写if (checkPermission(..))
的开发人员会想知道为什么它不起作用。告诉他们:“阅读文档!”并提供这篇文章。
强大的函数!
伟大的道无处不在,
向左向右。
不要被函数名称中写的内容限制住。要更宽泛。
例如,一个函数validateEmail(email)
可以(除了检查电子邮件是否正确)显示一条错误消息并要求重新输入电子邮件。
函数名称不应该明显看出有其他动作。真正的忍者编码员会让它们在代码中也不明显。
将几个动作合并到一个动作中可以保护你的代码不被重用。
想象一下,另一个开发人员只想检查电子邮件,而不想输出任何消息。你的函数validateEmail(email)
同时执行这两个操作,不适合他们。因此,他们不会通过询问任何有关它的问题来打破你的冥想。
总结
以上所有“建议”都来自真实代码……有时,由经验丰富的开发人员编写。甚至可能比你更有经验 ;)
- 遵循其中一些,你的代码将充满惊喜。
- 遵循其中许多,你的代码将真正属于你,没人会想更改它。
- 遵循所有,你的代码将成为寻求启迪的年轻开发者的宝贵课程。
评论
<code>
标记,对于多行 - 将其包装在<pre>
标记中,对于超过 10 行 - 使用沙盒 (plnkr、jsbin、codepen…)