本文作者:辰木
本文通过介绍了当前云音乐 BFF 研发模式现状,阐述了对当前研发现状的一些思考以及总结了 X6 在低代码流程编排中的实践历程;通过阅读本文,可以快速了解和学习如何通过 X6 构建符合业务诉求的可视化流程编排产品。
背景
目前云音乐已经建立了基于 GraphQL 的 BFF 研发模式,具体介绍参见《基于 GraphQL 的云音乐 BFF 建设实践》,在探索前后端协同的 BFF 研发模式上,起到了一定的作用和影响。然而,这种研发模式并未解决业务侧研发人员的核心痛点,同时又引出了一些新的问题,主要体现在以下几方面:
BFF 场景下业务逻辑的编排诉求
- 逻辑编排能力低:由于 GraphQL 是用于 API 查询的 DSL,比较侧重数据聚合和选择;当存在一定的业务逻辑时,诸如对输入参数、输出结果做相应的处理,需要增加逻辑判断等,只能在 Groovy 脚本中实现;由于脚本实现没有相应规范,很容易导致大量业务逻辑会通过脚本实现,造成脚本滥用。
- 资源开销成本高:不论是测试接口还是业务实现接口,都会产生机器资源开销,目前存在大量无流量应用和实例,造成资源浪费。
- 交互复杂,上手成本高:由于产品概念较多且交互复杂,中间实现链路较长,导致接口调试不便,排查问题困难。
- 角色分工不清晰,服务治理能力弱:前端研发人员主要负责 API 接口搭建、自测,从而完成接口的交付;但在引擎服务集群稳定性、流量水位方面缺少评估经验,而这部分内容服务端研发人员相对更擅长点;另一方面,由于前端和服务端研发人员需要关注的领域和内容不同,一些运维操作通常都需要跨平台使用,导致服务治理困难。
服务的沉淀与复用
在活动玩法场景下已存在简单的轻量级流程编排能力,但由于接入复杂、平台使用困难,目前使用并不广泛;与此同时,在该场景下一些固化配置和逻辑处理也并未沉淀成为服务资产,导致相应业务逻辑的复用能力较低。
全链路低代码建设
另一方面,云音乐已经构建了 Tango 低代码搭建平台,具体介绍参见《网易云音乐 Tango 低代码引擎正式开源》。Tango 在 UI 层已经极大地提升了需求交付和研发效率,但在基础逻辑编排、基础服务编排、乃至模型驱动 UI 的基础资源编排方面还是一片空白,构建服务端低代码产品,建立全链路低代码研发模式是重要建设目标。
思考
BFF 的应用场景是根据当前业务需要,对多个微服务接口返回的数据进行组装,会承载一些业务逻辑判断或数据格式转化,方便客户端(包括:PC Web,H5,App,小程序等)消费的架构模式,其主要是为了解决多访问终端业务耦合问题。
云音乐当前的 BFF 的研发模式只是交付 C 端部分业务场景的方式之一,其他 C 端场景以及大量 B 端场景也或多或少都存在相类似的诉求,但交付需求的方式依旧是传统的研发方式。相比较前端可通过组件、模块、页面模版、样板间、微前端架构等众多方式快速复用 UI 和交互能力,服务端想沉淀和快速复用一些服务资产时,存在诸多不便。这些不便主要体现在:接口实现规范较多,统一实施难以落地;微服务较多边界较模糊且占用资源不一,一些场景下又需要将多个微服务合并成一个微服务。
那么在云音乐当前研发现状下,有没有一种方式,即能实现自由组装服务资产,清晰地表达服务间依赖关系和对应业务场景逻辑;又能通过一定的手段沉淀和复用服务资产,在给定输入值后可自动调用依赖服务输出结果;与此同时,还可搭配 Tango 低代码搭建平台,在整体研发链路上进一步降低开发成本,提升交付质量和效率。
答案是存在的,那就是:基于流程编程 (Flow-based programming)
关于 FBP
基于流程编程是一种特殊形式的数据流程编程范式,其可以将程序表达为具有输入和输出的有向图,图内每个节点具备一定的中间运算过程,并通过特殊逻辑关联将节点衔接起来,当给定输入时,就会自动执行并输出结果。
典型的 FBP 程序图表达如下图所示:
通过对 FBP 程序的图表达分析不难发现,这种有向图包含着明确的输入和输出节点、中间依赖节点、以及节点间连接关系,其是可以通过流程图的方式表达的。
解法
为了解决当前研发现状所面临的诸多问题,基于 FBP 的理念和流程图可视化编辑能力,云音乐公技低代码团队发起了 TangoFlow 项目。项目旨在通过组装式架构,整合云音乐服务端技术栈,提供基础逻辑编排能力,以网关 API、统一 SDK 等方式暴露编排结果;从长远目标来看,期望构建符合云音乐研发现状的服务端低代码平台,结合 Tango 搭建平台在提升需求交付效率和吞吐率、降低交付成本的同时,建立起完整的全链路低代码研发模式。
架构设计
我们期望开发者在平台创建好流程后,借助可视化搭建能力对服务资产进行编排组装,通过接口将图信息传给服务端;服务端得到图信息后再将其转化为 DSL 并发送给流程引擎,引擎在得到 DSL 后会自动解析和执行并以特定方式暴露编排结果,从而提供给客户端消费,用户使用流程大致如下:
那么基于以上思考、期望目标以及用户使用核心链路,我们明确了 TangoFlow 的产品架构,整体设计如下:
技术选型
构建基础逻辑编排能力,首当其冲是要实现可视化的流程图编辑能力。在对比了社区众多相关流程图编辑产品后,决定使用蚂蚁开源的 X6 图编辑引擎,其主要有以下优势:
- 核心功能稳定,持续迭代并完善自身能力
- 开箱即用,组件和插件完备,便于定制,也可通过相应注册机制灵活扩展能力
- 事件驱动,有完备的事件机制来处理相关交互逻辑
- 数据驱动,支持图内的节点和关系的序列化和反序列化
- 丰富的案例实现,可快速查看和在线调试运行
产品设计
由于流程编排本质上是抽象输入、输出、服务为节点组件,通过可视化拖拉拽将这些组件按流程图方式组织,从而完成对应的逻辑表达需求。鉴于社区不乏相关优秀的产品,比如 XFlow、LogicFlow、ProcessOn、Figma、语雀、ioDraw等, 通过对这类产品的抽象和总结,最终确定 TangoFlow 的可视化编排界面结构如下图所示:
顶部导航
顶部导航需要展示一些核心的信息,同时也需要承载一些核心操作以及其他跳转入口,主要体现在以下几方面:
- 核心信息:所属应用、编排的流程、分支信息等
- 核心操作:分支切换、撤销/重做、画布缩放、 保存、发布等
- 其他入口:回到首页、前往 APM、问题反馈等
物料
物料面板不仅需要显示有哪几类、哪些节点组件,同时也需要节点组件具备拖拽至画布内自动添加和显示的能力。通过对流程图的抽象分析,我们将流程中包含的节点分为以下几大类:
- 触发器:流程对应的输入节点,其主要是暴露网关服务端 HTTP 服务
- 逻辑控制:一些常见的逻辑表达,如 if-else、switch、for 迭代逻辑等
- 基础服务:适配云音乐的服务资产,如:RPC 接口、Groovy 脚本、网关 API 接口等
- 数据结果:流程对应的结束节点,其主要是控制 BFF 服务输出的内容格式和数据结果。
画布
画布作为流程编排的核心能力,不仅需要提供流程节点的展示、节点组合嵌套、节点连接关系表达外,同时也需要承载一些快捷交互能力,诸如节点信息编辑、节点菜单、画布菜单、边标签设置等。
属性设置
通过对流程中涉及每个节点的属性抽象,产出相应的节点属性配置;由于每个节点所对应的属性配置是不同的,每个属性在设置时所需的 UI 组件也不尽相同,这就要求属性设置是一个动态表单,且需要具备足够的灵活度以及扩展能力。
控制台
在对流程进行调试时,控制台区域不仅需要展示请求入参和输出结果,也需要展示引擎运行 DSL 时的调用过程,方便在调试出错时能快速定位具体是哪一部分发生异常。
相关实现
基于以上产品设计和一些核心功能要求,最终的的 TangoFlow 的编排界面展示如下:
节点属性
得益于 X6 的强大能力,很简单通过 json 配置便可实现一个节点的样式及相关交互能力。一个 IF 节点的 json 配置如下图所示:
- markup: 指定了渲染节点时使用的 SVG 片段,表明在该片段存在那些标签元素
- width:节点在画布中的宽度
- height:节点在画布中的高度
- attrs:对 markup 中定义的元素选择器的 SVG 属性描述
- data:与节点关联的业务数据,主要是抽象出来的节点名称、类别、业务属性等,可通过 props 透传给属性面板使用
- ports:连接桩,即节点上的固定连接点
- tools:节点工具,可以增强节点的交互能力
通过举一反三的方式其他节点的配置也是如此,整体便可组成所需节点的属性配置 list 数据;在明确节点属性后,便可使用注册方法来注册画布所需的节点了,画布组件的实现和节点注册示例代码如下:
节点拖拽
由于 X6 已提供了 Dnd 插件,可快速实现往画布内拖拽节点自动显示的交互方式。整体实现思路是:在拖拽事件触发时,需要先调用创建节点方法,再通过节点对象进行节点属性修改和业务数据设置,最后调用 dnd.start() 方法。核心实现代码如下:
节点/画布菜单
当需要鼠标右键点击显示节点菜单时,可通过往节点添加自定义工具实现,效果图如下:
实现自定义工具的思路如下:
Canvas 组件内设置固定的 dom 节点用以渲染相关内容,部分示例代码如下:
实现自定义菜单,可通过继承 ToolsView.ToolItem 来覆盖内部一些具体逻辑,核心实现代码如下:
在注册节点时,注册节点工具,示例代码如下:
配置节点工具 tools 属性,示例参考:
节点提示
同样当需要鼠标 hover 显示节点提示信息时,也可通过往节点添加自定义工具实现,实现思路与实现节点菜单一致,此处不做过多赘述,展示如下:
实现节点提示时需要注意以下几点:
Canvas 组件内设置固定的 dom 节点用以渲染相关内容,示例代码如下:
- 由于是自由画布,需要考虑提示框的显示位置,可相对于节点位置来显示。
- 需要注意节点鼠标进入和节点鼠标移出与节点鼠标按下、节点连接桩移入等其他事件的影响。
节点提示组件的核心实现代码如下:
节点组合设置
embedding 是实现节点组合嵌套的核心,具体配置可参考文档说明;当需要检查节点是否允许被组合嵌套时,可通过 validate 方法实现,实现代码如下:
以下两类逻辑控制节点便是借助组合嵌套实现:
Switch 判断:有固定的 I/O 连接桩,通过属性配置增加 case 枚举条件,仅支持嵌套 If 和基础服务节点,展示如下:
For 迭代器:有固定的 I/O 连接桩,可指定迭代对象、对象类型以及迭代返回值格式,支持嵌套 If、Break、Contine 和基础服务节点,展示如下:
边标签设置
边标签设置是基于内置的 edge-editor 实现的,通过双击边可自动添加边标签;不过由于该小工具并未判断限制,鼠标双击可创建多个标签;如果想每次只修改和保存一个,可在对应的 setText 方法内先删除再添加,示例代码如下:
连接检查
connecting 是实现节点连接交互的核心,具体配置可查阅相关文档,当需要对节点间是否允许连接时,可通过 validateEdge 来实现,避免一些非法连线如:节点回环、从输出到输入等,实现代码如下:
属性面板
在产品设计章节有提到属性面板需要具备足够的灵活度以及扩展能力,鉴于 Tango 已经实现相关属性表单能力,此处可直接引入使用,具体使用和实现方式参见 setting-form
调试能力
流程在搭建完成后,还需要在线调试和验证。实现调试的思路是:借助 graph.toJSON() 方法导出节点和边的 json 格式数据,在通过接口将这些节点数据传递给服务端,服务端拿到 json 数据后转化为 DSL 并执行,从而实现流程的在线调试能力。目前,TangoFlow 支持了以下三种方式的调试能力:
流程调试,通过设置输入参数或者请求头信息,对整体流程进行调试,界面展示如下:
节点调试,对当前的服务节点进行在线调试,页面展示如下:
- 远程调试,即指定某一环境对应的集群内机器后进行流程调试
Mock 机制
mock 的能力主要是为了方便在线调试,确保流程在调试过程尽可能的暴露问题和快速通过测试,在进行调试时设置的 mock 数据也会一并发送至服务端,服务端在进行 DSL 转化时,会自动读取 mock 数据并写入 DSL 内。
对于基础服务节点来说应具备请求参数 mock 和响应 mock(固定返回 mock 值),而对于输出节点只需具备响应 mock 即可,在开启 mock 能力后节点会自动显示 mock 标记,页面展示如下:
发布卡点
针对流程每次的发布,我们制定了严格的发布部署模型;流程发布会经过开发、回归、卡点、预发、线上、完成这六个阶段;在开发和回归环境,可以存在多个分支发布部署;当一个分支需要发布上线时,需要先经过卡点环节的各项检查;只有卡点环节通过,才会被允许进行预发和线上环境的部署,并且流程线上发布的通道内只能存在一个分支;在线上环境部署后,线上环境测试通过,点击完成即可结束当前分支的发布生命周期。
通过此发布部署模型,确保了流程发布的稳定性,整体实现如下图所示:
总结
以上是借助 X6 在构建云音乐低代码流程编排能力时的一些实践历程,其强大的图编辑和自定义能力,使得可快速实现符合业务需要的流程编排诉求。在实现某一具体场景的编排产品时,个人觉得需要注意以下几点:
- 明确编排能力的核心诉求,并确定优先级
- 多参考和分析其他类似的优秀产品相关能力,然后多尝试用一些设计工具实现
- 做更多的技术预研,分析各个相关工具的优缺点,明确其擅长的应用场景
- 相比代码实现,前期的产品设计和技术预研至关重要
未来展望
随着当前编排能力的趋于成熟稳定,在继续完善全链路低代码建设的同时,也会在 AIGC 方向探索更多的可能,不断地重塑产品能力,未来主要包含以下方面:
- 继续整合服务端相关技术栈资源,借助编排的方式实现对相关资源的最大化利用
- 结合 Tango 完备的前端搭建体系,构建模型驱动 UI 的研发模式,进一步提高需求交付效率
集成 AIGC 能力,借助 AI Agent 能力根据用户的自然语言输入,自动识别用户意图从而完成一系列动作
最后
更多岗位,可进入网易招聘官网查看 https://hr.163.com/
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。