随着业务的迭代,不经意间写下的那几行代码,在后续的修修补补中,已经堆积成为屎山了。如果是自己一手造成了,还能游刃有余,修个 Bug 不至于引起雪崩。凡事都怕有个万一,是的,万一你接手了这么一个项目,而且这个万一的概率特别大,在换工作时,换业务方向时,业务有调整接手别人代码时,基本上能中奖。每一次改代码,都是嘴里念念有词,手上停滞不前。每一次上线都是胆战心惊,打开回滚页面,准备随时回滚以减少影响。一次又一次想推翻重来,然而没有人给予你勇气,直到有一天你能面对现实。。
对于技术人员来说,凡事能有一个通用的模型或者流程来分析,其实离解决问题就不远了。这要求我们需要具备分析问题,然后定义问题的能力。不知道是否有类似的经历,但别人反馈一个问题时,调试代码半天确没有复现,再对齐一下,结果是自己理解的问题和别人想要表达的不一样,这种情况很容易发生开发和测试之间,测试从行为角度去描述问题,开发从代码角度去尝试理解和复现问题,两种思维的差异就很容易造成问题。
治理屎山代码,首先值得庆幸的我们发现了代码是一个问题,但具体是一个什么问题,就涉及到分析这个问题了,这是需要重点思考的地方,也是体现一个开发人员核心竞争力的点。分析问题一般需要从现状分析出发,看代码一般只会看到细节问题,分析现状就是自下而上的发现整个项目的问题,例如产品流程是否有问题,状态管理是否可以优化,组件分层是否不符合预期等。那我们有如何来分析一个项目的现状呢?
可以从以下几点来分析,重点是描述现状,而不是预期优化:
梳理所负责业务方向的场景、功能模块,对业务有一个概述。可以通过脑图划分场景,一般而言一个页面就是一个场景,例如列表页面、编辑页面都是一个业务场景,当然涉及到一个页面 tab/step 这种,可以是多个场景。每一个场景会对应一个或者多个业务模块,一般就是组件纬度,例如列表页面这个场景中包含列表模块,筛选模块等。这一部分主要是对产品的流程的一个梳理,技术实现都是围绕产品功能展开的,有一个全貌,可以帮助更好的理解后续的技术上做的事情。关于场景、模块的论述可参考基于场景的产品模块设计与规划
对梳理的场景进行分析,首先是分析场景的主流程,从前端视角说明核心的交互链路,这部分可以使用时序图和流程图来进行描述。时序图是用于描述用户、前端系统、后端系统之间的行为和响应。流程图用户描述用户的交互,例如列表页面的筛选时,输入筛选项 -> 点击搜索 -> 展示筛选结果或输入筛选项 -> 展示筛选结果,这部分是补充模块的交互细节,并和前后端系统进行映射。
接下来是对场景下面的功能模块&依赖分析,这部分主要是从前端的代码组织角度分析,可以使用dependency-cruiser对需要分析的页面进行输出一个依赖图,根据依赖图进行组件的分层描述,并对依赖的外包资源也进行归类,例如公司内部的,公司外部的等。
基于功能模块的分析,梳理数据状态,包含数据的流向分析和数据结构分析,前者帮助分析状态管理是否合理,后者帮助分析数据设计是否合理,例如一个比较典型的例子我们存储了列表数据,其 length 不应该单独存储,可以使用一个计算属性,Vue 中对应 computed 属性, React 可以使用 useMemo 缓存变量。
最后一个是异常的处理,对核心流程链路上,JS 异常或者接口异常等是否有异常处理,如何处理的,帮助分析是否对用户友好。
通过上述 5 个步骤,基本可以涵盖前端的项目设计和实现,可以帮助分析质量、性能、效率方面的问题。当然主要还是解决一个开发效率问题,架构的主要目的之一就是复用,复用主要也是提升开发效率。
最后提醒一句勿忘记分析项目的初衷,是为了更好的定义问题,通过分析项目发现前端架构的问题(状态管理、代码规范)、实现的问题(依赖使用、代码分层)等。例如屎山代码最恶心的一点就是 all in one 模式,文件动辄几千行,这种对人的耐心是一个极大的挑战,通过分析项目就可以发现没有按照功能模块合理划分代码,一个文件包含 xx 个功能,导致文件极大。