企业级应用搭建平台是如何设计资产体系的?

简介: 看看云凤蝶的资产体系设计。
作者 | 绯一

image.png

搭建系统行业现状

面向领域提供解决方案,提高生产效率

image.png
via 云凤蝶可视化搭建的推导与实现

搭建系统并不是一个稀奇的概念,从 Dreamweaver 开始,有大量的产品试图用装配式的开发解决应用生产的效率问题。它们面向特定场景做抽象、沉淀出最佳实践,再通过产品封装来加速整个制作过程。

比如 Dreamweaver 认为 HTML 树是不重要的,应该通过所见即所得的自由拖拽生成;比如 SwiftUI 认为移动场景下,数据的流向与更新应该被高度简化,于是提供简洁的交互来快速建立组件与模型间响应式的数据流。

搭建系统要解决什么问题?

一言以蔽之,缺人。

前端沉重的上手门槛导致招聘培养非常困难,前端资源逐渐成为项目瓶颈,无法跟上爆发式的业务增长。现场我做了一个调查,写过前端页面的人中只有 1/3 是专职前端,剩下的大家都是被逼的没办法:服务早就写好了,但没前端资源,只能撸起袖子自己把页面做了。

image.png
via How it feels to learn JavaScript in 2016

如何解决问题?

参考制造业的最佳实践

作为高精尖产品 iPhone,通过标准化手机的制作程序,将大量生产外包。苹果有 200 多个零部件供应商,400 多道组装工序,终端的富士康郑州工厂每天可以生产 50 万部 iPhone,零部件拆分和流水线的组装大大提升产能,苹果通过这种方式书写了普通工人批量制造高精尖产品的神话。

image.png
iPhone 的供应链,红框内是富士康 via 云凤蝶中台研发提效实践

汽车行业将整车拆分为零部件,外包给专业的零部件生产商,再通过流水线的组装完成最后一步。这些组装汽车的人,可能对汽车一窍不通,但只需要在流水线,按部就班的重复再重复就行了。

image.png
传统研发 vs 搭建研发 via 云凤蝶中台研发提效实践

还有我们所熟悉的每一个快餐店:

image.png
论如何制作汉堡包

通过上面几种抽象,传统的生产过程被重新解构为:

  • 擅长生产零部件的沉淀为领域专家:比如相机、螺丝、轮胎、面包和炸鸡,在领域内不断突破降低成本
  • 在终端门槛极低的流水线组装:可以招聘大量普通工人扩大生产,实现效率的不断提升

云凤蝶的实践经验

企业级应用制作平台

在如今的 Web 领域,无论是大公司还是小公司,都很少会从 span、div 标签写起,大家都会有自己的一套组件库,对于 Web 研发我们似乎也可以使用这样的思路来解决问题。

在蚂蚁集团,有 36% 的中后台应用以这种方式搭建,应用的平均复杂度在 20 个页面,上百个组件的量级。我们通过对中后台应用的抽象,结合设计规范,希望能重新定义应用的制作方式,解决三个问题:

  • 降门槛:非专业前端也能搭建,拓展新的角色在终端「组装汽车」,可以大量外包用工
  • 提效率:结合设计规范,简化应用制作的各种概念,比如样式、布局、数据流、网络请求
  • 60 分:很多中后台应用缺乏产品和设计,体验参差不齐。之前 Ant Design 的作者曾提过一个观点,antd 最大的价值是保证应用可以达到一个最低及格分

自然搭建系统在发展中也会面临各种问题,本文主要结合在云凤蝶的实践经验,聊一聊对于一个搭建系统来说,如何通过组件化的思路应对搭建系统发展上面临的各种挑战。

一个搭建系统要面临怎样的挑战?

支持的业务复杂度提升,搭建系统的复杂度也会提升

每个人应该都写过最朴素的搭建系统,它的形式类似一个营销搭建系统。在业务开发中,我们会把页面中经常变化的内容抽象为模版的配置项,并在模版外进行配置,每当配置变化,模版无需重新构建和验证即可快速迭代,此时一个应用由一个巨大的模版组成,如下图 1。

随着需求复杂度的提升,搭建系统需要做更细粒度的拆分。比如双 11 有多个活动页面,页面间有一些共享模块,比如签到和抽奖。从复用和维护性的角度,我们会面向功能封装出一些业务组件,此时搭建系统也相应要进化为楼层式搭建,对业务组件做二次编排和配置。

