如何管理好10万行代码的前端单页面应用

2017-10-14 02:48:25      来源:互联网

原标题:如何管理好10万行代码的前端单页面应用

蚂蚁金服数据平台前端团队主要负责多个数据相关的PC Web单页面应用程序,业务复杂度类比Excel等桌面应用,业务前端代码量在几万行~几十万行,随着产品不断完善,破百万指日可待。管理好10万行级甚至百万行级代码的前端应用,是我们团队的核心挑战之一。

接下来的系列文章,我会尝试从以下几个角度介绍我们团队应对挑战的方法:

前端架构

质量保障

性能优化

团队前端开发流程

人员素养

前端架构

团队的架构方案是多个产品经历一年的持续迭代,不断摸索出来的一套适合本团队数据产品业务场景的架构方案,架构方案中还存在尚未解决的痛点和有争议的部分需要持续优化,不保证这套架构适合您的产品。

产品特点

先介绍下我们团队的产品特点:

ToB产品,业务复杂度高、业务理解门槛高;

前端代码量巨大(数据分析产品从零开始经历8个月迭代业务代码8万行,仅实现了产品长期规划需求的20%)

架构方案

架构的目的是管理复杂度,将复杂问题分而治之、有效管理,我们的具体方法如下:

1. 首先通过路由切割“页面级”粒度的功能模块

这里的“页面级”粒度指一个路由映射的组件

如何管理好10万行代码的前端单页面应用

router 2. 同一“页面”内的模块再划分

划分原则:

纵向:通过业务功能(可根据视图模块判断)划分

横向:通过Model-View-Controller三种不同职能划分

如何管理好10万行代码的前端单页面应用

module 3. 合并同类项

继续细分粒度,然后将可复用模块或组件抽离到公共区域

3.1 数据模型

数据模型根据职责分成两类:

    Domain Model 领域模型

    App State Modal 应用状态模型

3.1.1 领域模型

领域模型是业务数据,往往要持久化到数据库或localStorage中,属于可跨模块复用的公共数据,如:

Users 用户信息

Datasets 数据集信息

Reports 报表信息

领域模型作为公共数据,建议统一存放在一个叫做Domain Model Layer的架构独立分层中(前端业界一般对这层的命名为ORM层)。

下沉到Domain Model Layer(领域模型层)有诸多利处:

跨模块数据同步问题不复存在,例如:之前Users对象在A和B两个业务模块中单独存储,A模块变更Users对象后,需将Users变更同步到B模块中,如不同步,A、B模块在界面上呈现的User信息不一致,下沉到领域模型层统一管理后,问题不复存在;

除领域模型复用外,还可复用领域模型相关的CRUD Reducer,例如:之前Users对象对应的Create Read Update Delete方法可能在A和B两个业务模块各维护一套,下沉到领域模型层统一管理后,减少了代码重复问题;

自然承担了部分跨模块通信职责,之前数据同步相关的跨模块通信代码没有了存在的必要性;

3.1.2 应用状态模型

应用状态模型是与视图相关的状态数据,如:

当前页面选中了列表的第n行 currentSelectedRow: someId

窗口是否处于打开状态 isModalShow: false

某种视图元素是否在拖拽中 isDragging: true

这些数据与具体的视图模块或业务功能强相关,建议存放在业务模块的Model中。

3.2 视图层组件

组件根据职责划分为两类:

    Container Component 容器型组件

    Presentational Component 展示型组件

3.2.1 容器型组件

容器型组件是与store直连的组件,为展示型组件或其它容器组件提供数据和行为,尽量避免在其中做一些界面渲染相关的事情。

3.2.2 展示型组件

展示型组件独立于应用的其它部分内容,不关心数据的加载和变更,保持职责单一,仅做视图呈现和最基本交互行为,通过props接收数据和回调函数输出结果,保证接收的数据为组件数据依赖的最小集。

一个有成百上千展示型组件的复杂系统,如果展示型组件粒度切分能很好的遵循高内聚低耦合和职责单一原则的话,可以沉淀出很多可复用的通用业务组件。

3.3 公共服务

所有的HTTP请求放在一起统一管理;

日志服务、本地存储服务、错误监控、Mock服务等统一存放在公共服务层;

按照上面三点合并同类项后,业务架构图变更为

如何管理好10万行代码的前端单页面应用

api 4. 跨模块通信

模块粒度逐渐细化,会带来更多的跨模块通信诉求,为避免模块间相互耦合、确保架构长期干净可维护,我们规定:

不允许在一个模块内部直接调用其他模块的Dispatch方法(写操作、变更其他模块的state)

不允许在一个模块内部直接读取其他模块的state方法(读操作)

我们建议将跨模块通信的逻辑代码放在父模块中,或者在一个叫做Mediator层中单独维护。

最终得到我们团队完整的业务逻辑架构图:

如何管理好10万行代码的前端单页面应用

Architecture 数据流管理

刚刚从空间维度讲了架构管理的方案,现在从时间维度说说应用的数据流转 --- Redux单向数据流。

Redux架构的设计核心是单向数据流,应用中所有的数据都应该遵循相同的生命周期,确保应用状态的可预测性。

如何管理好10万行代码的前端单页面应用

redux 1. Action

用户操作行为:click drag input ...

服务端返回数据后续的行为

2. Reducer

每个Action都会对应一个数据处理函数,即Reducer。特别强调,Reducer必须是纯函数(pure function),这个规定带来一个非常大的好处,数据处理层代码变的非常容易写单元测试。

纯函数的特征是入参相同的情况下,返回值恒等,举个栗子

本文链接:http://www.baifenbai.org/kjpd/3848514.html