利用模板化应对ERP业务模型的快速变化

源宝导读:ERP这类复杂系统中,业务模型是系统功能的核心抽象,但业务模型对于不同的客户会有差异,也会随着业务发展而变化。虽然可以对业务组件进行复用,但客户定制的成本依然较高,本文将讨论如何利用模板化应对业务模型的差异与变化。

一、背景

来自用户的反馈:

  • A区域顾问:“客户的合同变更业务只有申报和指令两个阶段,并没有确认阶段,能否不用二开配置下就能用?”。

  • B区域顾问:“客户的合同变更有自己的操作习惯,产品标准体验不符合他们习惯,能否单独提供一个符合我们区域的交互模板?”。

  • C区域顾问:“客户有三类合同变更,但产品只有两类合同变更,能否不用二开,快速复制一套变更业务,简单调整下配置就能交付?”。

  • D区域顾问:“客户在合同变更业务上有多类应用,标准产品的变更业务太固化,能否提供一个途径让我们自己根据客户需求打包个性化的变更业务解决方案,并分享给其它顾问或区域实现快速交付?”。

二、如何应对多变业务

    低成本、快交付是软件产品交付领域一直非常看重的目标,其直接影响了产品最终利润率。那么对于前面场景所展现的业务多变性,我们如何破局?

    系统模型往往是业务模型的落地表现,在一个相对固定的业务场景下,功能是稳定的,需求是可预测的,那么对于系统设计来说,难度是相对较低的,在这个相对稳定的模型下,局部的调整与功能扩展点能够很明确的提取出来。这也是ERP、SAAS系统设计和进化的基础。一旦业务模型变得多变而缺乏预测性,那么对于系统来说,其设计的难度将成倍增长,如为应对单据与流程的多样化,单据模型配置将变得非常复杂。而对于明源云来说,同样将此类问题交由建模平台进行。

    近年来,“低代码”已经是一个非常高频的词汇,其核心是在探索用少量代码甚至无代码方式构建符合客户预期的业务系统,包括明源云在内,推出了基于各种形式的低代码平台。为了适配业务的多样性,“低代码平台”更多的是基于通用开发能力设计而成,如Paas底座、对象与关系管理、积木组件、流程编排等,再加上基于自身优势业务领域的经验沉淀的可配置组件,极大降低了系统开发难度,让非科班出生的从业者也能较为轻松的构建出个性化的业务系统。

    那么“低代码平台”是一劳永逸的完美方案么?虽然“低代码平台”提供了一系列低成本构建和扩展业务系统的手段。但是一个业务模型往往是一个业务闭环,涉及多页面、多逻辑、多对象之间的联动,共同形成一个完整业务。比如合同变更业务存在非常多的关联校验、业务及数据联动、成本算法计算,业务阶段也是多变的。从零开始搭建或者仅仅复用部分业务组件,客户的定制成本依然比较高。如何将如合同变更之类多变业务模板化,将是我们本次探讨的主要内容。

三、多变业务模板化

首先,我们根据开篇用户的反馈,从多变性业务中可以发现一些特点:

  1. 同一业务虽然多变,但仍然具有共同的外部关系,如合同变更有共同前置对象“合同”,共同的影响“合同金额变更”。

  2. 模型的变化实际上是业务阶段的拆解和合并,如合同变更有些客户会拆分为申报、指令、确认三个阶段,有些客户会把申报和确认合并,有些客户会把确认拆解为事项确认和费用确认。

  3. 在核心模型之外,会有追加诉求,如无效成本、税目信息、附件等。

  4. 交互体验会有差异。

