几个业务场景中的重构示例 请求顺序依赖前端
在这种场景中,首先仍是业务的复杂度决定了代码的复杂度。首先咱们来看一个在前端和node都有可能出现的一个简单的例子:node
咱们有 A, B, C, D 四个请求获取数据的函数(函数本身实现), C 依赖 B 的结果,D 依赖 ABC 的结果,最终输出 D 的结果。编程
错误示例 虽然这个代码是故意写成这样的,不过确实也有在一些初学者身上看到过。这份代码仍是能正确给出结果的,可是写法丑陋,回调地狱。若是后来人不进行重构,还有请求依赖,得继续回调嵌套。性能太差,没有考虑 A 和 B 其实是能够并发的。设计模式
这里介绍了一下最原始的 callback ... 中间你们能够去回顾一下 整个 ES2015+ ,callback (async.js) --> Promise --> generator + co --> async + await 的进化过程。实际上是从原生的语法层面不断去简化和加强咱们对于异步的控制能力。数据结构
下面直接给目前阶段原生提供的终极方案:基于 Promise + async/await架构
正确示例 咱们从新思考了一下上面的问题,理清楚了逻辑顺序的依赖。而且用最新的语法。并发
使用 Promise.all 结合 async/await 的形式,考虑了并发和串行,写法简洁,达到了在示例要求下的最快方案。解决了无限嵌套的问题。这是跟随语言进化自己带给咱们能够进行的优化。异步
但又不只仅如此。咱们将问题进行归类 将 B,C 有依赖顺序的请求,抽离出单独的函数。让他们去处理自身的逻辑。这个点咱们稍后再提。 折磨人的 if elseasync
可能存在下面一些问题 一、过多的嵌套 二、逻辑处理冗余 三、没有作好防护编程(错误处理函数式编程
直接来一个代码例子,这是一个获取背景颜色的方法,可是随着业务的不断变化,背景颜色的来源愈来愈多,在一些业务人员的处理下多是这样的:
错误示例 相信你在读上面的代码的时候是极为痛苦的,想要一目了然的知道最终会进入哪一个分支,基本不可能。因而基于下面两个原则
- 合理的抽取成函数
- 错误优先返回
有了一个基础版本的重构:
正确示例 能够看到整个逻辑,通过了从新梳理。拆分红了三个函数,子方法分别去处理对应层级的逻辑,由一个主方法负责调度。总体都变得一目了然了。
固然,在咱们基于上面的原则进行重构以后,这个代码有没有问题呢?固然有。能够看到咱们这三个函数,都依赖了全局变量。函数自己就不纯了。若是是全局的问题,仍是不易于排查。
咱们能够将其修改成纯函数,让这一份代码易于理解和测试。
以一个函数的修改成示例:咱们将 全局变量变成了参数,只须要在调用的时候,将全局变量传入便可,可是这样,咱们获得了一个纯函数。 为何会在这里特别强调这个点呢,其实在函数式编程中的一个最基础的问题那就是纯函数。只有这样输入输出才是可被观测的,一个输入必定会有一个输出。也只有经过这样的方式,才能让系统中非纯的函数愈来愈少。让代码变得更易于测试。
固然做为咱们若是以重构的角度去思考的话,咱们还须要关注到这个点: 这里的逻辑会将会 最后一个被匹配到的数据,设置为 bgColor 。(咱们都知道 find indexOf 等基本都是从前匹配。)是否真的是业务的需求呢?
能够看到将业务代码写好/重构的过程当中其实也是对业务逻辑和业务理解的再一次提高。
不管是抽取成函数仍是错误优先返回的设计,这其实也都是能够解决这样一个问题:能在不去读懂全局的状况下,了解某一个区域的细节逻辑,也就作到了让代码易于理解和修改。
... 这里的代码即使是通过这样的重构后,依然有能够考虑进一步优化的空间,好比函数与参数的命名,完整的测试用例等等,受限于文章篇幅,暂不展开说明。
一些代码中可能存在的其余问题
- 逻辑耦合在视图层。
- a === 'a' && b ==='b' && c==='c' && d ==='d'? <div>...</div>:null
- 组件复用,函数复用,不封装,代码重复。
- 函数功能不单一,一个函数处理太多职责。且这些职责没有任何关联,可是都耦合在同一个区块内。
- 参数列表混乱,有作好防护编程,不处理错误(接口错误,超时,重复提交等等
- 魔法数字,魔法字符串,且没说明。
- 糟糕数据结构 / 糟糕命名 (其实上面的具体代码示例也存在)
关于优化代码的思想准备
首先来讲一下为何会说须要优化代码?
- 技术追求。
- 公司要求,线上有系统在用。有用户在用,不写好出问题实际上苦的仍是本身。
- 团队协做,我很差好写,团队成员其余人也很差好写,恶性循环苦的仍是本身。
- 快速迭代。系统须要不断的增长新功能。必需要写好代码才能作到。
- 其余人的见解,怕别人以为本身技术能力差... xxxx....
那么就会有下面这些要求:
- 易于理解系统的架构
- 易于理解系统的生命周期与执行流程
- 易于理解每个函数的做用
- 易于理解函数之间是如何调用与传递的(输入输出)
- 易于理解变量的含义,表达式的含义。
- 易于扩展...
最终实际上又回到了写出来的代码应该是 整洁的代码,要使代码易于理解/修改/测试。(这里其实大部分时候,都隐含了一我的员协做的条件在里面,因此,既要写好代码,又不能过分封装,让团队其余成员看不懂(固然若是确实有些人经验不够,那么是他自身的问题,须要他本身去增强。))
一些建议
- 更加清晰的去了解业务,去思考可能的变化。思考和设计清楚再动手。
- 看一些开源项目与业界最佳实践,明白什么样的是好代码,什么样的是很差的代码。
- 创建明白代码虽然是给计算机运行的,但最终仍是人看的。不只仅是没有 bug 就好了,这样的心智模型。
- 创建业务与代码质量同等重要的思考模型。避免由于时间致使的不得不这么写的代码。
- 明白 code review 自己可能能发现和指出来一些问题,但最终的落实还的靠本身,不能变成形式,而是须要融合成自身的思考。
- 使用错误优先原则。尽量的让出错的先返回, 这样后面就会获得干净的代码。(写代码的时候,不只仅正向,反向的判断也须要思考)
- 合理的拆分红独立的函数。明确输入输出,错误处理等在函数内部的处理。(好比在一些场景中确实会存在大量逻辑判断,首先就要思考在判断内部的语句是否能被归类与拆分出去)
- 对于多种状态的判断与组合,可使用 组合状态表 (map表)状态机等模式
- 学习设计模式与重构等相关知识。
- 重构!!只要你以为这个地方有问题了,那就不要等到之后。之后每每就是不再。
结束
说到这可能会有一种戛然而止的感受。在这一篇文章里面,咱们首先以两个优化代码的具体实例为引子,让你们明白了一些业务代码的优化思路。在以后从列举了一些其余可能出现的错误,以及是优化代码的思想准备和理论指导。其实都是但愿你们可以在业务中去发现问题,再去思考如何解决问题,由于说了那么多,到底能不把代码写好,仍是得靠本身。
做者:三省吾身