背景与价值说到逻辑编排,大家应该都不陌生了。目前我们组有很多面向后端的逻辑编排技术专项,并没有统一的标准、通用的方案进行沉淀。也有前端逻辑布局的项目,但都是面向前端开发和提高效率的逻辑布局,我们想为非研发人员搭建一个平台,让他们可以基于图形组件构建逻辑。我们为什么要做这个?在搭建团队活动平台方面,随着页面可视化建设的蓬勃发展,对互动营销页面/组件的需求越来越大。为了提高开发效率,研发方在不断沉淀常用的基础库,与服务端协商标准化接口,降低维护成本,但现有的可视化构建效率和研发效率已经达到瓶颈。在紧张的时期形势下,我们迫切需要一种新的生产模式,这将给我们带来生产效率的突破。然后在前端尝试了页面级和模块级的复用,减少代码重复,提高产研效率。是不是也可以拆分到更小的粒度,在功能层复用逻辑?这就是我们最近打造的具有前端特色的逻辑布局平台——YOHO,它建立了一个编排器,让非研发人员可以自由地、规范地进行逻辑布局。以NoCode的形式,借助图形化的组件,构建和生产逻辑,可以在多个业务场景中复用。本文通过逻辑排列和视觉构建的设计和业务实践与大家交流。编排器的基本概念编排器在逻辑编排中通过可视化构建生成一个带有业务逻辑的容器;导出逻辑流程图,通过DSL转换生成业务实际执行的代码逻辑。可以理解为逻辑排列中的生产逻辑环节。平台端编排器如图所示设计为四个部分。工具栏、组件列表、构造画布、基本配置。工具栏包含保存逻辑、查看施工规范、导出逻辑等基本操作。组件是逻辑中的一个节点,一个功能,将业务中常用的逻辑提炼出来,按照编码规范进行沉淀。列表中有不同形状和颜色的组件如下图所示,这是我们按照功能类型对组件进行分类。中间部分是逻辑构造的画布。主要操作动作是将逻辑组件拖拽进去,通过定向线将组件连接起来,组合成一个有始有终的完整逻辑,从而实现具有特定业务意义的简单或复杂的逻辑。流程图也是核心部分。右侧是点击某个组件显示的对应的基本配置信息面板,是该函数的入参。我们的设计必须允许用户灵活配置组件的基本信息。在设计编排器时,我的目的是建立一个标准化的编排器,让用户通过技术手段最大限度地自由编排,使其无侵入,可复用于各种业务场景。这就是我们的设计方式。整体设计组件设计基于G6绘图引擎的能力,可以根据组件定义类型注册不同形状、颜色和结构的组件。组件由四部分组成:主体形状、支线、描述文字和节点。如图所示,节点也分为上部和下部。上层节点是其他组件连接到当前组件的节点,下层节点是当前组件可以连接到其他组件的节点。【外链图片传输失败,源站可能有防盗链接机制,建议保存图片直接上传(img-gYWZEE3O-1636024172026)(https://ata2-img.oss-cn-zhang...)]为了让用户更流畅、更规范地构建逻辑,我们在设计组件时将所有的约束都展现出来,并体现在用户的所有可执行动作中。比如我们在初始化一个组件的时候,开发者可以设置组件的几种输出情况和几个分支,每个组件可以连接到其他几个组件,每个分支代表结果导向,面向关联。所见即所得,不允许用户随意猜测或自定义连接。本次设计的目的是为了降低用户运营成本,降低解释成本,提升建设的标准化程度。组件类型根据组件是否包含逻辑,将组件分为两类:基础组件和业务组件。如上树图。基本元素没有任何业务逻辑,包括开始和结束元素,固定为一个逻辑的开始或结束,每个逻辑必须有一个开始元素和一个结束元素。基本部件设计为圆形和绿色;业务组件都有业务逻辑,只有一个输入节点。根据组件能够输出的结果数量,将业务组件更细粒度地划分为三种类型。(具体见下表)端业务元素,虽然有业务逻辑,但也可能是一个逻辑的端。比如跳转到新的页面逻辑,这个动作执行完之后,会跳转到一个新的地址,而当前页面上的当前逻辑不能传递到下一个动作,所以称为端业务元素,所以它被设计成只有一个输入节点,没有输出节点。因为它也标志着一个逻辑的结束,所以我也把它设计成一个圆圈,用黄色来区分。公共业务组件是通常具有输入并具有固定结果导向的组件。比如通过接口请求获取数据,返回数据输出会有固定的schema格式;因此,一个普通的业务组件有一个输入节点和一个输出节点,形状是矩形。判断业务组件比较复杂。根据组件设计规范,可以确定创建组件时存在多个结果输出。结果>1,返回的数据输出也会有固定的schema格式。比如判断用户是否登录,分为登录和未登录两种情况;判断业务元素的输出既不是1也不是0,可能有a,b,c,d...多个结果导向。因此,一个普通的业务元素有一个输入节点和N个输出节点,其形状设计为菱形。我们根据功能类型来定义和注册组件,并尽可能覆盖所有类型。目的是让这个逻辑编排方案具有通用性和可复用性,适用于多业务、多场景。注册组件有各种形状、颜色、分支和节点。平台端注册组件的思路:以判断业务组件为例,用SVG绘制菱形——组件主体的形状,根据组件类型自定义组件样式,基于组件的分支数量,动态绘制分支线的长度、节点位置、锚点信息等。G6.registerNode('diamond',{draw(cfg:Cfg,group:GGroup){constsize=[94,64];//转换为[width,height]模式constwidth=size[0];constheight=size[1];//svg自定义体形constpath=[['M',0,0-height/2],//上顶点['L',width/2,0],//右侧顶点['L',0,height/2],//BottomVertex['L',-width/2,0],//LeftVertex['Z'],//Closed];...},afterDraw(cfg:Cfg,group:GGroup){constsize=[100,64];constwidth=size[0];constheight=size[1];//分支描述信息addDesc(cfg,group,width,height,cfg.outLine);//分支线addLine(group,width,height,cfg.outLine);//连接锚点(小圆点)addNode(group,width,height,cfg.outLine,cfg.showNode);},...},'基本节点',);组件分支线也有不同的长度和方向,线的长度由分支的数量决定,即代码中的outline字段:constaddLine=(group,width,height,outLine)=>{group.addShape('path',{attrs:{path:[['M',-width/2*(outLine-1),height+3],['L',width/2*(outLine-1),height+3],['Z']],...edgeStyle},draggable:true,});}```组件的节点分为一个输入节点和一组输出节点。输出节点的位置仍然由轮廓决定constaddNode=(group,width,height,outLine,isShow)=>{//x坐标letxPosition=i=>{return-width/2*(outLine-1)+width*i;}outLine&&newArray(outLine).fill(0).forEach((d,i)=>{group.addShape('circle',{attrs:{x:xPosition(i),y:height+4,r:4.5,...dotStyle},name:`circle-shape-${i+1}`});})}`创建一个组件,用户需要根据到规范。初始化工程包含四个核心文件。以基本业务组件为例。如图所示,index.js是组件的主要功能逻辑文件,功能一般都有入参,并允许用户灵活配置。input.json文件定义为函数基本配置信息的标准Schema协议。内容可以在平台侧渲染为表单,供用户配置基本信息,在逻辑执行过程中作为payload参数传入相应的函数。对于基础业务组件,函数执行有固定的结果输出。然后branch.json,这个决定分支个数和分支信息的文件,数组长度为1,只能输入一项内容。output.json是main函数执行后最终return返回的数据对应的标准jsonschema协议信息。输出的数据是逻辑排列的产物,如图所示,可以在业务端绑定相应的字段,可视化展示相应的内容。不同的组件类型具有相同的项目结构。不同的是输出结果个数不同,主函数异步返回内容的结构不同。比如你勾选登录组件,它会返回登录和未登录两种情况,那么main函数会调用相应的api,判断返回的两种情况做出选择。如果返回信息branch为0,则表示该分支文件对应的数组第一项未登录;如果branch为1,则表示分支文件对应的数组第2项已登录,返回的数据也对应已登录的消息提示信息。Branch文件的数组长度是组件输出结果的个数,数组内容也是语义对应的。这就是组件整体结构的设计和对应的开发入口规范,开发者可以根据这样的规范新建对应类型的组件。我们还为开发者提供了输入输出文件的schema标准协议数据的【可视化构建表单设计器】,方便开发者快速构建相应的内容。基于Form-render的可视化构建我们的平台嵌入了基于Form-render的表单设计器,可以与自定义组件进行链接和快速访问,满足多种定制需求。考虑到form-render寻找合适的现有标准作为载体,在schema设计上适度扩展,经过长时间的积累,可以覆盖绝大部分的业务场景,所以我们的业务需求基本可以实现,也就是可以有扩展,所以选择模式形成方案。技术同学可以根据功能需求,通过可视化拖拽的方式构建配置表单;点击ExportSchema,导出标准的jsonschema协议信息,这是组件注册链接中InputSchema协议的基本配置信息来源,也是输出数据outputSchema标准协议InformationSources。构建组件市场逻辑排列的好处是逻辑与UI解耦,职责分工明确;开发者的职责是开发组件逻辑、发布组件、进入组件市场、状态管理、迭代版本管理。产品同学根据需求选择元器件市场中已有的元器件。如果没有对应的组件,他们会要求开发同学搭建逻辑,生产逻辑给业务方使用。逻辑排列构建逻辑就是将组件列表中的组件拖放到画布上,通过有向线将节点对应连接起来,然后将逻辑片段组合成一个完整的有头有尾的逻辑。(效果展示)通过技术手段,增加了构建智能对位、检查规范、自动纠错的能力。点击工具栏中的勾选按钮和保存按钮,将根据规则对不规范的施工行为进行提示和解释。比如组件基础配置表单中的某个字段不能为空;在用户搭建过程中,我们还设计了组件连接规则,解决不规范的搭建行为。自动纠错,例如组件不能在闭环中连接,不能重复连接等。我们构建一个编排器,让用户最大限度地自由编程和标准化,让用户在构建和发布逻辑时,已经是标准化可用的逻辑。当然,我们也解耦了设计编排器上的材质列表、画布、属性面板;每个功能面板都不会强依赖,有通用适配器,设置基本规格和可选使用,也有工具可以根据不同的业务场景定制。我们的初衷是注重逻辑构建,根据实际业务场景打造不同的产品形态。**业务落地UI&逻辑布局结合设计**我们第一个尝试落地的业务平台也是我们团队的活动搭建平台,与UI布局结合的一次尝试。UI布局概念:又称通用热区模组,是活动搭建平台推出的模组制作工具。提供简单易用、功能强大的操作界面,让操作设计类的同学可以像制作PPT一样制作模块。如图所示,UI布局完全可以实现静态页面的构建;用户可以任意创建热区模块,热区可以作为载体配置文本、样式、图片等基本信息,概念是用户主动点击触发的行为,比如跳转到页面、关闭页面、打开小程序等。这是纯粹的UI布局和构造。此事件的应用程序中的模块之一使用UI布局来尝试构建它。让我们来看看结合了UI布局和逻辑布局的整体设计。模块中的触发逻辑分为两种情况,一种是主动触发逻辑,即组件加载时开始自动执行的逻辑。一种是被动触发逻辑,需要用户点击触发逻辑的执行。在对应的功能配置区选择预建逻辑,将逻辑挂载到当前模块。如图所示,每段逻辑都有独立的上下文。逻辑执行完毕后,相应的数据产品会存储在上下文中,并共享给当前模块;模块将所有数据以key.value的格式扁平化,通过语义,将视图中的热度区域绑定到相应的字段;一旦逻辑执行过程中数据状态发生变化,就会驱动模块本地UI的动态渲染。如果模块的状态绑定了相应的字段,字段数据状态的变化也会带动模块整体UI的变化。平台端的实际操作,如下图右侧,在热区的action中选择“LogicArrangement”,在第二个逻辑排列平台中选择一个已经构建并导出的逻辑级下拉框。逻辑数据产品根据outputSchema协议可视化展示在业务平台端。对应的热区模块可以选择/绑定对应的字段内容。当逻辑真正执行时,数据驱动视图发生变化。前后对比——有什么优势?之前:产品需求提出后,前端开发人员需要依赖设计稿进行页面开发&逻辑开发。开发完成后,发布并进入模块到平台端,操作同学可以配置模块的基本信息。现在:了解需求后,前端和设计可以并行开始工作。前端同学开始开发模块需要依赖的逻辑组件。可以导入整体风格,然后操作同学配置基本信息,选择对应动作的匹配逻辑。这样做的好处是:在项目过程中,UI和逻辑的频繁变更不会过多依赖技术开发和技术发布,重开发拆分成多个角色,工作轻,迭代快;wewillsinkfrommodulereusetomoreadvancedSmall-grainedcomponentreuse将研发人员从“搬砖”工作中解放出来。经验证,传统源码开发从接到需求到上线评估需要2天左右,结合UI逻辑编排的方案仅需2小时。实现降本增效。而且最大的好处就是实现了逻辑和UI的解耦。UI设计稿变更时,前后流程对比:纯UI变更已经完全释放了开发资源,节省了源代码开发->代码发布->模块入/上架->操作升级模块流程,不仅节省了开发人力成本,也让学生不再依赖增/删/改配置信息来开发。逻辑变更虽然看似多了一个判断步骤,但如果有可复用的逻辑组件,产品可以直接拖拽更新逻辑;学生无需开发可重用组件。但从长远来看,我们已经从模块重用转向了更小粒度的组件重用。组件库在不断沉淀逻辑,以后组件复用率肯定会提高。从开发的角度,我们也打算从本地组件开发升级到线上开发,组件一键发布上架。让流程编排效率进一步提升。结构图该结构图展示了逻辑布局与业务平台端的整体上下游关系。逻辑布局分为三部分:orchestrator、DSL、Runtime。画布构造使用了形式和功能上的四种类型的组件;组件由开发者开发,可以在组件管理页面进行管理。画布包括工具栏功能,例如缩放和撤消。在用户构建过程中,我们通过技术手段提供智能对齐、检查规范、自动纠错、在线测试等能力,让用户构建逻辑更顺畅、更规范。DSL转换器将canvas的所有信息转换成json,提供给业务方。业务平台侧(活动搭建平台)的逻辑起点是主动触发逻辑&被动触发逻辑。一旦逻辑被触发,Runtime提供的api注册组件,并开始执行,每个组件执行对应的数据产品将通过上下文共享给业务。一旦绑定字段对应的数据状态发生变化,就会引起局部UI变化,模块整体状态发生切换。动作执行完后,流程进入下一个动作,依此类推,直到逻辑结束。这就是逻辑和UI结合的总体/核心思想。逻辑排列产生数据,UI排列监听数据变化,驱动尝试变化。综上所述,逻辑编排在以下三个方面取得了突破:可重用逻辑:避免研发同学重复代码开发,节省人力成本,降本增效,降低需求变更成本;更清晰的分工:实现UI与Logical的解耦,技术在开发过程中只开发逻辑,将繁重的开发工作拆分为多角色轻工作协作。并且产品在构建逻辑的同时,还将需求可视化,便于他人理解;业务复用性:通过组件、画布、DSL、Rumtime的通用化、灵活性和可扩展性设计,适用于多种业务场景。我们的计划是注重逻辑构建,根据实际业务场景打造不同的产品形态,希望服务更多的平台。