基于以上特点,我们可以分别将其进行实例映射:

  1. 业务外部关系=》事件与接口。

  2. 业务阶段=》页面、表、关系、逻辑。

  3. 追加的诉求=》业务组件、接口。

  4. 交互体验的差异=》可替换的UI。

    那么,如何将这些实物按照客户需求进行组合呢?首选方式是配置,配置实现有两种方案:

  • 第一种,是通过全局配置参数进行控制,比如利用参数开启阶段、启用组件等,但是这种方案难度系数巨大,首先是通过参数控制全量的对象,只能通过显隐方式实现,处理好这些元素间的关系、数据代价较大;其次,如果要复制一套业务,比如新增一个变更或合同,则全局配置参数是无法满足的。

  • 第二种,是通过将配置、对象一起打包为模板,通过配置动态创建对象,这个过程我们称之为模板生成实例。每个实例有一套配置副本,统一进行管理,而因为该模板具有极强的业务属性,我们称之为业务模板。

    业务模板我其实更倾向于称之为“业务解决方案包”,因为在前期推演时,向同事介绍业务模板概念,但是同事往往会将之与页面模板、脚本模板等概念相混淆,甚至认为业务模板就是页面模板。其实他们之间差异很大。页面模板是将相似的页面中差异的部分用占位符替代,然后根据实际数据动态生成最终的页面,并没有太多业务属性。而业务模板则是对整个业务闭环进行抽象,这个环是一个业务链,比如变更申报单填写、审批,再到指令单处理,最后到确认单审批,最终完成合同金额的调整。环上的点,就是每个阶段所涉及的具体单据业务,也就是页面。在这个环内有表数据对象、辅助功能页,外部有关联影响点和接口。这个业务闭环有多大、有哪些节点、最终会生成哪些数据对象,则依赖一套配置进行编排,这个配置就是某种意义上的占位符,只是其占位的不是数据本身而是数据关系。页面模板只是整个业务方案中具体的某个功能页面,仅仅负责用户交互。

    搞清楚了业务模板的定位,在后续的实践中,我们和建模平台的同事一起通过实践,确定了业务模板所包含的基本元素:

  1. 数据模板:定义数据对象及数据结构,最终会生成物理数据表。

  2. 数据关系模板:定义数据对象之间的数据关系。

  3. 页面模板:定义用户交互UI,最终会生成物理页面。

  4. 业务参数模板:控制涉及数据的业务个性开关,最终会生成供客户调整业务的业务参数。

  5. 模板配置:控制1-3模板的生成规则,最终形成的业务各个阶段。

四、业务模板的应用

    在我们前面的场景中,我们利用业务模板能做些什么呢?

  • 对于A顾问来说,我们可以通过模板配置只生成申报和指令两个阶段所需的页面、数据表,并在数据交互时识别配置,跳过缺失阶段。

  • 对于B区域顾问,我们仅需编写一套适合当地的页面模板替换掉业务模板中的页面模板,创建符合当地习惯的变更单。

  • 对于C区域顾问,则只需使用模板实例化一套新的变更单实例即可,所有的页面、数据表、关系、配套接口等一整套对象都可生成,在此基础上做一些微调即可。

  • 而对于D客户,我们未来可以将打包业务模板的权限逐步向顾问开放,通过对标准业务模板的调整,最终形成区域自己的业务模板,以快速交付区域内其它相似需求的客户。

    前面对业务模板的理解更多基于合同变更的例子,那么是否同样适用于合同业务中呢?

    对于合同业务,不同业务形态的合同是不同的,但梳理下来,会有以下共同特点:

  1. 合同对象:

    1. 基本属性。

    2. 特征属性。

    3. 关联对象。

  2. 合同分类:

    1. 合同模板。

  3. 配套服务:

    1. 工作流。

    2. 电子签章。

    3. 离线编制。

    4. 编码规则。

  4. 对外服务:

    1. 公共接口。

    2. 事件驱动。

    对于上面这些来说,似乎用页面模板就能解决,有些客户的合同就是采用页面模板+配置的方式实现了数十种合同。但是有些问题待考虑:

  1. 基于客户自身明确的需求,而标准产品无法预测客户会在某些合同上附加何种功能,而这些功能和数据应该是与其它合同隔离的。

  2. 所有的合同共用一张物理表是否合理。

    我们如果基于业务模板,我们来看如何设计这套合同系统。合同属性是由页面来承载的,基本属性是所有合同所共有的,因此作为固定元素,显隐控制即可。特征属性是每种合同特有的,可以抽离为特征业务组件,选择性使用。关联对象,比如税目信息,是从信息,同样可以抽离为业务组件,选择性使用。据此,首先将合同分类作为配置项放入业务模板,然后定义一个合同表模板,包含基础属性字段,而特征字段则根据配置的合同分类设置动态特征属性字段,而关联对象,则为每个对象定一个从表模板。再然后,我们定义一个合同页面模板,包含所有基本属性,并根据配置的合同分类设置动态嵌入特征属性组件以及关联对象组件。最后,将配套服务所需的开关作为业务模板的业务参数。那么客户需要某种合同的时候,在业务模板中选择合同类型,然后实例化出具体的合同,此时合同所需的一切页面、表都创建完成,逻辑也根据实例自动接入。后续仅需要通过建模做一些微调即可发布。

    当然,这里我们只做探讨,并非表述采用业务模板是实现合同业务最合理的方式,一切都需要进行技术选型和论证后才能决定。

