2020年 我要这样写代码
在 年初,一位朋友问我一个问题,如何才能够提升写代码的能力?
可惜的是: 当时仅仅回复了少量自己的想法,如多看开源代码,多读书,多学习,多关注业界的动向与实践,同时也列了少量准则。但是这些并没有所总结,又或者者说没有例子的语言始终是空泛的。所以在今年年底之际,对应着今年中遇到的形形色色的代码问题来逐个讲解一下。
好代码的用处
实际上本书建立在一个相当不可靠的前提之上:好的代码是有意义的。我见过太多丑陋的代码给他们的主人赚着大把钞票,所以在我看来,软件要获得商业成功或者者广泛使用,“好的代码质量”既不必要也不充分。即便如此,我依然相信,虽然代码质量不能保证美好的未来,他依然有其意义:有了质量良好的代码以后,业务需求能够被充满信心的开发和交付,软件客户能够及时调整方向以便应对机遇和竞争,开发团队能够再挑战和挫折面前保持高昂的斗志。总而言之,比起质量低劣,错误重重的代码,好的代码更有可能帮助客户获得业务上的成功。
以上文字摘抄于《实现模式》的前言,距离本书翻译已经时隔 10 年了,但是这本书依旧有着很大的价值。同时对于上述言论,我并不持否认意见。但是我认为,坏代码比好代码更加的费财(嗯,没打错,我确定)。对于相同的业务需求,坏代码需要投入的精力,时间更多,产出反而会更少。同时根据破窗理论( 此理论认为环境中的不良现象假如被放任存在,会诱使人们仿效,甚至变本加厉 ),坏代码会产生更坏的代码。这是一个恶性循环,假如不加以控制,完成需求的时间会慢慢失去控制。需要完成需求的人也会失落离开。
也就是说,好代码可以实现多赢,能够让客户爽,能够让老板爽,能够让开发者爽。总之,大家爽才是真的爽。
怎样写出好代码
少即便多
利用开源出来的设计与代码来减轻来自于业务线的时间压力。
The best way to write secure and reliable applications. Write nothing; deploy nowhere.
以上取自 github 上最火的项目之一 nocode。懒惰是程序员的美德之一。所以学习业务,了解业务,拒绝不必要的需求也是一个程序员的必修功课。介绍可以参考如何杜绝一句话需求? 这一篇 blog,当然,在大部分场景下,我们是不具有对需求说不的能力与权力的,但是无论如何,深度的了解业务,对用户有同理心是对程序员的更高要求。处理问题才是一个程序员需要做的事情。能够了解好题意才能处理问题。
对于软件开发而言,时间肯定是最宝贵,最有价值的资源。相应的,尽量把时间耗费在处理新的问题,而不是对已经存在确切处理方案的问题老调重弹。所以,尽量不要自己写代码,而是借用别人的设计与实现。而在事实上,你也很难在极短的时间压力下设计并完成比开源更加合适的代码。
当然,开源作者肯定是想让他的产品有更多的受众,所以从设计上而言,会采用较为通用的设计,假如你的需求较为特殊并且你觉得不能说服作者帮你“免费打工”(或者者作者拒绝了),那么你也只要要在特定之处进行包装与改写,但是要比完全重写要简单太多了。
当然,调研新的技术方案并且使用到项目中是一种能力,但是千万不要由于一个小功能增加一个非常大的项目。
笔者在之前就遇到过其余小伙伴由于无法使用数字四舍五入。说 fixed 方法有问题而使用 math.js 的小伙伴。
(11.545).toFixed(2)// "11.54"
假如想要理解 fixed 方法为何有问题的,可以参考 为什么(2.55).toFixed(1)等于2.5? 作者以 v8 源码来解释为何会有这样的问题,以及提供了部分修正 fixed 的方案。
事实上假如没有很大的精度需求,前台完完全全利用一个函数便可以处理的问题,完全不需要复杂的math 这种高精度库。
function round(number, precision) { return Math.round(+number + 'e' + precision) / Math.pow(10, precision);}
当然,也有小伙伴来找我讯问大量数据的表格优化,我第一反应就是 React Infinite 或者者 vue-infinite-scroll 此类处理方案。但是对方能够多提供少量信息包括上下文,采用的技术栈,当前数据量大小,未来可能需要达到的大小,当前表格能否需要修改等。得到了这些信息,结合业务来看,相比于添加一个库,能否如下方式更为便捷与快速
// 由于 vue 模型的起因,使用 Object.freeze 性能可以有很大增益this.xxx = Object.freeze(xxx);
随着堆积业务,代码的增长。管理复杂度的成本与日俱增,把依赖降低。 利用开源代码使得任务更容易实现。时间就是成本。关键是让收益可以最大化。
学习更多是为了做的更少。
统一
不同的人因为编码经验和编码偏好不同,项目中同一个功能的实现代码可能千差万别。但是假如不加以束缚,让每一个人都按照自己的偏好写自己的模块,恐怕就会变成灾难。
所以每次在学习少量新技术的时候,我总是想多看看作者的实例代码,作者是如何了解的,社区又是如何了解的。以求实现起来代码风格不至于偏离社区太多,这样的话可以提高沟通与协作的效率。相似于 《阿里巴巴Java开发手册》 或者者 vue 风格指南 这种取自大公司或者社区的经验之谈,要多读几遍。由于他们所遇到的问题和业务更加复杂。
对于公司内部开发来说,写一个组件时候,生命周期的代码放在文件上面还是放在最下面,如何把代码的一个功能点集中放置。通用型代码的修改。代码行数的限制。能够列出统一的方案,多利而少害。
化繁为简(笼统)
笼统是指从具体事物抽出、概括出它们共同的方面、本质属性与关系等,而将个别的、非本质的方面、属性与关系舍弃的思维过程。
假如你面对一个较大的系统,你会发现重构并不能处理根本问题,它仅仅只能减少少许的代码的复杂度以及代码行数,只有笼统才可以处理实质性问题。
无论是数据库设计,架构设计,业务设计,代码设计,凡是设计都离不开笼统。笼统能力强的所面临的困难会比能力弱的少很多。
或者者说笼统能力弱少量的小伙伴遇到少量问题甚至需要重新推翻而后再设计,这个是在时间和业务开发中是不能被接受的。
这里就谈谈代码,以下也举个例子,如 axios 库中有阻拦器与本身业务,在没有看到源码之前,我一直认为他是分 3 阶段解决:
- 请求阻拦
- 业务解决
- 响应阻拦
但假如你去看源码,你就会发现其实在作者看来,这 3 个阶段其实都是在解决一个 Promise 队列而已。
// 业务解决var chain = [dispatchRequest, undefined];var promise = Promise.resolve(config);this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { // 前置请求阻拦 chain.unshift(interceptor.fulfilled, interceptor.rejected); });this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { // 后置响应阻拦 chain.push(interceptor.fulfilled, interceptor.rejected); }); while (chain.length) { promise = promise.then(chain.shift(), chain.shift()); } return promise;
这并不是让你不写注释。但是我觉得更多的注释应该放在数据结构而不是代码逻辑上。聪明的数据结构和笨拙的代码要比相反的搭配工作的更好。更多的时候,看数据结构我能理解业务是如何运行的,但是仅仅看到代码并不能实际想象出来。
实际上,随着时间的推移,代码做出了许多改动,但注释并没有随之修改,这是一个很大的问题。注释反而变得更有欺骗性。
这里也提供一篇 的文章。我觉得 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}
这个优化之后如下:
public static boolean isXMLDigit(char c) { if (c < 0x0030) return false; if (c <= 0x0039) return true; if (c < 0x0660) return false; if (c <= 0x0669) return true; if (c < 0x06F0) return false; if (c <= 0x06F0) return true; // ... return false}
全局思考,善于交流
软件开发已经不是一个人打天下的时代了,你要不停的触达边界。在前后台分离的时代,前台可以不知道数据库如何优化,后台也可以不清楚浏览器的渲染机制,但是却不能不明白对方在做什么。否则等于鸡同鸭讲,也会白费时间。在开发时候,把一段逻辑放在那一端取决安全的思考以及简化逻辑。
善于交流是一种能力,在与别人交流时给与足够的上下文,让你的 leader 沟通,让她知道你的难处。和小伙伴沟通,说服他人按照你的想法推进,同时,善于凝听才能不断进步。
算法
我不是一个算法达人( leetcode 中等题目都吃力 ),但这个没什么可说的,你拿你的 O(n**3) 算法去对战人家 O(n * logn) 算法就是费财。所以,知道自己某方面不够好去努力就行了。
辅助工具
TypeScript
尽管早就接触和实践过,但是以往都是 AnyScript。今年也算重度使用了。才体会到该工具的利好。一个好的开发工具并不是让你少写那一点点代码,而是让你在交付代码时候能够更加自信。
TypeScript 最大的好处就是让你在写代码前先思考,先做设计。就像之前说的。聪明的数据结构和笨拙的代码要比相反的搭配工作的更好。
TypeScript 同时也可以让大部分运行时错误变为编译时,并且可以减少使用中的防御性编程(信任但是仍要验证)。你不是一个人在写代码,协作优先。
在开发中,假如你接触过复杂性数据结构,并且还要在模块中不断进行数据转化,你就会不断的遇到:我的数据呢?究竟在那一步丢失了?并且即便是代码对的,你依旧害怕,依旧怀疑。我已经过了那个“写 bug 是由于想的不够多,不够彻底”的年龄。大家在入门学习前台的过程当中有遇见任何关于学习,行业方面的问题,都可以加入我的前台技术学习裙是
282549184。缺乏相关的基础教程也可以直接来,整理了一套最新的前台基础教程,学习前台的这个过程当中我也收集了很多前台学习手册,面试题,开发工具,PDF文档书籍教程,可以直接分享给你们。
函数式思维
js 是有函数式的血统的,当年一直听说,函数是一等公民,只是当时完全不能了解。
纯函数,数据不可变以及代码即数据这三点是我认为是函数式思维对代码能力提升最大的三点。
这个我不想开展去聊,由于我没有熟练掌握过任何一门纯函数式语言。但是我的代码肯定有函数式的影子,并且它确实让我的代码更柔美。
其余
单元测试,代码审查,安全等等都没有讲到,这个我也需要足够的学习才能有所输出。不过这里列出少量资料供大家学习与理解:
有理有据就是好代码
工作在别人遗留的糟糕代码上是常有的事情,同时面对开发需求实际表,为了兼容,我们也不得不写出少量不那么好的代码。但是面对他人的疑问,我们需要给与别人这样做的理由,也就是你的每一行代码写下去肯定有充分的理由和依据。
结语
显著不等于简单,上述都是很显著的事情,但是要做好都需要很长时间的学习与经验。
所以如何才能写好代码呢?那就是多看开源代码,多读书,多学习,多关注业界的动向与实践。不断学习,不断进化的代码才是好代码。
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 2020年 我要这样写代码