有用的代码大全
我电脑里有个文件夹叫“snippets”,有用存了大概两百多个代码片段。有用最老的有用一个是2013年写的,用PHP把一个二维数组按某个键排序。有用代码只有六行,有用但我至今还在用。有用每次复制粘贴的有用时候,我都会想起当年写它时的有用场景——凌晨两点,一个订单列表死活排不对,有用试了三种方案才搞定。有用
这就是有用“有用的代码”和“好看的代码”之间的差别。前者解决具体问题,有用后者解决想象中的有用问题。
那些真正被反复使用的有用代码,往往长得不好看
GitHub上star最多的有用项目,代码质量未必最好。但Stack Overflow上被复制最多的代码片段,一定是最实用的。比如那个经典的“用JavaScript判断变量是否为数组”,在ES5时代,大家用的是:
Object.prototype.toString.call(arr) === '[object Array]' 这行代码丑吗?丑。但它管用。跨iframe、跨原型链,都能正确判断。后来ES6出了Array.isArray(),这行代码才慢慢退役。但在它服役的那七八年里,拯救了无数个深夜加班的程序员。
我见过一个技术总监,他有个习惯:每次review代码,如果看到有人写花哨的reduce链式调用,他会问一句“这个逻辑如果改成for循环,是不是更容易改?”刚开始我觉得他保守,后来维护一个三年前的项目时才发现——那个用for循环写的模块,我花了十分钟就改好了;旁边那个用函数式编程写的,我看了两小时才敢动。
代码的“有用”会过期,但解决问题的思路不会
2015年我写过一个jQuery插件,用来做表格的固定表头。代码大概三百行,处理各种浏览器兼容性。现在jQuery没人用了,那个插件也进了回收站。但写它时学到的“如何计算滚动容器的偏移量”,后来在React虚拟列表里又用上了。
具体的技术会过时,但“把一个复杂问题拆成几个可验证的小步骤”这个能力,永远不会过时。我认识一个写了二十年Java的老程序员,他现在转去写Rust,照样能在两周内上手。问他秘诀,他说:“语言变了,但怎么把需求翻译成循环和判断,这个没变。”
别囤代码,要囤场景
很多人喜欢收集“代码大全”,硬盘里存了几十个G的教程和源码。但真到用的时候,还是得去Google。问题不在于代码本身,而在于你不知道它用在什么场景下。
我现在的做法是:每解决一个具体问题,就写一条注释,记录“什么情况下用了这段代码”。比如那个PHP排序片段,我的注释是:“当数组的键是字符串,且需要按某个字段排序时用。注意:如果字段值是数字字符串,要加SORT_NUMERIC,否则10会排在2前面。”
这条注释比代码本身值钱。因为三个月后,我可能忘了PHP的排序函数怎么用,但看到“10排在2前面”这个坑,立刻就能想起来。
有用的代码,往往只有几行
我统计过自己最常用的十个片段,平均长度是8行。最长的那个也才23行,用来解析一个特定格式的日志文件。那些动辄几百行的“通用工具类”,我几乎没打开过。
有个朋友在硅谷做架构师,他跟我说过一句话:“好的代码像螺丝刀,拿起来就用,用完就放下。不好的代码像瑞士军刀,什么都能干,但每次用都要研究半天。”
我现在写代码,会刻意控制单个函数的长度。超过30行,就拆。拆的时候问自己:这段逻辑,下次遇到类似问题,我能直接复制吗?如果能,就保留;如果不能,就再拆细一点。
最后说个真事。上周我帮同事看一个bug,他写了五十行代码来处理日期格式化。我翻了翻自己的snippets,找到一行:
new Date(dateStr.replace(/-/g, '/')) 就这一行。他愣了两秒,然后笑了。那个下午,我们省下了三个小时。