五、业务模板的挑战

    在业务模板技术的艰难演进过程中,也不断收到过很多质疑。

    从业务方面来说,有同学质疑业务模板生成实例只是上线客户一次性的动作,如果使用过程中,客户做了模型调整,那么业务模板就起不了什么作用了,对于这个问题,从业务模板定位上来说,是解决客户业务模型初始化的问题,但是这个初始化并不是只在上线时使用,如果使用过程中,客户做了模型调整,那么依然可以使用业务模板初始化功能进行重新初始化,当然这里面涉及到了数据升级及客户前期个性扩展如果保留的问题。我们并不认为这是业务模板本身问题,而是我们要从数据迁移、建模元数据自升级两方面来降低客户重新初始化的代价,这个是任何升级都无法避免的问题,不仅仅是业务模板的特例。

    从技术方面来说,有同学质疑业务模板太重,以前每个业务每个页面都是具体的,开发简单,而业务模板却只是模板,开发、调试并不方便,增加了产品开发成本。这个是相对的,一方面新技术的演进本身就是有一定难度的,有种说法是把技术难度前置了,研发难度有一定提升,但是交付难度降低了,基于边缘效应,总体成本是快速下降的,这也是技术投入的初衷,技术投入从来都不是降低研发端的难度,而是降低总体的成本。比如单体应用是简单的,但弹性扩展难度大,而微服务的架构是复杂的,高难度的,难维护的,但却极大提升了弹性扩展能力,表现出来的结果就是面对业务数据的快速上升,但却能低成本快速的扩展应用,总体成本是降低的。另一方面,业务模板在开发端还并不成熟,体验还待改善,这个带来了错觉,觉得业务模板太复杂,难以驾驭。其实把问题打开来看,更多的是可以通过工具化、优化交互、调整流程就能解决的,如果解决了这些,是否还有模型本身的问题呢?这个也需要进一步审视,也期待能够更多的反馈。

    总的来说,多变业务模型如何能够实现快速交付是一个长期的课题,业务模板也许不是一个最完美的方案,但是也是值得去进一步发掘的方向。

------ END ------

作者简介

胡同学: 架构师,目前负责ERP成本应用系统的架构设计与开发工作。

也许您还想看

成本计算引擎动态规则解析技术详解

ERP开放平台定制化远程高效协作秘笈

建模平台标准组件可维护性改进实践

一个全栈式的应用集成平台,打破“信息孤岛”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/306725.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mockmvc get请求 tm的 一直404_大家快来看看404的兄弟姐妹

码个蛋(codeegg)第 624 次推文作者:xiaoxiunique博客:https://juejin.im/post/5cd2ea425188254459335583做开发的我们肯定少不了跟网络数据打交道,我们都知道,我们进行网络请求,无论成功还是失败,后台都会给…

网传不要升级.NET5的诸多原因,你赞同几个?

.NET5正式发布有十多天,博客园、知乎、技术群都讨论的非常热烈。关于项目是否迁移.NET5的话题讨论的尤为热烈,作为.NET十年老司机要告诉你,.NET5的迁移势在必行,当下就是最好的时机!犹豫项目是否升级到.NET5的&#xf…

sort()函数

sort()函数 标准库里的排序函数的使用方法 I)Sort函数包含在头文件为#include的c标准库中,调用标准库里的排序方法可以不必知道其内部是如何实现的,只要出现我们想要的结果即可! II)Sort函数有三个参数:…

WPF开发的实用小工具 - 快捷悬浮菜单

WPF开发的实用小工具 - 快捷悬浮菜单❝本文由网友投稿,Dotnet9站长整理。站长觉得这小工具很实用,站长家里、公司也在尝试使用了。行文目录:这工具有什么用?正文源码获取及应用下载体验站长的建议1. 这工具有什么用?问…

accdb原有的数据怎么清除_VBA中利用数组对数据批量处理的方法

大家好,今日继续和大家分享VBA编程中常用的常用"积木"过程代码。这些内容大多是我的经验和记录,来源于我多年的经验。今日分享的是NO.225-NO.226,内容是:NO. 225:数组的赋值和回填工作表NO. 226:…

问题 A: 约瑟夫问题(普及第一关模拟)

题目描述 求解约瑟夫(Joseph)问题。有n个小孩围成一圈,给他们从1开始依次编号,从编号为1的小孩开始报数,数到第m个小孩出列,然后从出列的下一个小孩重新开始报数,数到第m个小孩又出列&#xff…

云南河道 kml文件_处理能力提升 4 倍 ,大疆智图 4 天完成 5 公里河道建模

马陵河是江苏省宿迁市老城区一条重要排涝河道,1974 年人工开挖而成,全长 5.2 km,汇水面积 11.6 km,居住人口 13.85 万人。河道水质长期处于黑臭状态,严重影响周边居民日常生活,被称为宿迁的“龙须沟”。宿迁…

linq 查询的结果会开辟新的内存吗?