原本的一个配置项变为配置项数组,按照顺序描述每个组件暴露的接口,此时的搭建系统已经能够承载一定对复用的需求,有了组件化的雏形,如下图 2。

image.png
搭建系统的演进过程

再往后发展,页面出现了更自由的组合关系:导航栏、父子嵌套、弹窗、表单表格,这是典型的中后台应用。我们必须进一步拆分,并且多数组件已经无法针对具体应用重新开发,必须沉淀更细粒度的通用型组件,把原本大量内置到模版的逻辑,拆出来表达为组件间关系,才能支撑业务的持续增长,如上图 3。

从最简单的营销搭建到中后台搭建,整个组件体系在技术上有很多挑战:

image.png

组件体系 1.0 - 铸型

要建立一个怎样的组件体系,才能应对这些挑战呢?

组件从哪里来?

首先要回答一个问题,去哪找组件?

NPM 是社区非常有生命力的组件中心,复用 NPM 的基础设施是一个理想的选择:

  • 重新造一套组件的成本太高了,Ant Design 一个组件的平均成本在一个月左右
  • NPM 上有大量的高质量组件,可以快速补充组件内容
  • 不同的业务会有自己的一套组件库,无法全部内置到平台,必须要「开放」
  • 当业务出现自定义需求,可以封装 NPM 完成最后一公里

image.png
和 NPM 的关系

组件的生产必须与平台解耦,再通过组件规范建立连接,这样才能快速建立组件生态,完成面向组件的拓展。

1、对组件进行抽象和建模

建立组件规范:NPM 和搭建系统的连接

前面我们提到,对应用的配置可以分解对多个组件的配置。一个典型的组件编辑的场景如下,我们要能找到组件向外暴露的接口,并通过图形化的方式编辑他们。

image.png
编辑组件

再以主流的前端框架来看,一个组件是什么?

image.png
组件的抽象

UI 就是组件最终的渲染效果,f 是组件的实现,而 props 就是组件向外暴露的接口,以 React 的代码为例,上面的可视化编辑和下面的代码相对应:

<Button type="primary" loading={false} children="我是一个按钮" />

2、从类型出发找到组件

根据 NPM 的规范,我们可以从 package.json.typings 类型文件出发,通过 AST 解析找到所有的模块导出,并提取出其中符合 UI = F(props) 抽象的组件和属性定义。

比如在 React 技术栈下,React.ComponentReact.FCReact.PureComponent 都是符合要求的。

image.png
解析组件和 Props

3、识别/提取组件的元信息

找到组件后,我们可以深入挖掘他的元信息,比如如下的类型声明,我们很容易推测几件事情:

/**
 * @title 尺寸
 */
size: "small" | "middle" | "large";

/**
 * @format icon
 */
beforeIcon: string;

children?: React.ReactNode;
  • size 的中文描述是尺寸
  • size 只有三种取值,语义类似枚举,适合用下拉选择来编辑
  • beforeIcon 的类型是 string,但 formaticon,适合用图标选择器来编辑

将这些对元信息的推测规则沉淀下来,我们可以得到一个渲染引擎驱动的属性面板。在组件无需任何额外定义的情况下,尽可能的提升组件编辑效率。

4、一些复杂的编辑意图推断

除了上面对基础类型的简单推断,我们还可以做一些更深入的分析推断。

比如 nullable 通常用来表达可关闭的编辑意图。表格的分页属性可以配置为 Object 类型数据表达分页详细信息,也可以将值设为 false 来关闭整个分页功能,我们可以使用下面这种交互:

Table.pagination: false | Pagination

640 (2).gif
nullable

比如 unionType 通常用来表达分支情况。组件的提示信息有三种类型,每种类型都会一些特定配置项,在不同分支切换时,需要删除前一个分支的值,并为新的分支设置默认值。

tips: Text | Card | Popconfirm

640 (3).gif
unionType

组件如何加载、预览

应用如何处理 f 的依赖?

在写代码的模式里,我们把依赖安装到本地,再通过 Webpack 类似的工具对文件进行打包,每当代码修改/依赖发生变化,应用会重新构建,最终发布时,应用会把所有依赖的代码打包到一起。

但对于搭建系统来说,改一行文字等 5s 显然是不能接受的,我们要提供实时预览的方案。

image.png
一个简单的依赖关系

