





Oinone社区 作者:史, 昂原创文章,如若转载,请注明出处:https://doc.oinone.top/oio4/9201.html
访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验






Oinone社区 作者:史, 昂原创文章,如若转载,请注明出处:https://doc.oinone.top/oio4/9201.html
访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验
异步任务是非常常见的一种开发模式,它在分布式的开发模式中有很多应用场景如: 高并发场景中,我们一般采用把长流程切短,用异步方式去掉可以异步的非关键功能,缩小主流程响应时间,提升用户体验 异构系统的集成调用,通过异步任务完成解耦与自动重试 分布式系统最终一致性的可选方案 今天我们了解oinone是如何结合Spring+TbSchedule来完成异步任务 一、TbSchedule介绍 它是一个支持分布式的调度框架,让批量任务或者不断变化的任务能够被动态的分配到多个主机的JVM中,在不同的线程组中并行执行,所有的任务能够被不重复,不遗漏的快速处理。基于ZooKeeper的纯Java实现,由Alibaba开源。在互联网和电商领域TBSchedule的使用非常广泛,目前被应用于阿里巴巴、淘宝、支付宝、京东、聚美、汽车之家、国美等很多互联网企业的流程调度系统。也是笔者早期在阿里参与设计的一款产品。 oinone的异步任务执行原理(如下图4-1-11-1所示),先做一个大致了解: 图4-1-11-1 Oinone的异步任务执行原理图 基础管理工具 下载tbSchedule的控制台jar包去除文件后缀.txt(详见本书籍【附件一】)pamirs-middleware-schedule-console-3.0.1.jar.txt(31.2 MB) 启动控制台 java -jar pamirs-middleware-schedule-console-3.0.1.jar 图4-1-11-2 控制台启动方式 访问地址 http://127.0.0.1:10014/schedule/index.jsp?manager=true 图4-1-11-3 访问地址 配置zk连接参数 图4-1-11-4 配置zk连接参数 oinone默认实现任务类型 图4-1-11-5 Oinone默认实现任务类型 baseScheduleNoTransactionTask baseScheduleTask remoteScheduleTask — 适用于pamirs-middleware-schedule独立部署场景 serialBaseScheduleNoTransactionTask serialBaseScheduleTask serialRemoteScheduleTask — 适用于pamirs-middleware-schedule独立部署场景 cycleScheduleNoTransactionTask delayMsgTransferScheduleTask deleteTransferScheduleTask 注: a. 默认情况下:所有任务的任务项都只配置了一个任务项0,只有一台机器能分配任务。 1. 如果要修改配置可以在启动项目中放置schedule.json,来修改配置 2. 人工进入控制修改任务对应任务项的配置 b. 如果想为某一个核心任务配置的独立调度器,不受其他任务执行影响。那么见独立调度的异步任务 任务表相关说明 图4-1-11-6 任务表相关说明 二、构建第一个异步任务(举例) Step1 新建PetShopService和PetShopServiceImpl 1 新建PetShopService定义updatePetShops方法 package pro.shushi.pamirs.demo.api.service; import pro.shushi.pamirs.demo.api.model.PetShop; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import java.util.List; @Fun(PetShopService.FUN_NAMESPACE) public interface PetShopService { String FUN_NAMESPACE = "demo.PetShop.PetShopService"; @Function void updatePetShops(List<PetShop> petShops); } 图4-1-11-7 新建PetShopService定义updatePetShops方法 PetShopServiceImpl实现PetShopService接口并在updatePetShops增加@XAsync注解 displayName = "异步批量更新宠物商店",定义异步任务展示名称 limitRetryNumber = 3,定义任务失败重试次数,,默认:-1不断重试 nextRetryTimeValue = 60,定义任务失败重试的时间数,默认:3 nextRetryTimeUnit,定义任务失败重试的时间单位,默认:TimeUnitEnum.SECOND delayTime,定义任务延迟执行的时间数,默认:0 delayTimeUnit,定义任务延迟执行的时间单位,默认:TimeUnitEnum.SECOND package pro.shushi.pamirs.demo.core.service; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.PetShop; import pro.shushi.pamirs.demo.api.service.PetShopService; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.trigger.annotation.XAsync; import java.util.List; @Fun(PetShopService.FUN_NAMESPACE) @Component public class PetShopServiceImpl implements PetShopService { @Override @Function @XAsync(displayName = "异步批量更新宠物商店",limitRetryNumber = 3,nextRetryTimeValue = 60) public void updatePetShops(List<PetShop> petShops) { new PetShop().updateBatch(petShops); } } 图4-1-11-8 实现PetShopService接口并在updatePetShops增加@XAsync注解 Step2 修改PetShopBatchUpdateAction的conform方法 引入PetShopService 修改conform方法 利用ArgUtils进行参数转化,ArgUtils会经常用到。 调用petShopService.updatePetShops方法 package pro.shushi.pamirs.demo.core.action; …… 引依赖类 @Model.model(PetShopBatchUpdate.MODEL_MODEL) @Component public class PetShopBatchUpdateAction { @Autowired private PetShopService petShopService; ……其他代码 @Action(displayName = "确定",bindingType = ViewTypeEnum.FORM,contextType = ActionContextTypeEnum.SINGLE) public PetShopBatchUpdate conform(PetShopBatchUpdate data){ if(data.getPetShopList() == null || data.getPetShopList().size()==0){ throw…
模块(module) 概念 在 Oinone 系统的架构中,模块(module)是核心组成元素之一,可以被理解为域(domain)的一个具象化概念。模块的来源有两种:一种是基于后端代码定义,另一种是通过无代码新增。具体的代码定义方式,请参考“[占位符]”,而无代码定义的相关信息则可在“[占位符]”找到。在 Oinone 体系中,模块对应两种实体:模块和应用。 模块: 这是一类特定能力的集合,它可以依赖其他模块,也可以被其他模块依赖。 应用: 它是一种特殊的模块,具备模块的所有特性,并在此基础上可被终端用户访问。 使用 在前端开发中,module通常以应用的形式出现,它们往往对前端用户保持透明。在接下来的讨论中,我们主要围绕应用来探讨module的使用。从应用的角度出发,我们可以在前端开发中识别出以下几种典型使用场景,并通过具体的业务案例来加以说明 应用菜单扩展: 实现自定义母版来定义特定应用的菜单 表格布局扩展: 用于自定义布局的工具,以定义特定应用的表格布局 在这些场景中,我们着重实现了应用层面的隔离,确保每个模块都能在应用的维度上独立运作 查找 在实际业务开发中,有3个方式可以找到应用 浏览器url查找(查找速度快,可能不准) 图3-5-7-1 浏览器url查找模块(module) 接口返回查找 第一步找到截图类似请求 图3-5-7-2 接口找到viewActionQuery 第二步根据返回找应用 图3-5-7-3 接口返回查找模块(module) vue调试器选中对应的组件查找 图3-5-7-4 vue调试器查找模块(module) 推荐使用浏览器url查找,若与预期不符,可用另外两种方式查找 模型(model) 概念 在 Oinone 系统的架构中,模型(model)是另一个关键核心组成部分。模型在业务层面主要体现之一为数据库的实体表,它是承载业务实现的基础结构。要了解模型的详细介绍,请参考“[占位符]”,前端所用的模型,对应后端代码定义来说,代表的是模型的编码。 关于模型的定义,我们提供了两种方法: 代码定义: 对于需要通过编程实现的模型定义,您可以参考“[占位符]”来了解具体的代码实现方法; 无代码定义:如果您倾向于使用无代码工具来定义模型,具体的操作和流程可以在“[占位符]”中找到 使用 在前端开发中,模型是前端运行的必要条件,以下场景中,模型不直接感知: 视图渲染 页面之间跳转交互 与后端交互 以下场景中,模型会直接决定前端的渲染逻辑 母版扩展:为某模型扩展母版 布局扩展:为某模型扩展布局 页面扩展:为某模型扩展个性化页面 字段扩展: 扩展字段时加上模型的范围 动作扩展: 扩展动作时加上模型的范围 以上场景中,涵盖了前端工作的方方面面,在OInone体系中,模型不止是后端运行得基础,同样也决定了前端如何运行,那这样做有什么好处呢? 前后端几乎不需要联调,联调的协议用模型来承载 前端无需定义路由、权限埋点 查找 在实际业务开发中,有3个方式可以找到模型 浏览器url查找 图3-5-7-5 浏览器url查找模型(model) 接口返回查找 第一步找到类似截图请求 图3-5-7-6 接口找到viewActionQuery 第二步根据返回找模型 图3-5-7-7 接口找到viewActionQuery vue调试器选中对应的组件查找 图3-5-7-8 vue调试器查找模型(model) 动作(action) 概念 动作(action)定义了终端用户得交互,它描述了前端与前端、前端与后端之间的交互。 动作涵盖了前端以下部分: 页面跳转(router) 调用后端接口 页内交互(打开弹窗、打开抽屉) 它有两部分的来源: 模型内定义动作 窗口动作(页面跳转、打开弹窗、打开抽屉) 服务器动作(调接口) 前端定义客户端动作,可自定义其它逻辑,例如: 把选中行的某一列数据复制一下 使用 动作的使用绝大部分的情况是由平台自动执行的,在平台执行不符合预期时可以使用自定义动作自行扩展 查找 vue调试器选中对应的组件查找 选中服务器动作(ServerAction) 图3-5-7-9 vue调试器查找服务器动作(ServerAction) 选中窗口动作(ViewAction) 图3-5-7-10 vue调试器查找窗口动作(ViewAction) 字段(field) 概念 在我们的后端模型中,字段(Field)是核心的定义元素,它们在数据库中表现为数据表的列。更重要的是,这些字段在前端应用中发挥着数据传输的关键作用。例如,当前端需要调用后端接口时,它会发送如下结构的数据: 图3-5-7-11 name字段数据举例 这里的 "name" 是一个字段实例,它连接了前后端的交互。在后端,该字段不仅用于数据存储,也参与逻辑运算。 字段在 Oinone 系统中的加强应用 在 Oinone 系统中,字段的功能得到了扩展。除了基本的前后端数据交互,字段的定义还直接影响前端的用户界面(UI)交互。例如: 前端交互组件的选择:前端交互组件的类型取决于字段的数据类型。对于 String 类型的 "name" 字段,前端会使用输入框来收集用户输入的 "张三"。 数据存储和类型定义:在后端,"name" 字段被明确定义为 String 类型,这决定了它如何存储和处理数据。 字段与前端组件定义的解耦 一个关键的设计原则是,前端组件的定义与具体的字段值或字段名(如 "name" 或 "张三")不直接相关,而是基于字段的数据类型(此例中为 String)。这种设计实现了: 前端组件的一致性:确保所有组件的输入输出遵循同一数据类型(如 String)。 高度的组件复用性:在满足 UI 要求的前提下,任何 String 类型的字段都可以使用这种通用的组件设计。 使用 Oinone 系统中的视图与字段交互的灵活性 Oinone 系统为每种视图和字段类型(Ttype)提供了默认的交互模式。这不仅保证了前端工程启动时所有界面的即时展示,也为开发者带来了高度的灵活性和扩展能力。以下是这一设计理念的关键点: 1. 视图与字段交互的默认实现 每种视图都有对应字段类型(Ttype)的默认交互实现,确保用户界面一致且直观。这使得在前端工程启动时,所有界面能够无需额外配置即可正常展示。 2. 灵活性与扩展能力 尽管系统提供了默认的交互方式,开发者仍然拥有自定义这些交互方式的能力。这意味着开发者可以根据应用需求,设计更加贴合业务逻辑和用户体验的交互模式。 3. 覆盖和替换默认组件 最为重要的是,开发者不仅可以添加新的交互方式,还可以完全覆盖和替换系统的默认组件。这提供了极大的自由度,使开发者能够根据具体场景重新设计和实现界面组件,从而达到完全定制化的用户体验。 查找 vue调试器选中对应的组件查找 图3-5-7-12 vue调试器查找字段(field) 视图类型(viewType) 概念 在 Oinone 系统中,视图是模型在前端的具体表现形式。视图的核心组成和功能如下: 1. 组成要素 字段:视图中的字段代表了模型的数据结构,它们是界面上数据显示和交互的基础。 动作:视图包含的动作定义了用户可以进行的操作,如添加、编辑、删除等。 前端UI:视图的界面设计,包括布局、元素样式等,决定了用户的交互体验。 2. 数据源与交互 数据源:视图的数据直接来源于后端模型。这意味着前端视图展示的内容是根据后端模型中定义的数据结构动态生成的。 交互:视图不仅展示数据,还提供与数据交互的能力。这些交互也是基于后端模型定义的,包括数据的增删改查等操作。 3. 灵活性 视图可以灵活选择是否采用模型的交互。这意味着开发者可以根据需求决定视图仅展示模型的数据,或者同时提供与数据的交互功能。 使用 在 Oinone 系统中,用户可以通过无代码界面设计器轻松配置视图。系统内置了以下主要视图类型: 表格(Table) 表单(Form) 详情(Detail) 搜索(Search) 画廊(Gallery) 树(Tree) 界面设计器配置…
数据管理器和数据构造器是Oinone为模型自动赋予的Function是内在数据管理能力,数据管理器针对存储模型是方便在大家编程模式下可以利用数据管理器Function快速达到相关数据操作的目的。数据构造器则主要用于模型进行初始化时字段默认值计算和页面交互 数据管理器 只有存储模型才有数据管理器。如果@Model.Advanced注解设置了dataManager属性为false,则表示在UI层不开放默认数据管理器。开放级别为API则表示UI层可以通过HTTP请求利用4.1.15【Pamirs标准网关协议】进行数据交互。 模型默认数据读管理器 函数编码 描述 开放级别 queryByPk 根据主键查询单条记录,会进行主键值检查 Local、Remote queryByEntity 根据实体查询单条记录 Local、Remote、Api queryByWrapper 根据查询类查询单条记录 Local、Remote queryListByEntity 根据实体查询返回记录列表 Local、Remote queryListByWrapper 根据查询类查询记录列表 Local、Remote queryListByPage 根据实体分页查询返回记录列表 Local、Remote queryListByPageAndWrapper 根据查询类分页查询记录列表 Local、Remote queryPage 分页查询返回分页对象,分页对象中包含记录列表 Local、Remote、Api countByEntity 按实体条件获取记录数量 Local、Remote countByWrapper 按查询类条件获取记录数量 Local、Remote 表3-3-3-1 模型默认数据读管理器 模型默认数据写管理器 函数编码 描述 开放级别 createOne 提交新增单条记录 Local、Remote createOrUpdate 新增或更新,需要为模型设置唯一索引,如果数据库检测到索引冲突,会更新数据,若未冲突则新增数据 Local、Remote updateByPk 根据主键更新单条记录,会进行主键值检查 Local、Remote updateByUniqueField 条件更新,条件中必须包含唯一索引字段 Local、Remote updateByEntity 按实体条件更新记录 Local、Remote、Api updateByWrapper 按查询类条件更新记录 Local、Remote createBatch 批量新增记录 Local、Remote createOrUpdateBatch 批量新增或更新记录 Local、Remote updateBatch 根据主键批量更新记录,会进行主键值检查 Local、Remote deleteByPk 根据主键删除单条记录,会进行主键值检查 Local、Remote deleteByPks 根据主键批量删除,会进行主键值检查 Local、Remote deleteByUniqueField 按条件删除记录,条件中必须包含唯一索引字段 Local、Remote deleteByEntity 根据实体条件删除 Local、Remote、Api deleteByWrapper 根据查询类条件删除 Local、Remote createWithField 新增实体记录并更新实体字段记录 Local、Remote、Api updateWithField 更新实体记录并更新实体字段记录 Local、Remote、Api deleteWithFieldBatch 批量删除实体记录并删除关联关系 Local、Remote、Api 表3-3-3-2 模型默认数据写管理器 如果模型继承IdModel,模型会自动设置主键设置为id,则会继承queryById、updateById和deleteById函数。 queryById(详情,根据ID查询单条记录,开放级别为Remote) updateById(提交更新单条记录,根据ID更新单条记录,开放级别为Remote) deleteById(提交删除单条记录,根据ID删除单条记录,开放级别为Remote) 如果模型继承CodeModel,模型也会继承IdModel的数据管理器,编码字段code为唯一索引字段。在新增数据时会根据编码生成规则自动设置编码字段code的值,继承queryByCode、updateByCode和deleteByCode函数。 queryByCode(详情,根据code查询单条记录,开放级别为Remote) updateByCode(提交更新单条记录,根据code更新单条记录,开放级别为Remote) deleteByCode(提交删除单条记录,根据code删除单条记录,开放级别为Remote) 没有主键或唯一索引的模型,在UI层不会开放默认数据写管理器。 #### 使用场景 图3-3-3-1 数据管理器使用场景 数据构造器 模型数据构造器 construct:供前端新开页面构造默认数据使用。所有模型都拥有construct构造器,默认会将字段上配置的默认值返回给前端,另外可以在子类中覆盖construct方法。数据构造器 construct函数的开放级别为API,函数类型为QUERY查询函数,系统将识别模型中的以construct命名的函数强制设置为API开放级别和QUERY查询类型。 可以使用@Field的defaultValue属性配置字段的默认值。注意,枚举的默认值为枚举的name。
我在个人的微信公众号上《浅谈企业IT架构的十年困局》一文中写了“企业或者软件公司在工程领域都关注哪些特征,而这些特征又应与具体研发人员的个体能力无关”的相关内容。收到很多业内人士的留言,也引起了很多同行的共鸣,所以今天在这里也打算针对这个话题,跟大家再做个深入的探讨。 一、首先为什么强调要跟研发个体能力无关 我们先来看一个故事: 轮扁是春秋时期齐国的木工,齐桓公召其入宫打造物件。有一天,齐桓公在堂上看书,轮扁在堂下用椎、凿等工具做车轮。 齐桓公看书看到得意处,不由得读出声来。轮扁听到读书声,想了想,放下手里的工具,走上堂来,在齐桓公面前几步远的地方停下,恭恭敬敬地说:“请恕臣斗胆问一下,君王读的是什么书?”齐桓公没想到这个老木匠会走上堂来,倒有点意外。不过看在他年纪大的份上,倒也不去斥责他,就回答说:“寡人读的是圣人写的书。”轮扁问:“圣人还在吗?”齐桓公说:“已经死了。”轮扁说:“这样看起来,君王所读的,不过是古人的糟粕而已!”齐桓公勃然大怒,说:“寡人读书,你一个做车轮的怎么敢议论?你说,这书上怎么会是古人的糟粕?说出道理便罢,说不出道理便难逃一死!” 轮扁不慌不忙地说:“臣是根据臣所从事的活计而明白这个道理的。砍削轮子,榫头做得宽了则松滑而不牢固,做得太紧就必然涩滞而安不进去,臣制作的榫头松紧适宜,是因为心里怎样想的手便怎样去做。然而尽管所需要的分寸度数心里都明白,要把它用言辞表达出来却实在不可能,全靠自己手与心的配合。所以,臣无法将其中的奥秘传授给儿子,臣的儿子也无法从臣这里学到其中的奥秘。因此,臣如今七十多岁了,还只好亲手去干制作轮子的活。这样看来,古人之道的精华都已随着古人死去而无法传世,那么君王所读的,不就是古人的糟粕了吗?” 这就是著名的成语故事——轮扁斫轮,出自《庄子·天道》。庄子通过轮扁的言论,深刻地揭示了高妙之技的难以言传。 而当我们转换视角,在企业数字化转型领域,无论是软件公司还是甲方IT团队,核心上是应用级开发需求,更多的精力应该放在业务场景理解、需求把控以及业务系统实现上。但往往在一个项目进入研发之前,会花很大力气在技术架构设计、技术栈选型、通用能力对接、扩展点设计这些跟业务场景无关的技术事项上,且需要高级别的架构师来主导。大部分情况下,架构师会选开源框架来实现,慢慢沉淀为企业的研发标准体系,所以底层架构的能力往往依赖架构师个人能力。不禁发现他们与轮扁有着异曲同工之处。架构师所积累的个人经验和技术能力,往往难以通过简单的手把手教学、技术评审会完全传递给团队中的其他成员。即使有所传授,其效率也可能仅达到50%,并且随着团队成员数量的增加,这种效率还可能持续递减。因此,我们需要更多地依赖于技术手段,将架构师的经验和能力固化下来,形成一套可复制、可推广的标准技术产品。这样,每个团队成员都能够通过学习和运用这些技术,达到至少70%的传递效率,从而确保团队整体技术水平的稳步提升。这也正是开篇所强调的,企业或软件公司在工程领域所关注的特征,应当与具体研发人员的个体能力相剥离,而更多地依赖于标准化、系统化的技术手段,来确保团队整体的高效运作。 二、软件公司在工程化领域都关注哪些特征 接下来,我将从技术角度深入剖析设计初衷和技术实现原理,以展现技术公司应当“被标准化的特征”究竟长什么样。 先做个名称解释,下文中涉及“标品”、“升级”、“扩展逻辑”,这是站在软件公司角度出发描述的,如果是企业内部可以把标品理解为特定业务应用平台,升级则是业务应用平台的正常规划迭代,扩展逻辑理解为脱离平台发展的临时性需求。 1. 可逆计算 可逆计算,在应用上的特征图 场景:调查发现企业研发至少有40%的精力在跟各条业务线的团队在评审项目需求,判断需求是否合理。而且业务线对需求完善时间要求紧,每天盯着研发进度,经常问“这个需求什么时候支持,我们等着用”。导致产研部门的研发抱怨产品节奏乱,无法按照自身节奏进行迭代,被项目推着走,没有时间思考,人手不足,加班多,工作压力大…… 价值:该特性很好的规避了研发因为时间紧迫,写的一些临时代码腐蚀核心业务系统。它需要做到不论从数据模型、业务逻辑、交互展示都能有扩展能力,并且这些扩展能力与个体研发无关才行。它同时所描述的也是一个具备差量计算能力的软件架构模式,它允许用户通过添加或移除扩展包来定制标准应用,同时保持应用的可逆性和独立性。这种架构模式的核心优势在于其灵活性和可维护性,使得应用的定制和恢复变得简单而高效。 技术原理:它所描述的是一个基于元数据驱动和差量计算的软件架构模式,它允许用户通过添加或移除扩展包来定制标准应用,同时保持应用的可逆性和独立性。这种架构模式的核心优势在于其灵活性和可维护性,通过元数据来驱动应用的构建和变更,使得应用的定制和恢复变得简单而高效 在这种架构中,元数据起到了至关重要的作用。元数据是关于数据的数据,它描述了数据的结构、属性、关系等信息。在软件应用中,元数据可以用来描述应用的组件、功能、配置等信息。通过元数据驱动应用可以根据元数据的描述来动态地构建和配置自身的功能和结构 差量计算则是实现应用可逆性的关键。当添加或移除扩展包时,系统会根据扩展包中的元数据与标准应用的元数据进行差量计算,确定需要添加或移除的功能和组件。这种差量计算可以确保在添加扩展包后,应用能够保持原有的功能和稳定性,同时新增扩展包带来的新功能,而在去除扩展包时,应用能够恢复到原始的标准状态,不会留下任何冗余或冲突的代码和配置。 为了实现这种架构模式,元数据注册表和分布式部署能力是非常重要的。元数据注册表需要能够存储和管理大量的元数据信息,并且提供高效的查询和更新机制。分布式部署能力则能够确保应用在不同的环境中都能够稳定运行,并且能够快速地响应扩展包的添加和移除操作,即差量(扩展包》可独立存在又相互作用。 总的来说,这种基于元数据驱动和差量计算的软件架构模式为应用的定制和恢复提供了强大的支持,使得应用能够根据不同的需求进行灵活的定制和扩展。同时,它也提高了应用的可维护性和可靠性,降低了开发和维护的成本 2. 协同演进 协同演进,在应用上的特征图 场景:它所描述的场景是一个复杂的软件升级过程,其中涉及了标准应用的升级以及用户个性化扩展的保留。通过面向对象的方式扩展标准应用的功能,可以在升级过程中保持用户自定义逻辑的完整性,并同时集成新版本中的新特性。 价值:很多号称产品型的软件公司,在交付客户项目的时候,都是从标品复制一个分支,然后客户个性化直接在这个分支上改。这种模式会带来两个问题: 是当客户数量变大,每个客户的版本都不一致,维护成本很高; 是当标品升级带来的新特性无法复制给客户,导致客户满意度下降甚至流失。协同演进就是要解决这个问题。 技术原理:它需要在第一个差量计算的特性基础上才能得以完成,同时在这种升级能力中,元数据驱动和模型驱动是关键所在。元数据驱动确保了应用能够理解和处理不同版本之间的变化,包括功能的增删改以及结构的调整。模型驱动则提供了描述和管理应用结构、组件和行为的能力,它不仅能够描述模型间的关系,还能够支持面向对象的特性,如继承、重写和重载等。 具体来说,当标准应用从V1升级到V2时,元数据驱动机制会首先识别和分析两个版本之间的差异。对于用户应用1中已经扩展的A功能,由于采用了面向对象的方式进行扩展,因此在升级过程中,A+逻辑作为A功能的重写或重载版本会被保留下来。同时,V2版本中新增的B功能也会被集成到用户应用1中,因为它是作为标准应用的新特性而存在的。 这种升级能力的实现依赖于一个强大的元数据注册表和模型管理能力。元数据注册表需要能够存储和管理不同版本应用的元数据信息,包括功能、组件、结构等。模型管理能力则需要能够解析和应用这些元数据,以生成正确的应用结构和行为。同时,还需要一套高效的升级机制来确保升级过程的平滑和可靠。 总的来说,通过元数据驱动和模型驱动的结合,可以实现标准应用的平滑升级,同时保留用户个性化扩展的完整性。这种能力对于提高软件的可维护性、可扩展性和用户满意度具有重要意义 3. 公民研发和专业研发共同参与 专业研发与公民研发共同参与,在应用上的特征图 场景:它所描述是在应用开发的整个生命周期中,专业研发专注在标品的长期规划与迭代,当出现临时性的需求或者应急性的辅助场景则由非专业人士进行即公民研发方式进行。这种模式下,专业研发可以按照规划有节奏的迭代产品,做更高级的事情,不至于忙于应对临时性的事务没有深度思考,更加避免了因为临时代码堆积导致产品从内部腐化。同时利用独立的扩展逻辑包和无代码方式解决了业务的紧迫感,毕竟业务需求的合理性是很难争论出高低的。它在前两个特性基础上让研发效能进一步得到释放。 价值:它的本质是,在专业研发在以低代码的方式下实现应用,并通过无代码的方式,快速扩展逻辑功能和创建辅助性应用。整个过程无缝衔接,我们给他取个名字专业名称叫:“低无一体”。它大大降低了技术门槛,使得专业和非专业的研发人员都能参与到应用扩展和定制中来。此外,它还提高了业务响应能力,使得企业能够更快速地适应市场变化和客户需求。 技术原理:它的核心要求就是元数据在线,元数据在线能力是指能够实时地、在线地管理和操作元数据,这种能力为企业或组织带来了诸多优势。通过无 代码的方式,用户可以更加灵活地进行应用的个性化扩展,以应对各种应急性需求,从而显著提升业务的响应能力。此外,元数据在线管理还确保核心应用、核心应用扩展以及辅助应用都是基于一套统一的技术体系构建的,这为不同角色的用户(包括专业和非专业的研发人员)提供了多样化的参与方式。同时,元数据在线管理需要符合开闭原则,这确保了系统的稳定性和可扩展性,使得新的功能或需求可以通过添加新的元数据或配置来实现,而非修改现有系统。 这种低代码开发与无代码一体化的优势在于,它大大降低了技术门槛,使得专业和非专业的研发人员都能参与到应用扩展和定制中来。此外,它还提高了业务响应能力,使得企业能够更快速地适应市场变化和客户需求。 总之,从用户应用到业务实施的过程通过元数据在线得到了优化和升级。低代码开发与无代码一体化的优势使得整个过程更加高效、灵活和易于维护,为企业带来了显著的价值和竞争优势。 4. 基于平台级别的AOP能力出现反向集成 反向集成,在应用上的特征图 场景:平台级别的AOP(面向切面编程)能力允许开发者在应用程序的特定点“切入”额外的逻辑,而无需修改原有的业务代码。这种能力特别适用于横向追加平台逻辑,即在多个不同服务或功能点插入通用的处理逻辑,如日志记录、权限检查、审计、多租户、多语言等。过往在微服务架构中,这些能力都需要业务系统各自主动去对接,有了平台级别的AOP能力,则这些通用能力可以反向为所有业务系统增加特性能力,无需业务系统研发感知。这种现象我们称之为“反向集成”,能让业务研发更加专注在业务研发本身,不需要关心与业务无关的通用功能上。 价值:AOP的核心思想是将这些横切关注点(cross-cutting concerns)从业务逻辑中分离出来,使得业务代码更加清晰和专注于其核心功能。在平台级别的AOP中,标准化协议是实现这一能力的关键。平台具备统一的入口和扩展能力是非常重要的,因为它允许开发者在不修改现有代码的情况下添加新功能或修改现有功能的行为。这种能力对于快速响应业务需求变化、减少维护成本和提高代码质量都是非常有益的。 技术原理:标准化协议确保了不同组件之间的通信与语义是统一的,从而使得AOP能够更容易地实施。例如: a前后端通信要标准协议(与端无关): 这意味着无论前端是使用Web、移动应用还是其他类型的客户端,后端服务都应该能够以一种标准的方式与之通信。 bORM层要有标准协议(与数据库无关): 对象关系映射 (ORM)层应该提供一个标准的接口来与数据库进行交互,这样无论底层使用哪种数据库(如MySQL、PostgreSQL、Oracle等),上层的业务逻辑都不需要改变。 cRPC需要标准协议(与Dubbo和Spring Cloud无关): 远程过程调用 (RPC)应该遵循一种标准协议,以便不同的服务可以无缝地进行通信,而不受特定框架 (如Dubbo、Spring Cloud等)的限制。 d所有逻辑调用统一fun调用: 这意味着平台上的所有功能调用都应该通过一个统一的入口点(如一个函数或方法)进行,这样AOP就可以在这个入口点切入额外的逻辑。 总的来说,平台级别的AOP能力通过标准化协议和统一的调用入口,为开发者提供了一种强大而灵活的方式来管理和扩展平台的逻辑功能。 5. 应用研发与部署无关 应用研发与部署无关,在应用上的特征图 场景:现在研发在选择部署方式的时候往往会选择分布式部署,或者你的客户招标需求里就写着“微服务”,构建一个微服务系统并不是一件容易的事,构建的复杂度远远超过单体系统,开发人员需要付出一定的学习成本去掌握更多的架构知识和框架知识。服务与服务之间通过HTTP协议或者消息传递机制通信,开发者需要选出最佳的通信机制,并解决网络服务较差时带来的风险。另外服务与服务之间相互依赖,如果修改某一个服务,会对另一个服务产生影响,如果掌控不好。会产生不必要的麻烦。由于服务的依赖性,测试也会变得很复杂,比如修改一个比较基础的服务,可能需要重启所有的服务才能完成测试。前段时间有篇很火的文章,《从微服务转为单体架构、成本降低 90%!》,无论是选择何种部署方式,我认为这都应该跟应用研发无关。 价值:应用研发与部署无关的理念确实为现代软件架构带来了显著的优势,它使得研发团队能够专注于业务逻辑和功能实现,而无需担心具体的部署细节。这种分离带来了灵活性、效率以及成本效益的多重提升。应该采用一种同时支持分布式和单体部署、且可以自由切换的架构,我们称之为可分可合。 首先,可分可合的能力使得系统能够灵活应对业务量的变化。在业务量小的时候,可以采用单体部署的方式,简化部署流程,降低初期成本。随着业务量的增长,系统可以平滑地过渡到分布式部署,通过拆分微服务来提高系统的处理能力和扩展性。这种灵活性确保了系统既能满足未来发展的需要,又能兼顾当下的成本效益。 其次,应用级别扩容的能力使得系统性能不再受限。通过增加微服务实例或调整资源配置,系统可以按需进行扩容,从而确保在业务高峰期或突发流量下仍能保持稳定的性能。这种按需扩容的方式不仅提高了系统的可靠性,还降低了运维成本。 技术原理:核心在于逻辑调用的统一执行和智能判断。通过如funEngine这一统一调用引擎,系统能够智能地选择最适合当前业务场景和性能需求的fun调用方式。无论是同步调用、异步调用还是基于消息队列的调用方式,funEngine都能进行智能决策,确保调用的高效性和可靠性。这种统一调用的方式简化了开发过程,降低了开发难度,同时也提高了系统的可维护性和可扩展性。 此外如果作为低代码或者其他研发平台来说。被集成特性也是实现该特性的关键所在。它提供了一套标准化的接口和协议,使得其他系统或应用能够轻松地与其进行集成。这种平台框架化的特性能够作为一个统一的、可扩展的框架来支撑整个系统的运行。 综上所述,具备可分可合的能力、应用级别扩容以及逻辑调用的统一执行和被集成特性,共同构成了应用研发与部署无关这一核心特性。该特性使得软件系统能够灵活地应对业务变化,实现高效、可扩展和可维护的运行,从而满足客户的长期发展需求并兼顾当下的成本效益。