什么样的代码才是好代码

651 阅读13分钟

什么样的代码才是好代码

写出好代码是每个程序员的目标与追求,不过如果要问什么样的代码才是好代码,可能每个人的回答都不一样, "好"这个词太过于主观了,缺少相应的标准,如果没有标准,那么就没法衡量,因此定义什么是好代码, 是一件非常重要的事情,只有先定义问题,才能针对性的提出方案,最终解决问题。

我们经常讨论代码的好坏时,一般都是站在技术的角度,而忽视了技术只是整个产品研发过程中的一环, 代码的好坏与否,不只是由技术人员来判定,与我们合作的各类同事,对我们都有一定的期待和要求, 技术要满足产品和业务的要求,发挥它应有的价值,而不是一个孤岛。

不同人眼中的好代码

现在让我们忘记自己的程序员身份,带入不同的角色,试着思考下他们眼中什么样的代码才是好代码。

...

经理、领导

好的代码应该能够快速支撑业务发展,当我们有一个好的创意时,程序员能够很快的将其实现落地, 不希望因为技术做不到,而被迫砍掉需求或者降低需求标准;好的代码还应该稳定,不能隔三差五就出问题,更不能存在 严重的安全漏洞,引起公司财产及名誉损失;产品使用体验好,用户满意度高...

作为领导,首先肯定关注的是价值,也就是好代码必须是高价值的,没有价值的代码,无论写的多么优雅, 带不来业务发展都没有意义,所以作为程序员,我们首要的就是关注我们代码产生的价值,这里就需要我们有一定 的产品思维,能够判断什么样的事情有价值的,进而提出自己的想法和解决思路,而不是一个代码机器,听从各类人的指挥, 每天忙于写一些没人用的代码。

除了高价值,经理一般关注交付时间,也就是要持续快速交付有价值的代码

持续产生价值.png

在项目初期,有时候不好的代码,反而能够快速完成需求,因为缺少一些代码设计,直奔目标而去,盲目堆砌业务代码, 很快就完成了任务。但是随着时间的增长,由于代码结构不合理、可读性差、深度耦合等原因,导致后期即使改动一行代码, 都会花费大量的时间去梳理逻辑,产出有价值代码的能力越来越弱,相信很多有经验的程序员都遇到过这种情况, 看代码一小时,没有改动几行代码,改了这个那个又出问题了,战战兢兢如履薄冰,代码可维护性极差。

产品经理

好的代码应该能很好的支持需求的变化,当来了新需求或者原有需求发生变更时,程序员能够快速应对这种变化, 而不是做不到(缺乏可扩展性)或者需要大量的时间(可维护性差),产品经理最不爱听到的一句话,我想莫过于"这个需求实现不了"这句了。

好的代码需要有良好的用户体验,比如网站的加载速度要快,功能操作要流畅(高性能),用户的交互要有相应的响应(鼠标移入的颜色变化、网络请求的loading), 出错了要有及时良好的反馈,最好提前有很好的指引等等。

要满足产品经理的要求,代码要有很好的可维护性,即可修改和可扩展,可修改的前提是代码可读性好,可修改的关键是代码解耦且没有重复; 可扩展需要对代码进行抽象,抽象是容易扩展的,细节是不容易扩展的。除此之外还要有产品思维,明白用户到底要什么,能深入理解、挖掘用户需求, 进而提出更好的解决方案,面向用户需求开发,而不是面向功能开发,如何才能拥有产品思维,如何优化产品用户体验后面单开章节分享。

测试、QA:

好的代码应该是健壮的,考虑了各种边界和异常情况,不能只在正常场景可用,一遇异常场景就崩溃, 代码崩不崩溃不能由用户的操作顺序决定,比如用户必须先点击A再点击B最后点击C,如果先点击C就崩溃,这是不行的。

好代码应该有好的兼容性,不能在升级新版本后导致含有老数据的页面不可用,也不能要求用户必须只用谷歌100以上, 更不应该要求用户清空一下浏览器缓存~~

