当前位置: 首页 > article >正文

别再让JSON字段毁了你的业务代码:从阿里商品中台案例看领域模型与数据模型的正确分工

领域模型与数据模型的分工艺术从阿里商品中台实践看架构设计的本质记得三年前接手一个电商促销系统重构时我发现前任开发者将所有营销规则都塞进了一个名为promotion_rules的JSON字段里。当需要增加限购地区功能时团队直接在JSON里追加了region_restrictions数组而业务代码中遍布着类似JSON.parse(rule).region_restrictions.includes(userProvince)的判断——这种将数据存储结构直接暴露给业务逻辑的做法让系统在半年内变成了无人敢动的祖传代码。1. 领域模型与数据模型的本质差异1.1 领域模型业务语义的精确表达领域模型是解决业务问题的概念框架其核心价值在于显性化业务语义。在商品价格管控场景中一个良好的领域模型应该像这样public class PriceRule { private ListPriceRange ranges; private ApprovalStrategy strategy; public boolean isPriceValid(BigDecimal price) { return ranges.stream().anyMatch(range - range.contains(price)); } } public class PriceRange { private BigDecimal min; private BigDecimal max; private RangeType type; // AUTO_APPROVE, AUTO_BLOCK等 }这种建模方式明确表达了价格规则由多个区间组成每个区间有特定类型的业务语义。当产品经理提出某些商品需要人工复核时开发者可以自然地扩展ApprovalStrategy枚举而不是在JSON里添加need_manual_review字段。1.2 数据模型存储效率的极致追求数据模型的核心诉求是存储效率和访问性能。同样价格管控场景数据库设计可能简化为字段名类型描述idbigint主键rule_namevarchar规则名称conditionjson价格区间配置modified_byvarchar最后修改人架构师笔记优秀的存储设计应该像乐高积木——通过有限的基础结构组合出无限可能。但业务代码不应该直接拼装这些积木。2. 混淆模型的典型反模式2.1 JSON字段滥用综合症在商品中心系统里我们经常见到这样的灵活设计CREATE TABLE product_extend ( product_id BIGINT PRIMARY KEY, features JSON COMMENT 商品扩展属性 );初期看似便捷的方案随着业务发展会出现三大致命伤可读性灾难代码中充斥着feature.get(pre_sale).get(deposit_amount)这样的魔法字符串验证缺失无法在数据库层约束JSON结构的有效性查询低效即便现代数据库支持JSON查询性能也远不及结构化字段2.2 垂直扩展表的陷阱阿里商品中台的auction_extend表设计确实是扩展性典范字段名类型示例值auction_idbigint123456extend_keyvarcharpresale_infoextend_valuetext{start:1630000}但当业务代码直接操作这些扩展字段时就会出现前文提到的面向字段编程现象。更糟糕的是这种模式会像病毒一样扩散——当第一个团队开始用getFeature(presale_info)其他团队会迅速效仿。3. 模型转换的架构实践3.1 网关模式Gateway的威力COLA架构提出的Gateway模式正是解决这类问题的银弹。以商品服务为例// 数据访问层 public interface ProductGateway { Product getById(Long id); } // 实现层 public class ProductGatewayImpl implements ProductGateway { public Product getById(Long id) { ProductDO productDO dao.selectById(id); ListFeatureDO features featureDao.selectByProductId(id); return convertToDomain(productDO, features); } private Product convertToDomain(ProductDO productDO, ListFeatureDO features) { Product product new Product(); product.setId(productDO.getId()); // 将扩展字段转换为领域对象 features.forEach(f - { if (presale_info.equals(f.getKey())) { product.setPresaleInfo(parsePresaleInfo(f.getValue())); } // 其他字段转换... }); return product; } }这种模式带来三个关键优势业务语义隔离领域层完全感知不到底层存储结构变更局部化数据库结构调整只需修改Gateway实现测试友好可以轻松Mock网关进行单元测试3.2 转换策略的演进随着系统复杂度提升我们可以引入更高级的转换策略策略对比表策略类型适用场景实现复杂度典型案例硬编码转换字段少且稳定★☆☆☆☆基础商品信息注解驱动中等规模领域模型★★★☆☆订单核心流程DSL映射高度动态的业务扩展★★★★★营销活动配置元数据驱动SaaS多租户系统★★★★★★电商开放平台性能提示对于高频访问的领域对象可以在Gateway层引入二级缓存缓存转换后的对象。4. 中台架构的平衡之道4.1 阿里商品中台的启示深入分析阿里auction_extend的设计哲学我们可以提炼出三个核心原则存储与业务解耦扩展表只负责存储不定义业务含义元数据描述通过单独的feature_meta表描述扩展字段语义分层治理核心字段结构化存储长尾需求用扩展表这种设计虽然完美解决了不同业务线疯狂加字段的问题但需要配套的架构约束严格禁止业务代码直接查询扩展表为每个业务线提供专用的SDK封装字段访问建立扩展字段的注册和审计机制4.2 现代架构的解决方案在云原生时代我们可以采用更优雅的解决方案// 使用Spring Data的Converter接口 public class ProductConverter implements ConverterProductDO, Product { private FeatureRepository featureRepo; public Product convert(ProductDO source) { Product product new Product(); // 基础字段映射... // 动态扩展字段处理 featureRepo.findByProductId(source.getId()) .forEach(f - product.addFeature( FeatureFactory.create(f.getKey(), f.getValue()) )); return product; } } // 在Repository中注册 public interface ProductRepository extends JpaRepositoryProductDO, Long { Override EntityGraph(attributePaths {features}) OptionalProductDO findById(Long id); }配合Hibernate的TypeDef注解甚至可以做到JSON字段到领域对象的自动映射TypeDef(name jsonb, typeClass JsonBinaryType.class) public class ProductDO { Type(type jsonb) Column(columnDefinition jsonb) private ProductSpec spec; // 自动序列化/反序列化 }5. 实战重构商品评价系统最近主导的一个电商平台重构项目正是运用这些原则将评价系统从字段驱动改造为模型驱动的典型案例。改造前存储设计CREATE TABLE item_review ( id BIGINT PRIMARY KEY, item_id BIGINT, content TEXT, features JSON -- 包含: media_urls, is_anonymous, tag_scores等 );改造后架构领域模型明确定义public class Review { private ReviewId id; private Content content; private Media media; private AnonymousInfo anonymity; private ListTagRating tagRatings; }网关层转换逻辑public class ReviewGatewayImpl implements ReviewGateway { public Review save(Review review) { ReviewDO reviewDO new ReviewDO(); reviewDO.setItemId(review.id().itemId()); reviewDO.setContent(review.content().text()); // 结构化字段 reviewDO.setIsAnonymous(review.anonymity().enabled()); // 动态扩展字段 reviewDO.setFeatures(JsonUtils.toJson(Map.of( media, review.media().urls(), tags, review.tagRatings().stream() .collect(toMap(TagRating::tag, TagRating::score)) ))); return convertToDomain(reviewDao.save(reviewDO)); } }业务代码的蜕变// 改造前 if (review.getFeatures().getBoolean(is_anonymous)) { displayName 匿名用户; } // 改造后 if (review.anonymity().enabled()) { displayName 匿名用户; }这次重构使得新需求的实施时间平均缩短40%因为新增评价维度时只需扩展领域模型业务规则检查集中在值对象方法中存储结构调整对业务代码零影响6. 模型转换的性能优化当系统达到一定规模时模型转换可能成为性能瓶颈。我们在社交平台项目中遇到过网关转换消耗15%CPU的情况最终通过以下方案优化多级缓存策略原始数据缓存缓存ProductDO等数据对象领域对象缓存缓存转换后的Product懒加载代理对不常用字段使用代理模式public class ProductProxy extends Product { private SupplierProductDetails detailsLoader; Override public ProductDetails getDetails() { if (super.getDetails() null) { super.setDetails(detailsLoader.get()); } return super.getDetails(); } }批量转换优化// 低效做法 ListProduct products productIds.stream() .map(gateway::getById) .collect(toList()); // 高效做法 ListProduct products gateway.batchGet(productIds);在Gateway实现内部批量转换可以利用并行处理和缓存机制大幅提升效率。我们的压测显示批量接口的吞吐量可达单条查询的8倍。7. 领域模型的进化策略优秀的领域模型不是一次性设计出来的而是随着业务认知不断演进的。我们采用三段式演进策略初期允许数据模型驱动领域模型快速验证成长期通过DDD的限界上下文划分明确模型边界成熟期引入领域事件保持模型间松耦合典型案例商品库存模型演进阶段数据模型领域模型驱动因素V1单库存字段Item.stock简单SKU管理V2分仓库存表WarehouseInventory多仓发货V3库存流水表快照InventoryAggregate InventoryLog库存预占与审计V4分渠道库存视图ChannelInventory区分线上线下渠道这种渐进式演进确保了我们既不错失早期市场机会又能支撑业务长期发展。关键在于始终保持数据模型与领域模型之间的明确界限——存储结构可以推翻重来但领域模型应该通过适配器平滑迁移。

相关文章:

别再让JSON字段毁了你的业务代码:从阿里商品中台案例看领域模型与数据模型的正确分工

领域模型与数据模型的分工艺术:从阿里商品中台实践看架构设计的本质 记得三年前接手一个电商促销系统重构时,我发现前任开发者将所有营销规则都塞进了一个名为promotion_rules的JSON字段里。当需要增加"限购地区"功能时,团队直接在…...

2026年OpenClaw阿里云8分钟云端集成零基础部署及使用教程【超详细】

2026年OpenClaw阿里云8分钟云端集成零基础部署及使用教程【超详细】。如何集成OpenClaw?还在为部署OpenClaw到处找教程踩坑吗?别再瞎折腾了!OpenClaw一键部署攻略来了,无需代码、只需两步,新手小白也能轻松拥有专属AI助…...

Dify医疗问答上线前最后72小时:必须完成的4层语义一致性验证(含Jieba+UMLS双引擎比对模板)

第一章:Dify医疗问答上线前最后72小时:必须完成的4层语义一致性验证(含JiebaUMLS双引擎比对模板)在Dify医疗问答系统正式交付前的72小时内,语义一致性验证是阻断临床术语误释、规避医患沟通风险的核心防线。我们采用四…...

图像图片照片风格转换API接口介绍

前言 在日常工作生活中,我们可能会需要将图片转化风格后再使用,比如把自己拍的照片转换成铅笔画。图像风格转换可以帮我们实现此功能,还可用于开展趣味活动,或集成到美图应用中对图像进行风格转换。 图像风格转换可将原始图像转…...

告别objdump!用Python的pwntools一键生成汇编对应的hex机器码(附Mac/Linux安装避坑)

告别objdump!用Python的pwntools一键生成汇编对应的hex机器码(附Mac/Linux安装避坑) 在二进制安全研究和CTF竞赛中,快速将汇编指令转换为机器码是每个从业者的基本功。传统方法依赖gcc或nasm配合objdump工具链,不仅步骤…...

拯救者R7000用户看过来:保姆级教程,让你的非华为笔记本也能和MatePad Pro多屏协同

拯救者R7000与MatePad Pro多屏协同实战指南 作为一名长期使用联想拯救者R7000的游戏玩家兼生产力工具爱好者,我最近入手了华为MatePad Pro平板,却被一个现实问题困扰:如何让这台非华为笔记本与华为平板实现真正的多屏协同?经过两周…...

Xiaomi Cloud Tokens Extractor:解锁智能设备管理新维度的安全密钥提取工具

Xiaomi Cloud Tokens Extractor:解锁智能设备管理新维度的安全密钥提取工具 【免费下载链接】Xiaomi-cloud-tokens-extractor This tool retrieves tokens for all devices connected to Xiaomi cloud and encryption keys for BLE devices. 项目地址: https://gi…...

Java排序不止Comparator.comparing:用reversed()和thenComparing构建复杂排序规则(附完整代码示例)

Java排序不止Comparator.comparing:用reversed()和thenComparing构建复杂排序规则(附完整代码示例) 在电商订单管理后台,我们经常需要先按订单金额降序排列,金额相同的再按下单时间升序排列;在人力资源系统…...

从CAD老手到中望3D新手:快速上手的草图绘制习惯迁移与效率技巧

从CAD老手到中望3D新手:快速上手的草图绘制习惯迁移与效率技巧 作为一名有AutoCAD或SolidWorks经验的工程师,第一次打开中望3D的草图模块时,那种既熟悉又陌生的感觉可能会让你有些无所适从。图标位置不同了,命令名称变了&#xff…...

别再折腾WSL2了!Windows 10/11一键搞定Docker Desktop安装(附保姆级排错指南)

Windows开发者必备:Docker Desktop极简安装与高效排错全攻略 每次打开Docker Desktop时那个转个不停的鲸鱼图标,是不是让你血压飙升?作为常年与Windows系统打交道的开发者,我完全理解那种看着教程一步步操作却卡在WSL2配置环节的崩…...

国内业界首个AI一键生成手绘思维导图的脑图产品来!万兴科技旗下万兴脑图重磅焕新

4月18日至19日,2026世界思维导图暨快速阅读锦标赛博赞思维导图大师挑战赛在成都举办。本届赛事由世界思维导图理事会(WMMC)中国区组委会主办。WMMC由思维导图发明者托尼博赞创立,致力于在全球范围内推广思维导图教育与应用&#x…...

GD32F407 USB CDC虚拟串口调试实战:从枚举失败到稳定收发数据的避坑指南

GD32F407 USB CDC开发实战:从设备枚举到数据收发的深度排错手册 当你的GD32F407开发板通过USB线连接到电脑,却始终无法在设备管理器中出现那个期待的"USB串行设备"图标时,这种挫败感每个嵌入式开发者都深有体会。本文将以一个真实的…...

python+requests实现的接口自动化测试

🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 框架详细教程前段时间由于公司测试方向的转型,由原来的web页面功能测试转变成接口测试,之前大多都是手工进行,利用postman和jme…...

draw.io桌面版架构解析:基于Electron的跨平台图表编辑实现

draw.io桌面版架构解析:基于Electron的跨平台图表编辑实现 【免费下载链接】drawio-desktop Official electron build of draw.io 项目地址: https://gitcode.com/GitHub_Trending/dr/drawio-desktop draw.io桌面版是基于Electron框架构建的专业图表编辑工具…...

甲方爸爸要的PPT展示功能,我用Unity3d + Aspose.Slides搞定了(附打包避坑指南)

Unity3D与Aspose.Slides实战:高效集成PPT展示功能的完整方案 当甲方提出"在Unity项目中嵌入PPT展示"的需求时,许多开发者第一反应可能是寻找现成的插件或考虑导出为图片序列。但真正经历过项目交付的老手都知道,这两种方案要么功能…...

从零到一:三极管功放电路实战设计与关键参数剖析

1. 三极管功放电路设计基础 三极管功率放大电路是电子工程师必须掌握的核心技能之一。我第一次接触三极管功放是在大学电子设计竞赛时,当时需要驱动一个8Ω扬声器,但成品功放模块价格昂贵且参数固定,于是决定自己动手设计。三极管功放看似简单…...

从相位缠绕到高程图:InSAR干涉测量核心原理全解析

1. InSAR技术初探:从雷达回波到三维地表 第一次接触InSAR技术时,我被它神奇的能力震撼到了——居然能用卫星拍的照片算出地面的高度变化!这就像用普通相机拍两张照片,就能测量出建筑物的精确高度一样不可思议。InSAR全称是干涉合…...

STAP旁瓣干扰抑制:从原理到对抗仿真的实战解析

1. STAP技术入门:空时滤波的降噪艺术 想象一下你在嘈杂的鸡尾酒会上试图听清某个人的谈话。传统方法就像用手捂住一只耳朵(空域滤波),而STAP技术则是同时用手捂住耳朵并配合对方说话的节奏点头(空时联合滤波&#xff0…...

哔咔漫画下载器终极指南:打造个人离线漫画图书馆的简单方法

哔咔漫画下载器终极指南:打造个人离线漫画图书馆的简单方法 【免费下载链接】picacomic-downloader 哔咔漫画 picacomic pica漫画 bika漫画 PicACG 多线程下载器,带图形界面 带收藏夹,已打包exe 下载速度飞快 项目地址: https://gitcode.co…...

STC15单片机驱动LCD12864显示汉字和图片,串行接口比并行接口省多少IO口?

STC15单片机驱动LCD12864显示:串行接口如何极致节省IO资源 在嵌入式设备开发中,IO口资源常常成为制约功能扩展的瓶颈。以STC15W408AS驱动LCD12864液晶屏为例,当我们需要在小型温湿度计或仪表中实现汉字和图形显示时,串行接口相比并…...

imFile下载管理器深度解析:为什么它能成为你的全能下载解决方案?

imFile下载管理器深度解析:为什么它能成为你的全能下载解决方案? 【免费下载链接】imfile-desktop A full-featured download manager. 项目地址: https://gitcode.com/gh_mirrors/im/imfile-desktop 你是否曾经为下载大型文件而烦恼?…...

告别依赖地狱!Ubuntu 20.04/22.04 安装 ITK-SNAP 3.8.0 最全避坑指南(含libpng12终极解决方案)

医学影像处理利器:Ubuntu系统ITK-SNAP 3.8.0安装全攻略与疑难解析 在医学影像研究领域,ITK-SNAP作为一款开源的图像分割与可视化工具,凭借其强大的功能和友好的交互界面,成为众多科研工作者的首选。然而,当我们在较新…...

TRNSYS新手入门:从零开始搭建你的第一个建筑能耗模型(附Type56模块详解)

TRNSYS新手实战指南:Type56建筑能耗建模全流程解析 第一次打开TRNSYS时,面对数百个模块图标在画布上铺开,那种手足无措的感觉我至今记忆犹新。作为建筑能耗模拟领域的工业级软件,TRNSYS的强大之处恰恰在于其模块化设计——但这也成…...

3分钟完成Windows和Office激活:KMS_VL_ALL_AIO智能激活工具终极指南

3分钟完成Windows和Office激活:KMS_VL_ALL_AIO智能激活工具终极指南 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为Windows系统频繁弹出激活提示而烦恼吗?Office文…...

别再手动调间距了!用Matlab的tiledlayout函数搞定论文级多图排版(附代码)

告别繁琐排版:用Matlab tiledlayout打造学术级多图布局 还在为论文中的多图排版焦头烂额?每次调整subplot位置都要耗费半小时?Matlab R2019b引入的tiledlayout功能彻底改变了这一局面。这个被严重低估的工具,能让你的科研图表排版…...

nanobot保姆级教程:Qwen3-4B tokenizer分词结果可视化、special token作用解析

nanobot保姆级教程:Qwen3-4B tokenizer分词结果可视化、special token作用解析 1. 引言 如果你正在使用大语言模型,尤其是像Qwen这样的开源模型,有没有好奇过模型到底是怎么“读”懂你输入的文字的?为什么有时候你输入一个词&am…...

别再只用箱线图了!用R的Raincloud Plots(云雨图)可视化你的纵向数据,附完整代码

用R语言打造科研级纵向数据可视化:云雨图全流程解析 第一次在学术会议上看到那张融合了散点、箱线和小提琴图的幻灯片时,我正被自己单调的柱状图折磨得昏昏欲睡。那张图表像有魔力般,既展示了整体分布规律,又保留了每个受试者的个…...

PADS页面连接符更新失败?手把手教你解决原理图更新问题(含GND/PWR符号)

PADS页面连接符更新失败?手把手教你解决原理图更新问题(含GND/PWR符号) 在PCB设计流程中,原理图设计是至关重要的一环。作为行业标准工具之一,PADS Logic凭借其强大的功能和稳定的性能赢得了众多工程师的青睐。然而&am…...

MATLAB三维散点图进阶:scatter3函数参数详解与实战可视化技巧

1. scatter3函数基础:从零开始绘制三维散点图 第一次接触MATLAB的三维可视化功能时,我被scatter3函数的强大震撼到了。这个函数就像是一个三维空间的魔法笔,能够把枯燥的数据点变成直观的空间分布图。记得当时处理一组流体力学实验数据&#…...

服务器该如何防范网络攻击?

服务器作为网络系统的核心枢纽,存储着大量关键数据并支撑着各类业务运行,一旦遭受网络攻击,可能导致数据泄露、服务中断等严重后果。防火墙是服务器网络安全的第一道防线,它可以根据预设的规则,对进出网络的数据包进行…...