以上文字摘抄于《实现模式》的前言,距离本书翻译已经时隔 10 年了,但是这本书仍旧有着很大的价值。同时对于上述言论,我并不持否认意见。但是我认为,坏代码比好代码更加的费财(嗯,没打错,我确定)。…
一、如何写出好代码
1.1 好代码的用处
以上文字摘抄于《实现模式》的前言,距离本书翻译已经时隔 10 年了,但是这本书仍旧有着很大的价值。同时对于上述言论,我并不持否认意见。但是我认为,坏代码比好代码更加的费财(嗯,没打错,我确定)。对于相同的业务需求,坏代码需要投入的精力,时间更多,产出反而会更少。同时根据破窗理论( 此理论认为环境中的不良现象如果被放任存在,会诱使人们仿效,甚至变本加厉 ),坏代码会产生更坏的代码。这是一个恶性循环,如果不加以控制,完成需求的时间会慢慢失去控制。需要完成需求的人也会失落离开。
也就是说,好代码可以实现多赢,能够让用户爽,能够让老板爽,能够让开发者爽。总之,大家爽才是真的爽。
1.2 怎么写出好代码
少即使多
利用开源出来的设计与代码来减轻来自于业务线的时间压力。
对于软件开发而言,时间一定是最宝贵,最有价值的资源。相应的,尽量把时间耗费在解决新的问题,而不是对已经存在确切解决方案的问题老调重弹。所以,尽量不要自己写代码,而是借用别人的设计与实现。而在事实上,你也很难在极短的时间压力下设计并完成比开源更加合适的代码。
当然,开源作者一定是想让他的产品有更多的受众,所以从设计上而言,会采用较为通用的设计,如果你的需求较为特殊并且你觉得不能说服作者帮你”免费打工”(或者作者拒绝了),那么你也只需要在特定之处进行包装与改写,但是要比完全重写要简单太多了。
当然,调研新的技术方案并且使用到项目中是一种能力,但是千万不要因为一个小功能添加一个非常大的项目。
笔者在之前就遇到过其他小伙伴因为无法使用数字四舍五入。说 fixed 方法有问题而使用 math.js 的小伙伴。
1 | |
事实上如果没有很大的精度需求,前端完完全全利用一个函数便可以解决的问题,完全不需要复杂的math 这种高精度库。
1 | |
当然,也有小伙伴来找我询问大量数据的表格优化,我第一反应就是 React Infinite 或者 vue-infinite-scroll 此类解决方案。但是对方能够多提供一些信息包括上下文,采用的技术栈,当前数据量大小,未来可能需要达到的大小,当前表格是否需要修改等。得到了这些信息,结合业务来看,相比于增加一个库,是否如下方式更为便捷与快速。
1 | |
这就是一种代码抽象能力。让自己的代码可以适应更多的场景是程序员需要思考的。代码不是机器看的,是给人看的,更高的要求是: 代码不仅仅是给人看的,更是给人用的。需要考虑到协作的人与事,灵活的配置也是必须要考虑到的。就拿前端的 虚拟 dom 来说。能够适配更多的平台。
当然了,抽象能力需要时间,需要经验,需要学习大量的设计。
注意!:不要过早的抽象业务代码,甚至不要抽象业务代码。多写一点代码无所谓,千万别给自己找事做。 在业务上尽量保持简单和愚蠢。除非你是业务专家,确认当前业务不太会产生变化。
1 | |
从代码上来看,某个模块是否承担了它不应该做的事情,或者某个模块过于简单,徒增复杂度。
当然,事实上有些东西目前是做不到的让所有人都觉得满意,增一分则肥,减一分则瘦,刚刚好很难界定。就像 Dan Abramov 说的那样:
只做一件事
Unix 哲学,这个很好理解,就像我今年想做的事情太多,反而什么都没有做(或者说都做了,但都不好)。
代码上来看,不要因为一点点性能的原因,把几件事合在一起去做。例如在一次 for 循环中解决所有问题,或者将所有代码写在一个函数中,例如:
1 | |
// 完成之后的逻辑
}
改造后:
const axx = doA()
doB()
const cxx = doC()
1 | |
// 分离出3个函数
doA() {
const {a,b,c} = this.data
1 | |
相比于第一个只需要一次取数,一次setData,第二个性能无疑更低,但是可维护性变高了,3 件事情都被拆分出来,后面修改代码时候,我可以追加一个 doD 而不是再次把第一份代码中逻辑整理清楚再小心翼翼的修改代码。
命名与注释
命名与缓存失效是两大难题,今年讲了不少缓存问题,同时,命名的确是很困难的一件事情。通过一句话来解释你们在做什么事情,通过一句话来解释一件事的意图。
不说在程序世界中,在现实世界中也是如此。例如: 《震惊!xxx居然xxx》等新闻,虽然说看完后都会想要骂一句,但是,正如这样的名字才能吸引人家点击进入,让人情不自禁的被骗一次又一次。所以在项目没有发布前,要取一个简单而又好记的名字。
但在程序内部,我们不需要“骗取”人家的点击量,反而是要务实点,不要欺骗另外的同伴,比如说写了一个简单的名字,结果内部却封装了很多的业务代码。同时我认为这也是函数越写越短的理由,因为大家难以通过命名来解释那一大坨代码的意图。所以,需要编写可以自我解释的代码,而这种代码最佳实践就是好的命名。
对于开源代码,你往往会发现,这些文件开头都会有一系列注释,这个注释告诉我们了这个模块的意图与目的。让你无需看代码就可以进行开发。
对于业务开发而言,仅在你不能通过代码清晰解释其含义的地方,才写注释。在多个条件下都无法解释你的代码。
项目名
模块名
文件名(类名)
函数名(方法名)
这并不是让你不写注释。但是我觉得更多的注释应该放在数据结构而不是代码逻辑上。聪明的数据结构和笨拙的代码要比相反的搭配工作的更好。更多的时候,看数据结构我能了解业务是如何运行的,但是仅仅看到代码并不能实际想象出来。
实际上,随着时间的推移,代码做出了许多改动,但注释并没有随之修改,这是一个很大的问题。注释反而变得更有欺骗性。
这里也提供一篇 export default 有害 的文章。我觉得 export default 导出一个可以随意命名的模块就是一种欺骗性代码(随着时间的推移,该模块的意图会发生变化)。
考虑场景
没有放眼四海皆准的方案,所以我们必须要考虑到场景的问题,我们总是说可修改性,可读性是第一位的(往往可读,可修改的代码性能都不差)。但是如果是急切需求性能的场景下,有些事情是需要再考虑的。
if 是业务处理中最常用的,在每次使用前要考虑以下,哪个更适合作为主,哪个更适合放在前面进行判断。如果有两个维度上的参数,一个是角色,一个是事件。一定是会先判断角色参数,然后再去判断事件参数,反之则一定不好。因为前者更符合人的思维模式。在同一维度下,至于哪个放前面,一定是更多被使用的参数放在前面更好,因为更符合机器的执行过程。
就像在 if 中你究竟是使用 else 还是 return。大部分情况下处理业务逻辑互斥使用 else,处理错误使用return。因为这样的代码最符合人的思维逻辑。
但是在这里我也要举出来自《代码之美》的例子,在第五章中,作者 Elliotte Rusty Harold 设计了一个 xml 验证器,其中有一段在验证数字字符:
public static boolean isXMLDigit(char c) {
if (c >= 0x0030 && c <= 0x0039) return true;
if (c >= 0x0660 && c <= 0x0669) return true;
if (c >= 0x06F0 && c <= 0x06F9) return true;
// …
return false
}
这个优化之后如下:
1 | |
全局思考,善于交流
软件开发已经不是一个人打天下的时代了,你要不停的触达边界。在前后端分离的时代,前端可以不知道数据库如何优化,后端也可以不清楚浏览器的渲染机制,但是却不能不明白对方在做什么。否则等于鸡同鸭讲,也会浪费时间。在开发时候,把一段逻辑放在那一端取决安全的思考以及简化逻辑。
善于交流是一种能力,在与别人交流时给与足够的上下文,让你的 leader 沟通,让她知道你的难处。和小伙伴沟通,说服他人按照你的想法推进,同时,善于聆听才能不断进步。
算法
1 | |
1.3 辅助工具
TypeScript
虽然早就接触和实践过,但是以往都是 AnyScript。今年也算重度使用了。才体会到该工具的利好。一个好的开发工具并不是让你少写那一点点代码,而是让你在交付代码时候能够更加自信。
TypeScript 最大的好处就是让你在写代码前先思考,先做设计。就像之前说的。聪明的数据结构和笨拙的代码要比相反的搭配工作的更好。
TypeScript 同时也可以让大部分运行时错误变为编译时,并且可以减少使用中的防御性编程(信任但是仍要验证)。你不是一个人在写代码,协作优先。
在开发中,如果你接触过复杂性数据结构,并且还要在模块中不断进行数据转化,你就会不断的遇到:我的数据呢?到底在那一步丢失了?并且即使是代码对的,你仍旧害怕,仍旧怀疑。我已经过了那个“写 bug 是因为想的不够多,不够彻底”的年龄。
函数式思维
js 是有函数式的血统的,当年一直听说,函数是一等公民,只是当时完全不能理解。
纯函数,数据不可变以及代码即数据这三点是我认为是函数式思维对代码能力提升最大的三点。
这个我不想展开去聊,因为我没有熟练掌握过任何一门纯函数式语言。但是我的代码一定有函数式的影子,并且它的确让我的代码更优美。
其他
单元测试,代码审查,安全等等都没有讲到,这个我也需要足够的学习才能有所输出。不过这里列出一些资料供大家学习与了解:
谷歌代码审查指南
SaaS型初创企业安全101
1.4 有理有据就是好代码
工作在别人遗留的糟糕代码上是常有的事情,同时面对开发需求实际表,为了兼容,我们也不得不写出一些不那么好的代码。但是面对他人的疑问,我们需要给与别人这样做的理由,也就是你的每一行代码写下去一定有充分的理由和依据。
1.5 结语
明显不等于简单,上述都是很明显的事情,但是要做好都需要很长时间的学习与经验。
所以如何才能写好代码呢?那就是多看开源代码,多读书,多学习,多关注业界的动向与实践。不断学习,不断进化的代码才是好代码。
最近有一些小伙伴(无中生友)问我的名字为什么要叫 jump_jump。我是为了让自己以及看到我的小伙伴们牢记多锻炼,闲下来的时候多跳一跳。对身体有好处。
1.6 鼓励一下
如果你觉得这篇文章不错,希望可以给与我一些鼓励,在我的 github 博客下帮忙 star 一下。 博客地址
本文标题: 2020年我要这样写代码
发布时间: 2019年07月03日 00:00
最后更新: 2026年09月16日 05:40
原始链接: https://haoxiang.eu.org/7b8b9ce9/
版权声明: 本文著作权归作者所有,均采用CC BY-NC-SA 4.0许可协议,转载请注明出处!