常见的玩法是,每个组件提前独立打 umd 包,应用只构建自己的代码,再通过 loader 远程加载所有外部组件依赖,形成一个 distMap,最终做组件渲染,这里 Map 的值就是上面我们提到的 UI = f(props)里的 f。

{
  Button: eval(request(buttonDist)),
  Card: eval(request(CardDist)),
}

React.createElement(map['Button'], ...);

但把所有依赖都打包进去的方法会导致 A 被重复打包多次,如上图,如果 A、B、C 分别打一个 umd 包,应用会有三个 A 的打包体积,并且对于 React.Context 等场景还会带来不同实例数据不通的问题。

我们需要有更细粒度的模块打包方式,能够支持按照版本规则对 A 进行复用。

1、Bundless 技术方案

NPM 包维度提前打包 & 实时依赖计算

组件在第一次进入到系统时,会按照依赖树递归的做 NPM 级打包,并将结果存储到 Assets CDN 上。

当前端应用的依赖发生变化时,通过请求 Assets CDN,按照版本合并 A & C 的所有依赖,并通过一次网络请求加载回来,再拆分给 loader 装载到 distMap 上。

image.png
组件导入 & 依赖加载

2、TreeShaking

上面的场景中,提前打包的粒度是 NPM 包级,这会导致一个问题,应用只使用了 lodash.get 但却加载了整个 lodash,体积还是很大。如下图,使用了 antdButtonMenuTable,最后加载了整个 antd

image.png
按需 TreeShaking

我们还需要做一些动态的处理,在应用发布时,根据应用对组件的实际使用情况,自动 TreeShaking 掉未使用的模块,创建一个虚拟的 antd 来降低体积。

这里有一些衍生的问题,如何保证依赖计算的速度、为什么 treeShaking 是安全的,以及为什么不做文件级的 Bundless?后续会有文章专门介绍。

组件体系 2.0 - 演进

「偷」来的组件不够好用怎么办?

通过一键导入 NPM 可以帮我们快速补充组件内容,但 NPM 上是相对松散的组件,距离在搭建系统上好用还有很大距离,我们需要对他们做一些封装,并且建立能持续迭代和治理的方案。

横向封装

1、弹窗类组件难以使用

弹窗类组件通常有一个受控属性来控制显示隐藏,如果设为可见,会挡住其他所有组件的编辑;如果设为不可见则无法编辑弹窗本身。

我们尝试抽象弹窗组件的特性,结合编辑态大纲树选中状态这一交互做一些封装:

  • 大纲树上选中 visible: true
  • 取消选择 visible: false

image.png

2、dataEntry 类组件双向绑定成本过高

输入框等组件的值也是受控模式,在输入框输入后需要手动在 onChange 方法里把新的值同步回 value 上,这使得表单类组件在搭建系统下使用效率很低。

我们同样去抽象这类组件的特征,在组件接入时,让组件回答几个问题:

  • 是否为表单类组件
  • 表达值的属性名是什么(比如 value)
  • 同步数据的事件是什么(比如 onChange)

这样我们可以建立一个虚拟的 store,在 onChange 事件触发时,自动完成事件参数到 value 的数据同步。在产品上的体现就是双向绑定,用户只需要为表单类绑定一个变量,数据同步就自动完成了。

image.png

3、面向特征做能力切面的拓展

类似上面两种的封装方式还有很多,这种面向组件特征而不是具体的组件做抽象,有几个非常明显的好处:

  • 横行提升表达力:此类组件都能使用,能力是有限的,但组件是无限的
  • 降低耦合:系统和组件解耦,通过能力描述建立关联
  • 统一心智:通用行为集中在与组件无关的配置区

image.png
组件表现力 = 组件数量 x 横向能力

举个例子,一个普通的头像组件,经过大量通用能力的描述可以变为带徽标的头像数组。

资产沉淀

除了用导入 NPM 的方式生产组件,我们还可以在搭建系统沉淀一些组件吗?

1、画布组件

如果一个应用中有多个地方都使用了相似的布局,我们可以把这部分内容提取为画布组件,并像 React 那样,向外暴露一些属性,实现一处维护、多处使用的目的。

如下,我们把用户信息的展示封装为一个组件,而用户信息作为外部参数传入,这种局部复用的思路和 NPM 是一致的,只是生产组件的方式不仅局限于写代码,还可以通过搭建。

image.png
封装画布组件

2、JSXBox 最后一公里