一:背景 1. 讲故事昨天群里有位朋友问:linq 查询的结果会开辟新的内存吗?如果开了,那是对原序列集里面元素的深拷贝还是仅仅拷贝其引用?其实这个问题我觉得问的挺好,很多初学 C# 的朋友或多或少都有这样的疑…

问题 B: 十进制到二进制的转换

这个问题我们来用栈来实现 首先,我们先定义一个栈的结构体(栈的结构体与链表的结构体不可同,栈的结构体第二项是用int定义栈的顶端; 而链表的第二项,是用struct定义一个指针) struct stack{int data[10005];int top;…

javascript内存泄漏调试工具mac_node.js 内存泄漏的秘密

一直以来,跟踪 Node.js 的内存泄漏是一个反复出现的话题,人们始终希望对其复杂性和原因了解更多。并非所有的内存泄漏都显而易见。但是,一旦我们确定了其模式,就必须在内存使用率,内存中保存的对象和响应时间之间寻找关…

c++STL中的find()函数 有两种使用方法

cSTL中的find()函数 有两种使用方法 方法一: 开头引头文件:中的函数 其调用形式为 find(start,end,value) start搜寻的起点,end搜寻的终点,要寻找的value值; 如果没有找到,则返回end。函数的返…

关于C# Span的一些实践

Span这个东西出来很久了,居然因为5.0又火起来了。特别感谢RC兄弟提出这个话题。相关知识在大多数情况下,C#开发时,我们只使用托管内存。而实际上,C#为我们提供了三种类型的内存:堆栈内存 - 最快速的内存,能…

问题 C: 【例2-3】围圈报数

题目描述 有&#xff4e;(n<100)个人依次围成一圈&#xff0c;从第&#xff11;个人开始报数&#xff0c;数到第&#xff4d;个人出列&#xff0c;然后从出列的下一个人开始报数&#xff0c;数到第&#xff4d;个人又出列&#xff0c;…&#xff0c;如此反复到所有的人全部…

怎样用python批量处理文件夹_python批量处理文件或文件夹

本文实例为大家分享了python批量处理文件或文件夹的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下 # -*- coding: utf-8 -*- import os,shutil import sys import numpy as np ##########批量删除不同文件夹下的同名文件夹############# def arrange_file(dir_path0…

leetcode-349-两个数组的交集

给定两个数组&#xff0c;编写一个函数来计算它们的交集。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 输出&#xff1a;[2] 示例 2&#xff1a; 输入&#xff1a;nums1 [4,9,5], nums2 [9,4,9,8,4] 输出&#xff1a;[9,4] 说明&#xff1a; 输…

Leansoft再发招贤令:面试官徐磊有话讲 | IDCF

&#xff08;图片来源于网络&#xff09;2020是Leansoft成立的第五年&#xff0c;凭借专业的服务及实施能力&#xff0c;逐渐成长为国内唯一的端到端专业DevOps实施服务公司。Leansoft是一家怎样的公司呢&#xff1f;准确地说&#xff0c;我们其实是国内唯一一家提供端到端的De…

问题 B: 数塔问题

题目描述 有如下所示的数塔&#xff0c;要求从顶层走到底层&#xff0c;若每一步只能走到相邻的结点&#xff0c;则经过的结点的数字之和最大是多少&#xff1f; 输入 第一行是一个整数N(1 < N < 20)&#xff0c;表示数塔的高度&#xff0c;接下来用N个数字表示数塔&a…

leetcode-345-翻转字符串中的元音字母

编写一个函数&#xff0c;以字符串作为输入&#xff0c;反转该字符串中的元音字母。 示例 1&#xff1a; 输入&#xff1a;“hello” 输出&#xff1a;“holle” 示例 2&#xff1a; 输入&#xff1a;“leetcode” 输出&#xff1a;“leotcede” 来源&#xff1a;力扣&…

e盾服务端源码_gRPC服务注册发现及负载均衡的实现方案与源码解析

今天聊一下gRPC的服务发现和负载均衡原理相关的话题&#xff0c;不同于Nginx、Lvs或者F5这些服务端的负载均衡策略&#xff0c;gRPC采用的是客户端实现的负载均衡。什么意思呢&#xff0c;对于使用服务端负载均衡的系统&#xff0c;客户端会首先访问负载均衡的域名/IP&#xff…

堆问题(最小堆变最大堆,堆删除,中序遍历)

2-6 设最小堆&#xff08;小根堆&#xff09;的层序遍历结果为 {8, 38, 25, 58, 52, 82, 70, 60}。用线性时间复杂度的算法将该堆调整为最大堆&#xff08;大根堆&#xff09;&#xff0c;然后连续执行两次删除最大元素操作&#xff08;DeleteMax&#xff09;。则该树的中序遍历…