好代码应该是经过自测的,当交付到外部时,bug含量不能太高,降低bug一个是严格的自测,另一个是采用自动化测试,如单元测试。 单元测试要求代码具有可测试性,可测试性的关键是代码应该是解耦的,有时候为了测试一个utils函数,既要模拟网络请求,又要模拟 共享数据vuex,还要模拟路由router,这样的代码是充分耦合的,导致准备测试环境的代码比代码本身还要长,不可测试的代码即耦合的代码。

研发:

对于研发来说,一般经常提及的好代码关键词都有这几方面:可读性要好、复用性要好、扩展性要好、高内聚低耦合、性能优、健壮等。 而具体怎么样做到可读性好,怎么增强复用,如何提升扩展性,什么是高内聚低耦合,如何实现,可能还缺少有效的方法论和实践技巧。

好代码的四大特点

综合上面不同人对好代码的认识,我们可以总结出来好代码的四大特点,即高价值、高可靠、高性能、易维护。

好代码的特性.png

高价值

高价值简单来说就是有用和好用。

有用代表能满足用户需求,帮助用户解决问题,代码的价值就在于是否能帮用户解决问题。要实现这一点需要有产品思维,明白什么是用户、需求、场景, 能够通过同理心来感知客户的需要。

好用及代表用户体验,在使用产品解决问题的过程中省时省心省力。

高可靠

高可靠的代码能经得住外部各种不同的环境考验,这里的外部环境可能是不同的系统、不同的浏览器或者不同的操作方法等, 不管用户怎么折腾,都能像一个不倒翁一样始终屹立不倒,高可靠的代码让人充满信心。

高可靠的代码不能依靠巧合编程。

有时候我们可能依靠巧合编程,特别是在面对复杂系统时,在没有搞明白完整逻辑时,恰好修改了某个属性或方法, 或者做了什么不太明确的改动,程序竟然按照我们的期望进行工作了,于是欣喜若狂,在经过简单测试后便匆匆上线, 甚至不敢进行充分的测试, 生怕再出现什么样的问题,这样的代码是脆弱的,就像一盆精心呵护的小花, 一旦拿出去面对外面的风吹雨打,便很快凋谢。

可靠的代码一定是算出来的,而不是凑出来的

假如让两个元素上下间距保持20像素,那么它们的css各个属性分别设置多少, 这个间距等于那几个属性相加,盒模型是什么,有没有考虑BFC的边距塌陷等,最终我们根据布局、盒模型和BFC等知识, 算出来一个数值,经过验证确实上下边距达到了20像素,也可能没有达到,那么分析哪块有问题,而不是通过一个像素一个像素的调整, 最终通过某种巧合,完成了20像素的设置。

质量是设计出来的,不是测试出来的

高可靠的代码一定是设计出来的,就像是手表内部复杂的机械结构,每个模块都有什么职责,对外提供什么功能,产生多大的转速, 都是经过严密的设计和计算的,好的设计才是代码高质量的第一关键因素。

每次写完一段代码,应该从头到尾来仔细过一遍,梳理一下每块的逻辑,每个函数调用的意义和结果是否是按照我们设计进行的, 结果正确不一定代表设计正确,巧合的正确结果是不可持续的。

高可靠的代码充分考虑了各种异常

我们常见的异常有哪些

网络请求:

  • 网络请求失败:不能忽视请求失败的处理
  • 接口返回数据格式不对:比如某个字段应该无数据时应该为空数组,但是后端返回null,不能信任后端的数据格式
  • 接口请求已发出但是由于页面要跳走,需求取消原来请求
  • 使用await等待请求但是没有使用try catch捕获错误

针对网络请求的异常,可以通过对网络请求进行封装,来实现一些统一的错误处理逻辑,如登录失效的跳转、错误提示Toast等

表单校验:

  • 用户未输入合法字符:清晰的提示+及时的校验反馈
  • 某些字段的联动

高可靠的代码是安全的