除了使用已有的组件进行搭建外,有些场景可能更适合用代码,比如根据数据动态嵌套渲染,或是绘制一个复杂的图表。我们可以在页面上挖一个洞,让用户写代码的方式,完成这部分定制化的需求。

它的形态有些类似 CodeSandbox,写一段 React 代码,最终和其他组件混合跑在一个页面上。

image.png
JSXBox

3、资产包

在持续发展中,每条业务线都会沉淀自己适用的业务资产,可能是一系列 NPM 包,也可能是我们可以提到的搭建系统内的资产。在产品形态上,我们可以引入资产大包的概念,业务线的开发可以聚合比如 UI 组件、工具函数、服务等,整合到资产包内,再发布给其他应用使用,通过这种方式完成业务资产沉淀和定向的二次效率提升。

并且无论是画布组件、代码组件、JSXBox 都是遵循同样一套组件规范,我们可以直接将搭建系统内沉淀的资产包发布到 NPM。

适合搭建的走搭建、适合代码的写代码。用户可以通过 NPM 完成各自的互相融合研发。

image.png
沉淀资产包

版本治理

只要有版本,就会有版本碎片

image.png
antd 的版本碎片分布 & antd4 changeLog

当搭建系统封装组件给应用使用时,必然会出现版本,也就必然面临版本碎片问题。版本碎片无论对组件的开发者还是使用者都是巨大的成本,对于搭建系统来说,如何解决这个问题?

一次 API 不兼容变更

我们来看一个具体的例子,Menu 早期用 Boolean 表达水平/垂直布局,但新的设计规范引入第三种布局,Boolean 无法承载,需要升级为 String 枚举,从 API 上来看,确实是一次不兼容升级。

image.png
Menu1.0 -> Menu2.0

但组件的 API 发生变化,能力并未发生变化,也就是 Menu2.0 仍然支持水平/垂直的布局能力,只是旧的 Boolean 数据不再适用新的组件实现,需要更新。

而搭建平台下,组件的使用是严格受控的,是一份结构化的数据,我们完全可以通过精准的 Codemod 来将所有旧版本的数据升级为新版本,即:

delete $props.vertical
create $props.layout: $before.vertical ? 'vertical' : 'horizontal'

通过这种方式,我们可以将大部分组件不兼容的版本升级上来,组件始终可以保持向前兼容,0 版本碎片。

分享一个数据,去年 antd 从 3 到 4 的升级,使用云凤蝶搭建的几百个应用全程无感知,只需要点一下升级等上一会就行了。

实现开放与收敛

有生命力的资产体系

image.png

通过上面各种手段,我们实现了一个无序的 NPM 组件到搭建系统的资产的过度,在这个过程:

  • 一键导入:让原来的组件都能用
  • 横向封装:让原来的组件在搭建系统下更好用
  • codemod:让用户始终用最新的组件

同时,面向组件规范、能力切面的抽象,使得在支撑更复杂业务的同时,搭建系统本身的复杂度可以得到收敛。通过底层的各种功能模块支撑,建立起一个有生命力的资产体系。

one more thing

如何评价程序员 50% 的时间都在写表单表格?

就算搭建系统再好用,资产再有生命力,用户仍然还是要一个表单项一个表单项配置表单、表格、高级搜索,处理双向绑定、字段映射等重复工作,面对有大量规律可循的增删改查中后台应用,我们能不能抽象一些套路,把程序员从千篇一律的工作中解脱出来呢?

实际上我们观察 API 文档可以发现,接口格式和最终的表单、表格有非常大的关联关系

  • GET /api/use 查询用户列表,大概率会使用表格,表格列和返回值有高度的对应关系
  • POST /api/user 新增用户信息,大概率会使用表单,表单项和入参数有高度的对应关系
  • name: string 大概率在表单中使用输入框,在表格中使用文本

这些推断来源于对 API 元信息的理解、按照能力切面为组件做的封装,以及中后台应用在设计上的最佳实践。

image.png
传统 vs 智能向导

有了智能向导的帮助,用户只需要选择接口、勾选他们想要的字段,再做一些简单的映射配置,即可生成带有完整逻辑功能的表单、表格页面,在云凤蝶应用中,有 53% 的等效代码由机器自动生成。

点击查看视频

写在最后

The dignity of movement of an ice-berg is due to only one-eighth of it being above water.
Ernest Hemingway

