问题分析
公司的代码比较难维护,因为组件里的代码特别多,混杂了各种逻辑,管理store数据的,请求接口的,负责ui交互的。各种逻辑似乎都可以堆到这里,就像androrid里可以一个Activity
搞定一切一样。但是很显然,这样的代码的维护性非常非常低,问题出在哪呢,出在架构的混乱。
MVC模式
MVC模式
可以说任何一个学web开发的人都要接触到的模式,但是很多人并没有把他用到写代码中。
什么是MVC
从前端的角度来看:
Model
, 是数据模型,从后端或者本地或者其他任何地方获取到的数据,同时提供操作这些数据模型的接口,说白了就是增删改查。
然后业务逻辑应该基于这些操作数据模型的接口,完成各种业务过程,比如说我的数据模型有 老师
、学生
、课程
、奖章
、积分
等,然后提供了对各种数据模型单独的增删改查
的接口,业务逻辑层想要完成一个 老师给学生发奖章的过程, 那么就需要用到 新增奖章的接口、修改学生的接口等,按需求写完各种控制逻辑、组合操作数据模型的接口来完成这个业务过程。
View
,负责的是渲染,就是把数据模型经过业务逻辑处理的数据显示到界面上,当然他不知道要显示的数据的意义,他只懂渲染。这一层需要接触到用户,会涉及到交互逻辑、ui风格等,这些是View所擅长的。
Controller
, 数据模型和数据模型的变动要和界面同步,才能被用户感知,而view层很傻,并不知道要渲染的是什么,所有的数据都需要Controller层来“喂”给他,Controller层就像一个经纪人,View想要执行任何业务逻辑或想要任何数据都找他,而Controller会去找Service。他负责双向的绑定,这个过程很繁琐,是可以自动化的,于是这一层经历了各种变化,出现了MVP、MVVM模式。总之,这一层很薄,不应该有任何的逻辑存在,类似于一个交易所之类的东西。
然后前端现在的库或者框架,都是按照这个思路来做的,但是并不包括全部,react或者view只专注view层,他们只能算一个库,想要完成mvc的完整架构,需要搭配其他的vuex、redux、flux之类的库等,当然angular算是一个框架、完整的mvc模式。
前端的组件属于View层,负责渲染,但同时也属于Controller层,因为除了渲染,他还负责绑定数据、绑定业务逻辑和交互逻辑的功能(当然vue是实现了自动的绑定,Controller也可以叫View Model Binder了)。
我们项目用vue技术栈,数据模型层
对应state,数据模型的接口
对应mutation ,业务逻辑层
的职责包括 对action的处理, 请求服务端的接口, 调用数据模型接口mutation等, action是一个亮点,这是一个命令模型, view层
不需要直接调用service方法,只需要dispatch一个action,然后service会进行对应的处理,这种声明式的方式取代了传统的命令式的直接调用,优雅很多。
我们项目中的组件存在的问题就是在View和Controller(ViewModel)层 组件里写了很多业务逻辑,并且Model层没有数据模型、数据模型接口、业务逻辑层的明显划分。在上线时间的逼迫下,似乎只要能完成需求就是对的,但是真的是对的吗?为什么代码的bug多,为什么代码的复用性和维护性还有可读性都很差,我觉得原因出在架构。
比如这段代码:
在组件里调用了操作数据模型的接口,跨了一个层级(偷偷做了不该做的事),同时下面还有一段业务无关的代码。首先,View、ViewModel、Model应该是逐层向下依赖的,组件里不应该拿到store,组件应该保持stupid;其次,业务无关的横向代码应该抽取到 utils
、common
等 公共代码中。这种代码多了,可读性、维护性自然不会高,后来人会觉得很坑,上手很难。
理想的架构
我觉得理想的架构应该是这样的:
很明显的MVC分层
, 组件里只有渲染还有交互的逻辑,涉及到业务逻辑的部分都dispatch一个action
到 Model
层, 由对应的service
处理,service
里会组合各种操作数据模型的接口,网络请求的接口来完成数据模型的更新,也就是完成一个业务过程。state
和mutation
都很纯粹,state
里面是边界清晰的数据模型, mutation
只是对这些边界清晰的数据模型的增删改查、 当然划分了边界就可以模块化。
重构思路
针对项目中存在的问题,我的思路是首先把service
层建立起来,新的模块基于这个service
层来开发,组件不和数据模型耦合,已有的模块会尽量去做一些重构,当然这个重构可能“很危险”。其次是把业务逻辑无关的通用代码抽取到 utils
、common
、plugin
等之中。
具体的改动还没做,我的思路就是这样,欢迎来和我交互。