安全场景的几个情景

  • 网站内容由用户产生,也就是常说的UGC,此时要注意用户输入恶意内容,如文章或者评论中携带非法脚本
  • 文件上传避免上传非法的可执行文件
  • 文件获取功能避免用户指定超出可访问权限的目录
  • 文件上传目录设置为不可执行
  • 文件名加随机数或时间戳,让人不能猜到
  • 网站短信校验是否有安全限制,避免被人大量盗刷
  • 网站登录是否有错误次数,避免暴力破解
  • 在服务端执行用户脚本时,特别注意非法脚本以及死循环导致的服务器资源占用
  • cookie是否设置了http-only以及secure
  • cookie有效期是否过长
  • 每个接口是否都增加了权限校验
  • 返回敏感信息,手机号,密码等
  • 密码传输不加密
  • 配置信息、注释等泄露账号密码
  • 未使用https

高性能

  • 多:并发支持
  • 快:响应速度
  • 好:质量高、可靠稳定
  • 省:节省资源(网络、CPU、内存、硬盘)

易维护

结构清晰

好的代码首先要有一个清晰的结构,一个项目分几个模块,每个模块做什么,每个模块又包含什么子功能。 一个函数分几步执行,每一步做什么,都清清楚楚,结构清晰不仅涉及可读性,还涉及到解耦。

好的代码结构维护时,就像是通过一个hash表进行查找,能直接定位要要修改的内容在哪里,混乱的代码结构在维护时, 就像一个链表,每次都要从一个入口开始,一步一步的定位到目标代码,甚至都不如链表,可能是个树形结构,也可能是个网状图。

好的代码结构能清晰指引我们做一个事情分几步,就像在使用一些MVC类型的框架时,我们在面对一个功能时, 很自然的知道要创建model、view、controller三个文件,相当于给出了编程范式,让我们按照既定范式去编程。

在创建一个新的文件时,好的代码结构让我们不用思考就知道应该放到那里,而不好的结构则让人纠结, 不知道究竟应该放到哪里。

可读性好

为什么要把可读性好,算作易维护的一个子集呢,因为只有要维护的代码,可读性才有意义。 如果一段代码不再被维护,那么可读性的好坏就变的根本不重要了,只要机器能识别即可。 可读性好的本质还是为了易维护。

做好可读性的核心是我们要知道,代码是给人看的,或者说是给别人和未来的自己看的,而不是给机器看的,

复用性强

可复用的代码能够极大降低开发时间,提升开发效率,也能避免在后续面对需求更改时进行"散弹式"的更改, 很多bug都是因为没有进行复用而导致遗漏修改造成的。

而复用也带来了耦合,如何尽可能的利用复用的好处,而降低耦合带来的坏处,如何避免不合理的复用, 也是我们要思考的,不合理的复用会导致严重的灾难,所以面对复用时要保持清醒的头脑和谨慎的态度, 以及必要的方法。

低耦合

低耦合的代码是正交的,即两个或更多事物中的一个发生变化,不会影响其他事物,这些事物就是正交的。

低耦合的功能模块是独立的,具有单一指责的,高内聚的,改变一个模块的内部实现,不会影响其他模块。

有时候我们发现改了A模块,B模块不能用了,这就说明我们的设计存在耦合。

正交的系统能够提高生成效率和降低风险

  • 改动得以局部化,开发和测试时间都得以降低
  • 正交的系统能促进复用,因为模块没有复杂的依赖,可以在多个场景进行复用

降低风险

  • 正交的途径能减低任何开发中固有的风险
  • 有问题的代码被隔离开来,一个模块有问题,不会把病症扩散到其他系统,要把它切掉换成健康的新模块也更容易
  • 系统更加健壮,对系统做的更改,导致的问题都被局限在该区域
  • 正交的系统具有可测试性
  • 不会与特定的平台或者第三方绑定在一起,因为与第三方组件的交互接口都被隔离在全部开发的较小部分中

扩展容易

好的代码考虑了可预见的未来的需求变化,能够未雨绸缪的做出适当的设计,好的代码进行扩展时, 不会对原有结构造成的冲击。

前端同学欢迎添加vx好友交流:_hit757_

写出高质量前端代码系列文章:

什么样的代码才是好代码

写出高质量的前端代码之提升代码可读性

写出高质量的前端代码之消除代码中的重复

写出高质量的前端代码之降低耦合提升正交性