image.png

最后以一张经典冰山图作为结尾,实际上我们看到的很多酷炫功能,为了保障他的正常运行,在看得到的冰山下,有大量看不见的工具链路、渲染引擎、设计规则在悄悄运转。

作者:绯一 ,就职于蚂蚁集团体验技术部(AFX),专注于工程领域。曾参与组件规范、构建工具、应用框架、研发平台等基础设施的研发工作。目前主要负责低代码搭建平台的资产体系设计,致力于打造下一代 Web 研发平台「云凤蝶」。

image.png

相关文章
|
4月前
|
域名解析 弹性计算 运维
高效构建企业门户网站解决方案测评
阿里云提供的高效构建企业门户网站解决方案测评:通过阿里云ECS、云解析DNS、专有网络VPC和云效工具,实现快速、稳定的企业网站搭建。预估成本约15元,流程涵盖需求分析至运维管理。方案适合中小企业,但对非技术人员可能有难度,建议增加模板选择和详细教程以降低入门门槛。
132 33
|
4月前
|
监控 安全 搜索推荐
企业应用集成(EAI):连接企业系统的技术探索
【6月更文挑战第25天】企业应用集成(EAI)技术连接异构系统,实现数据共享和业务流程优化。EAI包括界面、业务过程、应用和数据集成,提升协同效率、降低成本、改善客户体验、支持创新及强化风险管控。实施涉及规划、需求分析、选择方案、开发测试、部署监控及维护优化。EAI在企业信息化中扮演关键角色。
|
4月前
|
开发框架 运维 前端开发
构建一体化运维平台的八大功能
【6月更文挑战第6天】构建一体化运维平台的关键8个基本功能。
|
4月前
|
弹性计算
高效构建企业门户网站测评
高效构建企业门户网站测评
|
5月前
|
运维 监控 安全
构建高效自动化运维体系的五大关键要素
【4月更文挑战第29天】 在当今IT基础设施管理领域,自动化已经成为提升效率、降低错误率和实现快速响应的关键驱动力。本文将探讨构建一个高效自动化运维体系所需关注的五大关键要素:标准化流程、模块化设计、监控与报警机制、持续集成/持续部署(CI/CD)和安全性考量。通过深入分析这些要素,我们旨在为企业提供一个参考框架,以实现更智能、更灵活的运维管理。
|
11月前
|
运维 搜索推荐 API
带你读《构建企业级好数据(Dataphin智能数据建设与治理白皮书)》——9. 开放能力:自由拓展,满足企业个性化需求
带你读《构建企业级好数据(Dataphin智能数据建设与治理白皮书)》——9. 开放能力:自由拓展,满足企业个性化需求
279 0
|
小程序 Java 人机交互
智慧校园大数据云平台源码,实现基础数据共享、应用统一管理
智慧校园云平台电子班牌系统,利用先进的云计算技术,将教育信息化资源和教学管理系统进行有效整合,实现基础数据共享、应用统一管理。借助全新的智能交互识别终端和移动化教育管理系统,以考勤、课表、通知、家校互通等功能为切入点,从班级建设、校园文化、班级文化、学生工作、信息发布、家校共育六大方面,着力打造满足用户场景,深度贴合学校教育的改革需求。
|
设计模式 自然语言处理 数据可视化
管理平台优势
介绍 DM 是一个完全开源的项目,源代码全部托管在 Gitee 上,项目源码和核心插件源码放在 https://gitee.com/xiaomagenb/dlvm
130 0
管理平台优势
|
监控 安全 网络安全
企业上云基础框架设计
在持续了多年的上云浪潮中,许多企业享受到了云计算带来的红利,也在云计算时代逐渐成长,业务与体量都得到了飞速的发展。然而随着企业的发展,企业所面临的问题也在不断产生着变化,本文将着重讨论一下如何更好的应对企业在阿里云上多业务多账号的统筹管理问题。
472 0
企业上云基础框架设计
|
存储 Cloud Native 安全
如何一站式快速构建企业全场景数据库管理平台?
Gartner 的报告显示预计到2022年将有75%数据库将采用云数据库,与此同时,IDC预计到2024年传统部署数据库市场将达到13亿美元,企业数字化转型升级,积极拥抱开源、云原生数据库成为重要趋势,也是必然选择。
1088 0
如何一站式快速构建企业全场景数据库管理平台?
下一篇
无影云桌面