在上一篇[《业务团队如何统一架构设计风格?》] 中,探讨了一种业务架构的设计规范,以期达到这些目标:用标准约束技术细节;用技术工具而非文档推行标准;持续重构而非造新轮子;重视业务建模。但通篇表述较为抽象。本篇将总结团队近来的架构演进工作,以更具体的技术细节,详细阐释该理念,作为“统一业务设计风格”的实践篇。文中详述了多个层面的设计规约和基于规约的搭建方式,并在末尾回答了上一篇的诸多疑问。
上图以电商产品为例,展示了一套标准框架的各层设计单元。先简单了解下概念,下一章节会详细解释各层的设计规约和搭建方式:
以产品合约描述完整的功能列表;以签署人身份来定位产品功能的适用场景;以合约分组来描述一个独立完备的功能域,分组的集合就是产品功能的范围和边界。通过对合约分组进行组装,可以快速搭建商业产品。
为了减少不同技术同学对领域进行建模的风格差异,我们对业务模型的使用场景做了诸多约定,串联起仓储管理/业务流程/业务组件等基础模块。所有人更关注于业务在模型上的表达,而大大减少了对实现细节的关注。基于对领域的分析,可以快速搭建业务模型。
用一套标准的业务流程框架,描述业务模型的完整执行流程:业务组件是一套高内聚的业务功能集合,基于组件配置将业务模型的信息适配为标准参数,交由基础设施执行具体功能;流程引擎负责创建和管理流程实例,接收指令来触发组件动作的执行,并实现状态推进/条件跳转和异常处理等分支管控的需求。通过对业务组件/基础设施的抽象和沉淀,可以快速搭建业务流程。
用一套标准的数据流机制,来满足视图层的定制化需求:数据流订阅器用于采集数据,物理来源包含区块链跨链数据/业务DB数据/文件系统数据/离线任务数据等;数据流消费器用来加工原始数据,生成展示层数据/待核对数据/数据指标等等。订阅器确保了数据来源的稳定和低成本的快速接入,消费器则交由技术同学自行定制业务逻辑。在不干扰领域建模的基础上,可以快速搭建数据视图。
以电商产品为例,商家单独签署的产品合约被作为商家合约,描述了商品的上架要求;商家+平台+买家共同签署的产品合约,则适用于交易下单场景。
新增/修改
低代码:基于业务需求,在产品中心设计产品模板,明确合约分组和具体内容
使用:
接入时编码,一次性:在业务系统内编写对应产品合约和签署身份的模型类,完成和产品中心的对接,包括合约的创建/失效,基于签署身份的合约查询等等
电商产品合约下,商品分组描述了商品上架的流程和配置,下单分组约束了订单创建的流程和服务信息,退货分组则说明了退货流程和买家能够享受的客户服务。
新增/修改
低代码:以元数据的方式定义一个合约分组,包含模型/流程/配置等等,每一个配置都可以用键路径/配置值类型和限制等描述
使用
硬编码:在业务系统内定义合约分组的模型类,完成与产品合约内容交互的写入和读取,在业务代码处显式获取业务分组实例
低代码:搭建合约查询->分组解析->配置获取的通用框架(引入缓存避免重复查询),业务层只需要通过元数据描述,就可以获取对应分组内的配置信息
退货业务,基于退货单推进业务流程,各业务组件从退货单获取必要的业务信息,执行退货/退款/通知等业务功能;退货单关联自一个正向订单,但正向订单不可反向依赖退货单;一个退货单模型对应一张主单据表和多张退货明细表,仓储需要负责完成业务模型<->数据模型的双向读写
硬编码:编写业务模型(Model)/数据模型(DO)/数据交互(Mapper)/视图模型(VO)/转换层(Converter)/仓储(Repository)等等
低代码:用元数据描述,自动生成DO/VO/Mapper/Converter;基于底座提供的仓储组件,也可以通过元数据描述,自动生成业务模型仓储的实例
1、业务服务是一套以业务领域为单位(interface)作聚合,开放给内外所有使用方的最小业务功能单元(method) 2、业务服务需要一套定义规范(annotation/aop等),对每一个功能单元有清晰直观的元数据描述,用以实现服务发现/文档生成/权限管控/稳定性保障等等。元数据包括:业务域,业务动作,读/写,错误码范围,返回值模型等等 3、业务服务的入参,限制为一个sysParam和一个bizParam,前者为调用来源/幂等ID/产品码/租户ID等系统参数,后者为各业务自行定义的模型参数,建议为可全链路透传(rpc->api->flow->component)的POJO
4、业务服务以Result形式返回,错误码尽量控制在元数据描述的范围内,不泄漏任何exception给调用方。返回的业务信息,建议为POJO或VO 5、业务服务不局限于调用方的物理来源,只需要在对接层增加简单的转换逻辑,做授权管控即可 6、写服务的实现,需要有事务管理机制
public interface DemoOrderService {
/**
* 下单申请
* @param sysParam sysParam
* @param bizParam bizParam
* @return result
*/
@ApiFunction(apiType = ApiType.SUBMIT, funcBiz = "ORDER",funcAction = "APPLY",
returnType = OrderApplyResponse.class, errorCodeType = CommonErrorCodeEnum.class)
CommonResult<OrderApplyResponse> apply(ApiReqSysParam sysParam, OrderApplyInfo bizParam);
}
新增/修改
定义-低代码:基于元数据描述,自动生成interface+method+errorcode+POJO等等
实现
硬编码:简单需求/不可模板化/无法流程化的业务需求,直接编码
低代码:对于标准的流程发起服务(申请上架/申请下单/申请退货),用模板实现合约分组加载->流程配置加载->流程初始化(幂等)->流程触发->结果处理;对于标准的流程推进服务(通知回执/调度推进),用模板实现流程配置加载->流程触发->结果处理等等。随着更多服务场景的出现,可以有更多模板化的业务服务。
使用
硬编码:与所有interface的使用一样,组装请求->调用->处理结果
低代码:基于元数据描述和业务配置,将当前业务对象/外部参数映射为服务入参的POJO,异常处理模板化,成功返回的结果以同样方式映射回业务对象或外部响应
1、Flow用于描述一个完整的业务流程,基于单个业务模型,推进一个或多个业务子环节
2、对于单个业务模型的同一类型业务流程,可以有多个Flow定义,以满足不同业务模式的定制需求
3、Flow包含迁转 (transition) ,组件 (component) 和动作 (action) 三级结构,运作原理如下:每次触发 (operate) 对应于组件的一次action,所有action都成功的component会完结,而所有component都成功的transition将会触发Flow和业务模型的状态迁转。
4、Flow的目标是将复杂流程拆解成多个原子化的业务动作,相互解耦
5、Flow需要结合业务服务/消息/调度等调用入口的触发,才能实现完备的流程推进
6、Flow需要依赖外部调用方提供事务管理机制(通常是业务服务),需要依赖业务模型仓储来控制模型的加载和存储
<?xml version="1.0" encoding="UTF-8"?>
<flow id="OrderApply" version="001" desc="标准下单流程">
<config>
<model class="xxx.xxx.Order"/>
</config>
<init type="INIT" desc="初始化">
<action operate="INIT.INIT"/>
</init>
<transitions>
<transition from="INIT" to="ITEM_OCCUPIED">
<component type="ITEM" desc="扣减库存">
<action operate="ITEM.OCCUPY"/>
</component>
</transition>
<transition from="ITEM_OCCUPIED" to="DISCOUNT_OCCUPIED">
<component type="DISCOUNT" desc="扣减优惠">
<action operate="DISCOUNT.OCCUPY"/>
</component>
</transition>
<transition from="DISCOUNT_OCCUPIED" to="SUCCESS">
<component type="NOTIFY" desc="下单成功通知">
<action operate="NOTIFY.SELLER"/>
<action operate="NOTIFY.BUYER"/>
</component>
</transition>
</transitions>
</flow>
新增/修改
低代码:Flow自身的运作由底座组件支撑,只需一次性编码;若需要定义业务流程,可基于业务组件模板和业务模型,动态生成Flow配置文件;加上版本控制和隔离机制,就可以防止兼容性问题
使用
硬编码:Flow初始化场景,从当前业务领域的合约分组中,获取需要的Flow配置,初始化流程并推进;Flow推进场景,基于modelId+modelType+operate+request,可以用模版化代码自动触发
低代码:通过对合约分组中Flow配置的标准化,可以将Flow初始化场景也以模板化的方式实现;当一个现有业务服务需要支持新定制的业务流程时,只需调整合约内的配置即可
1、业务组件是某一类业务动作的聚合,面向业务功能设计,不局限于任何一个业务模型
2、业务组件的业务动作,是原子化的最小业务单元,粒度暂无强制要求,但以解耦和复用程度为衡量依据;建议其依赖一个到多个基础设施/业务服务,以模板化的方式提供标准的业务动作实现
3、对于某个业务模型,业务组件通过开放适配器(详见【基础设施-适配】)的方式支持受控定制,或以完全复写的方式实现排他定制(不允许其他业务复用)
4、所有的核心业务逻辑,都应收归到业务组件层及其以下(无流程的简单业务服务除外),包括但不限于:参数校验,业务校验,重入/幂等控制,业务模型变更,合约分组变更,计算规则,外部服务交互等等
5、业务组件需要一套定义规范(xml/annotation等),对其支持的业务动作和业务模型有清晰直观的元数据描述,用以搭建业务流程。元数据包括:业务动作列表和对应的触发点(operate),支持的业务模型列表
public interface BizModelDiscountComponent<T extends BizModel> extends BizModelComponent<T> {
/**
* 占用优惠
* @param context
*/
void occupy(FlowContext context);
/**
* 退回优惠
* @param context
*/
void refund(FlowContext context);
}
<componentTemplate type="DISCOUNT" desc="优惠">
<interface name="xxx.xxx.BizModelDiscountComponent"/>
<bizModelMappings>
<bizModelMapping>
<bizModel class="xxx.xxx.Order"/>
<componentEntry name="orderDiscountComponent"/>
</bizModelMapping>
<bizModelMapping>
<bizModel class="xxx.xxx.RefundOrder"/>
<componentEntry name="refundOrderDiscountComponent"/>
</bizModelMapping>
</bizModelMappings>
<triggerMappings>
<triggerMapping>
<triggerTemplate operatePostfix="OCCUPY"/>
<methodEntry name="occupy"/>
</triggerMapping>
<triggerMapping>
<triggerTemplate operatePostfix="REFUND"/>
<methodEntry name="refund"/>
</triggerMapping>
</triggerMappings>
</componentTemplate>
适配器Adapter的解释,详见【模型适配】小节
public abstract class AbstractBizModelDiscountComponent<T extends BizModel> implements BizModelDiscountComponent<T> {
@Resource
private DiscountApiService discountApiService;
@Override
public void occupy(FlowContext context) {
// TODO AdapterConfigInfo根据context从当前合约中获取
T bizModel = (T) context.getBizModel();
getDiscountAdapter().processOnOccupyResult(
bizModel,
discountApiService.occupy(getDiscountAdapter().toOccupyInfo(bizModel, new AdapterConfigInfo()))
);
}
@Override
public void refund(FlowContext context) {
// TODO AdapterConfigInfo根据context从当前合约中获取
T bizModel = (T) context.getBizModel();
getDiscountAdapter().processOnRefundResult(
bizModel,
discountApiService.refund(getDiscountAdapter().toRefundInfo(bizModel, new AdapterConfigInfo()))
);
}
@SuppressWarnings("unchecked")
protected BizModelToDiscountAdapter<T> getDiscountAdapter(){
return (BizModelToDiscountAdapter<T>) FlowInstanceFactory.instanceBizAdapter(
"DISCOUNT", (Class<? extends BizModel>) TypeUtils.getRealClassOfParameterizedType(this));
}
}
新增/修改
硬编码:全新业务组件基本无法低代码化,需要开发有足够的设计思维和大局观,权衡复用度和成本后实现初版;随着业务发展,逐步抽象出模板化的业务组件实现;很多场景下,如果避免不了复杂的定制逻辑,可以自行以策略/职责链/工厂等多种设计模式落地,这依赖于开发者的建模能力,不做强制要求
低代码:已有的业务组件应用于新业务模型的场景,如果已经抽象出合约配置+适配器+基础设施的标准模板,只需做合约配置即可(通知/核身/存证上链等场景适合)
使用
低代码:在Flow底座中完成业务组件的编排/发现和触发,一次性编码;完成Flow配置,即完成业务组件的装配
注:此处的基础设施与DDD中的概念有很大差异,请勿混淆
public interface NotifyGateway {
/**
* 通知(邮件/短信/站内信)
* @param notifyInfo
* @return
*/
CommonResult<NotifyResponse> notify(NotifyInfo notifyInfo);
}
新增/修改
硬编码:基础设施的接入通常是一次性的,低代码的价值不易发挥
使用
硬编码:在业务服务/业务组件等调用方代码中,组装入参->调用->解析返回
低代码:在业务组件中,基于下文将介绍的适配机制,可以实现:合约配置+模板化业务组件,低代码复用现有基础设施
public abstract class BizModelToDiscountAdapter<U extends BizModel> implements BizModelAdapter<U> {
@Override
final public String getType(){
return "DISCOUNT";
}
/**
* 生成扣减申请
* @param bizModel
* @return
*/
abstract public OccupyInfo toOccupyInfo(U bizModel, AdapterConfigInfo configInfo);
/**
* 处理扣减结果
* @param bizModel
* @param result
*/
abstract public void processOnOccupyResult(U bizModel, CommonResult<OccupyResponse> result);
//...
}
@BizAdapter
public class OrderToDiscountAdapter extends BizModelToDiscountAdapter<Order> {
@Override
public List<ConfigDef> getConfigDefs() {
return Lists.newArrayList(
ConfigEnum.DISCOUNT_TYPE,
ConfigEnum.DISCOUNT_TERM
);
}
@Override
public OccupyInfo toOccupyInfo(Order bizModel, AdapterConfigInfo configInfo) {
// 解析出客户选择的优惠类型
return new OccupyInfo();
}
@Override
public void processOnOccupyResult(Order bizModel, CommonResult<OccupyResponse> result) {
// TODO 根据扣减成功的优惠,重新计算订单金额
}
// ...
}
新增/修改
定义-硬编码:当业务组件和基础设施/业务服务出现调用关系时首次定义,通常不再变更
实现-低代码:可以用一套灵活的合约配置描述映射关系,实现一次编码后只需配置维护;但是,这既依赖于DSL级别的描述能力,也需要业务模型和基础设施/业务服务的设计者,都具备较高的抽象能力,成本较高
使用
硬编码:当业务开发抽象出可模板化的业务组件时,即完成了首次接入;当基础设施/业务服务出现新模式时,需要进行适配调整
啰嗦了这么多,为避免被过度细节冲淡主题。最后以几个问题做个小结:
架构层面,从产品合约->业务领域->基础设施,我们对应用做了模块拆解,在不同层面设计了业务规约,约束了各模块的职责;技术层面,通过多个底座组件,一定程度上实现了平台和业务定制的隔离,限制了业务细节的无序散布。
规范的目的不是标准本身,本文提出的标准也未必适合所有问题域。想传达的是,团队内需要有业务设计的某种共识和沉淀,在每次迭代需求和每次项目产出的基础上,持续积累持续重构持续优化,这对新人融入/个人成长和团队协作都很有帮助。
需要明确的是,对于全新的业务需求,不会带来明显的效能提升,甚至会为了满足设计规范,带来一定程度的额外成本。但当多人协作,工作交接,或是现有功能部分可复用的场景下,会减少很多不必要的沟通和维护成本。举例来说,当一个业务需求出现时,研发人员需要做如下判断:
2 . 业务服务:xxxxxxxxxxxx业务服务,xxxxxxxxxxxx现有服务
3 . 业务流程:xxxxxxxxxxxx业务流程,xxxxxxxxxxxx现有流程
4 . 业务组件:xxxxxxxxxxxx业务组件,xxxxxxxxxxxx现有组件
5 . 基础设施:xxxxxxxxxxxx基础设施,xxxxxxxxxxxx现有设施
6 . 产品合约/合约分组:基于上述判断,评估产品合约和合约分组的组装
带来的效能提升有这样几点:业务领域的每个模块互相解耦,研发过程并行化,投入人员1+1可以=2;改造范围更易于定位,资源评估更为准确,进度把控更加清晰;针对频繁变动且成本过高的模块,进行针对性的重构,影响范围可控;上文中的很多处规约,都有潜在的低代码化可能,能进一步提升搭建效率。
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/5Q1Fd_s3amFW8I_S1A8w2w
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。