乐趣区

关于前端:编写高质量可维护的代码数据建模

67 篇原创好文~
本文首发于政采云前端团队博客:[编写高质量可保护的代码:数据建模
](https://zoo.team/article/data…

什么是数据建模

数据建模是一种用于定义和剖析数据的要求和其须要的相应反对的信息系统的过程。

随着前端页面的交互变得更加细腻简单,本来寄存于服务端的状态搁置在了前端,相似 flux、redux、mobx、dva、rematch、vuex 的状态治理库也成了每个我的项目的标配。

因为分层理念的遍及,前端工程师们须要把更多精力放在数据管理上,数据建模也成了基本功。

而建模的产物是 数据模型,数据模型是定义数据如何输出和输入的一种模型,其次要作用是为信息系统提供数据的定义和格局。

数据模型包含 数据结构、数据操作、数据完整性约束条件 这三要素。

简略了解就是数据模型提供了一个“模具”,数据依照事后的设计和束缚进行搁置。

三要素

数据完整性约束条件

好的数据结构必须要有束缚,例如形容同一个状态的字段有时候是字符串,有时候是数字,这样的话就容易造成预期之外的状况。增加束缚能够最大限度保障这份数据是洁净参差的;

// status 是字符串的时候不通过
if (status === 1) {...}
// 依照肯定束缚
model.define(
  'user',
  {
    name: { 
      field: 'name',
      type: STRING(64),
      allowNull: false, 
      comment: '姓名',
    },
    sex: {
      field: 'sex',
      type: INTEGER(1),
      allowNull: false,
      comment: '性别',
    }
  }
);

数据结构

形容模型自身的性质之外,还需通过某些字段表白模型(表)和模型之间的关联;

数据操作

在数据结构上对数据或者数据之间的关联关系的操作。

畛域驱动设计

在围绕着数据模型进行利用开发的时候,咱们会思考如何进行建模呢?

实际上,软件开发行业中曾经积攒了一些方法论,例如 畛域驱动设计 (DDD) 就被宽泛采纳。

在进行软件开发前,通常须要先进行业务知识梳理,而后达到软件设计的层面,最初才是开发。而在业务知识梳理的过程中,咱们必然会造成某个畛域常识。依据畛域常识来一步步驱动软件设计,就是畛域驱动设计的基本概念。简略来说畛域驱动设计就是 关注精简的业务模型及实现的匹配

分层架构

依照畛域驱动设计的分层架构能够将利用进行分层

  • UI 层:负责向用户展示信息以及解释用户命令。
  • 应用层:用来协调利用的流动。它不蕴含业务逻辑;它不保留业务对象的状态;但它保有利用工作的进度状态。
  • 畛域层:业务软件的外围所在。在这里保留业务对象的状态,对业务对象和它们状态的长久化被委托给了基础设施层。
  • 基础设施层:为其余层的撑持库存在。它提供了层间的通信,实现对业务对象的长久化,蕴含对用户界面层的撑持库等作用。

依照这个分层,越往左边代码变动越频繁。随着业务简单,应用层和畛域层的边界变得含糊,畛域之间也容易交织在一起。

良好的设计应该防止层与层之间产生过多依赖,如果代码没有被清晰地隔离到某层中,它会迅即变得凌乱和难以保护。

通过分层架构和高内聚低耦合的设计思维,最终实现零碎与需要有较好的一致性,在业务迭代中疾速响应需要变更。

实体

实体在畛域模型中是必须的对象,并且它们应该在建模过程开始时就被思考。例如要实现一个“猫”的概念,咱们可能会去发明一个 Cat 的类,这个 Cat 可能蕴含名称、性别、种类等属性,然而这些属性都不足以辨别这只猫,所以咱们须要创立一个惟一不反复的 ID 来辨别他们,也就辨别实体的标识符。

创立 ID 的形式有很多种,它能够是主键、能够来自内部、也能够由零碎本人产生,但它必须合乎模型中的身份差异。

值对象

用来形容畛域的非凡方面,且没有标识符的一个对象,叫做值对象。例如画布上的一个点 Customer 会跟姓名、省份、城市、区、街道相干。最好是将地址分离出来,保留对地址的援用,因为它们都是同一个址属性。

服务

你能够简略地将行为了解成一种服务。例如你去商店购买商品,你的敌人也能够去购买商品。如果将购买这个能力作为一个属性放在 Person 这个实体里显然有点不对劲,因为“去购买”这个性能并不属于你和你的敌人(实体或者值对象),同时去购买也可能波及到商品对象。

保障服务的单一性和隔离十分重要,留神辨别畛域服务和应用服务。决定一个服务所应归属的层是十分艰难的事件,咱们在设计阶段建设模型时,须要确保畛域层从其余层中隔离开来。

模块

模块是一种被用来作为组织相干概念和工作以便升高复杂性的办法,通常状况下由性能或者逻辑上属于一体的元素形成,以保障高内聚,同时通过接口的模式裸露给第三方以升高模块之间的耦合。

聚合

聚合是针对数据变动能够思考成一个单元的一组相干对象。聚合基于(有且仅有)一个实体(根),聚合通过这个根被内部拜访,它能够援用任意聚合或者被其余聚合援用。以下是一个简略的聚合例子:客户作为聚合的根,其余信息都是客户外部的,如果须要地址则将地址的拷贝传递进来(Javascript 中特地须要留神)。

工厂

工厂用来封装对象创立所必须的常识,它们对创立聚合特地有用。工厂办法是一个对象的办法,蕴含并暗藏了创立其余对象的必要常识。

资源库

资源库作为一个全局可拜访对象的存储点而存在。它是一个独立的层,介于畛域层与数据映射层(数据拜访层)之间。它的存在让畛域层感觉不到数据拜访层的存在,它提供一个相似汇合的接口,提供给畛域层进行畛域对象的拜访。

前端的数据建模

数据建模和后端的工作关联较为严密,前端的数据模型更多是依赖后端传递的数据传输对象(DTO)进行二次构建。无论二次构建是产生在服务端聚合阶段还是用户端 AJAX 申请实现阶段,前端都须要参加肯定的数据荡涤,并利用到前端的数据模型之上。

畛域划分

当初你能够开始尝试划分你利用内的业务畛域。以一个商城为例子,它可能会包含用户、商品、货架、订单、结算、账户等内容。

每一个业务畛域都能够至多拆分成一个畛域,依照业务畛域来组织代码,例如在交易畛域中依照以下目录构造划分:

src
  modules 
    ...
    trading             # 交易畛域
      components/         # 组件
      models/             # models
      pages/              # 页面
      redux/              # redux
      services/           # 交易模块相干 api
      styles/             # 交易模块款式
      index.ts
  ...

概念模型

数据建模的前提是对业务的充沛了解,充沛了解业务相当于在更高的视角去对待业务之间的关系,有利于更好地实现模型建设。

尝试回忆一下你所保护的业务(利用)场景,你是否清晰业务场景和业务对象之间的关系以及具体交互?

应用思维导图梳理出概念模型,这个阶段能够不必严格遵守三要素,指标清晰表白事实世界就行。

定义模型

定义模型能够根据概念模型,补充细节和关联关系,例如简略定义一个营销商品:

以上展现了商场货架上划分的一块流动区域,规定是满 XX 减 XX,再将参加该流动的商品在区域内进行上架。

升高复杂度

在大部分状况下,特地是展现逻辑这块,前端不应该是重逻辑的。

以商品为例,不同商品的营销类型背地暗藏着简单的价格体系,只管是同一种营销类型,商品在不同的状态展现的价格也不肯定雷同。你能够设想这背地的字段,以及计算规定。

如果后端把这些字段、各种 price 和规定一股脑抛给你,先不谈前后端对称问题,光挑字段都能让你目瞪狗呆。

遇到相似状况更好的方法是:尽量避免在前端(用户端)去解决简单的业务判断,在聚合层或者让后端同学给你解决好这些展现逻辑。

特地是在 C 端场景下,数据直出显得更加重要,同时前端同学也有更多工夫去做性能优化(早点上班不香么?)。

另外一个益处是如果呈现展现问题,你只有确定读取的字段正确,剩下的仅需一个人排查就够了;

// Bad
const switchPrice = product => {switch(product.status) {
    case 0:
        return product.priceA;
    case 1:
        return product.priceB;
    case 2:
        return product.priceB;
    default:
        return  product.priceBase;
  }
}
<Price value={switchPrice(product)}/>
     
// Good
<Price value={product.price}/>

逻辑分层

设计上须要辨别应用逻辑(业务逻辑)和展现逻辑。应用层重视对畛域层的调度,是业务逻辑的实现,展现层专一渲染和交互动作。

在一个大型项目中,同一个 Model 可能被多处援用,你很难确定谁最终会对同一份数据进行怎么的操作。

同时 Model 中仅保留数据源的形象构造,而不批改数据源的内容。

// 在视图层只做展现逻辑解决
// 组件 A
...
<>
    <span> 日期:{format(res.date, 'YYYY-MM-DD')}</span>
</>

// 组件 B
...
<>
    <span> 日期:{format(res.date, 'YYYY-MM')}</span>
</>

对立字段

在设计模型的时候,尽可能与后端放弃对立字段。比方某些表单场景在回显和提交的时候要多一层转换,前期保护会带来多一层心智累赘。在前后端拆散的开发模式下,不肯定能保障后端会先给出字段,我的习惯是标记字段,等联调的时候全局替换一下就行了。

简化字段、明确语义、扭转不合理的前后端交互是做好数据建模的根底,否则你将破费大量工夫去了解这些字段背地的含意和计算规定。

小结

没有一个美中不足的数据模型能够实用任何需要场景,模型的落地须要综合思考业务理论场景和技术选型。在构建模型的过程中,锤炼系统性思考能力、从更高的视角对待业务,能力发明出一个生命周期更长的模型。

招贤纳士

政采云前端团队(ZooTeam),一个年老富裕激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 50 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员形成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端利用、数据分析及可视化等方向进行技术摸索和实战,推动并落地了一系列的外部技术产品,继续摸索前端技术体系的新边界。

如果你想扭转始终被事折腾,心愿开始能折腾事;如果你想扭转始终被告诫须要多些想法,却无从破局;如果你想扭转你有能力去做成那个后果,却不须要你;如果你想扭转你想做成的事须要一个团队去撑持,但没你带人的地位;如果你想扭转既定的节奏,将会是“5 年工作工夫 3 年工作教训”;如果你想扭转原本悟性不错,但总是有那一层窗户纸的含糊… 如果你置信置信的力量,置信平凡人能成就不凡事,置信能遇到更好的本人。如果你心愿参加到随着业务腾飞的过程,亲手推动一个有着深刻的业务了解、欠缺的技术体系、技术发明价值、影响力外溢的前端团队的成长历程,我感觉咱们该聊聊。任何工夫,等着你写点什么,发给 ZooTeam@cai-inc.com

退出移动版