2025上半年,最新 AI实践都在这!20+ 应用案例,任听一场议题就值回票价 了解详情
写点什么

大型网站复杂业务持续重构之道——全程领域建模实践

  • 2012-03-27
  • 本文字数:3161 字

    阅读完需:约 10 分钟

人物介绍:

Jack Chen ——“宠物商店”的首席架构架构师,拥有丰富的软件设计与建模经验,但对新生事物持怀疑态度。

王总——“宠物商店”的总经理,从美国留学后回国创立“宠物商店”网站。一路来唾手可得的成功让他养成了固执专横的行事作风。

Spark —— Jack Chen 的大学同学,一家商业软件公司的高级咨询顾问。最近热衷于宣扬“领域驱动设计”的最佳实践。

引子

就象大家所听说过的那些神奇小子创业故事一样,几只从大西洋游回的海龟找到了一个伟大的 idea——在互联网上开办在线商店销售宠物。幸亏的是他们找到了投资者而且发展的很不错。但是随着时间的推移,当初“完美”的技术架构随着越来越多的装进篮子的需求后变得不堪重负。作为公司首席架构师的 Jack Chen 已经被这几个月“鸡毛蒜皮”的需求折磨失眠好几天啦。

Jack Chen 周一一早就被兴奋的王总给喊进了办公室,立即就被王总扔出来的 idea 吓傻了。

“我有一个很 cool 的想法,我们可以在线为宠物医院提供在线预约的服务业务。而不仅仅是卖掉它们,你知道这意味着什么吗?这是一个年产值上百亿的市场!!!”。

“可是王总,我们的系统不能支持这种非实物的服务预订销售,它可能对我们原有的网站形成巨大的冲击,我们需要三个月的时间对这个业务进行全方面的评估…”

Jack Chen 立即就被气势汹汹的王总打断了,“三个月的评估?我需要在两个月内就给我上线这个新业务。我们的投资人非常认可我的 idea,并要求我们立即把这个项目上线,它可能会帮助我们提高明年的 IPO 价格。你明白吗? DO IT ASAP!”

评估

“好吧,也许这个该死的王胖子是对的。我们这个将技术与业务混在一起的乱摊子也是到了该整理整理的时候。”自言自语发了半小时牢骚后的 Jack Chen 终于恢复到正常状态上来了,我想我应该看看我们现在是什么样子的,为了支持这个该死的“在线为宠物医院提供在线预约的服务”的需求我们需要做出哪些改变。于是 Jack Chen 在白板上很快的就画出了下面的 Use Case 图来。

图 1 原宠物商店 UseCase 汇总图

为了支持“在线预约”这种特殊的产品,它会影响到大部分的 Use Case,具体列举如下:

  1. 商品信息需要增加“预约时间”这个属性,客户在下订单时会把它作为标识一个预约的关键要素。
  2. “在线预约”是个虚拟的商品,它可不需要真的需要去检货和包装发货,如果真的那么做啦,我就太傻了。
  3. 每个宠物医院每天都只能接受一定数量的预约,从这个概念上来说,它与实物商品有类似的库存概念。可是我该怎么去表达它们呢?
  4. 最要命的是:我真的要把这些所有受影响的 Use Case 都翻出来去让它们支持虚拟物品的业务吗?我怎么可能在 2 个月内完成这些重构?

银弹

了无生趣的 Jack Chen 在王总的办公室门口徘徊了 N 圈,还是没有勇气去迎接那一通狂风暴雨般的中英文双语版的羞辱谩骂。“也许事情是有转机的,我好象在哪里听说过有种银弹可以解决这种系统重构的问题的”。“该死,谁把 Spark 送给我的《领域驱动设计》垫在显示器下啦,他一直在向我布道这本书给他的项目带来的种种神奇改变,也许我也可以试试它的威力”。

“好吧,Spark,我承认你给推荐的书非常棒,你说的也很有道理。我读了它,明白并一些概念——例如:领域分割 、Entity、Service、Value Object…,可我对于该如何去做还是一头雾水。你能不能直接把你从重构项目中获得的最佳实践直接分享给我呢?不然的话,周一王胖子是不会放过交不出答案的我的!”。读完了这本书,Jack Chen 觉得很有收获,但又不知道怎么开始,打个电话给领域建模的先行者Spark 也许真的是解决问题最快的方法。

“什么,这个问题说来话长?不要紧,我已经在你家门口了,你同我慢慢说”,Jack Chen 带着星巴克咖啡+ 肯德基全家桶+ 久久鸭脖+ 谄媚的笑容出现在Spark 家门口。

布道

Spark 听完了 Jack Chen 对于现状及需求的描述之后,一幅气定神闲的样子讪讪地说出“这个很简单嘛,你现在需要做的只是这样一些事情:”

  1. 用大比例结构对你的系统进行领域划分
  2. 找出这个需求影响的领域及对外接口
  3. 建立一个适合你们公司的领域驱动设计的技术框架
  4. 按照需求的紧急度来重构各个领域的设计与编码

下面我们就按照这个顺序来实践一下:

一、概要领域划分

Jack Chen 立即把自己之前画的 Use Case 重画了一遍,然后用希冀的眼神看着 Spark 等待着认可。“你的错误是过于看重 Case 或者操作者身份,领域的划分不是基于功能或角色来进行的,通常来说我们是将内聚程度较高的 Use Case 归到一个上下文中。尽量使得领域自闭程度较高,并拥有相同的业务语言环境。例如基于你的 Use Case 图,我会画出以下的领域”

图 2 宠物商店领域通道图

通道图是一个对业务领域建模非常有帮助的工具,它可以同时表达出执行序列与分片的作用。

二、找出受影响的领域与接口

从领域的角度来看,只有商品对外暴露出来的接口是会影响到各个领域,需要优先建立商品领域(ProductDomain)及读取商品信息服务接口(GetProductService)来进行重构。

之外,在【图 2】 中用绿色标识出来的 Use Case 是由于增加支持“在线预约”这种虚拟商品所需要进行代码重构的部分。这部分工作如果工期比较紧,可以优先使用模式的方式来进行代码重构,这样也可以在之后更加容易用领域驱动设计的方法再次重构。

三、建立技术框架

这一点,是《领域驱动设计》这本书没有过多提及的内容。这个需要结合你们公司的原来技术框架用最小化改造成本最大化收益的方式来建立领域驱动的技术框架。下面是一个可以广泛使用的领域驱动的技术框架,可以在这之上增加更多的个性元素形成你公司自己的框架。

图 3 领域驱动设计参考技术框架图

这个框架的各个元素基本上在 《领域驱动设计》一书中都可以找到对应的解释,但这里需要解释一下我建立这个框架的个性理解:

  1. 领域对外(页面、AJAX、ESB 调用)只暴露领域服务,其它所有领域类都是包内自闭的,对外不可见。
  2. 基础仓库的引入,基础仓库是一个抽象的仓库,它封装了大量常用工具方法、业务对象生命周期维护(实体 OR 映射、DAO 调用)、外部接口调用。可以降低业务仓库不必要的重复编码与复杂性。业务仓库是继承基础仓库的子类。
  3. 基础设施的引用,基础设施是用来承载引用非领域调用的桩,我们在使用领域驱动设计的时候往往是从一个旧的系统重构开始。这时我们不可能要求所有的业务子系统相互调用都通过 Domain Service 调用,这时我们可以通过 Infrastructure 优美的把调用封装在业务仓库的业务方法内。

四、重构受影响领域的设计与编码

图4 重构后的商品详情页类图

Spark 以商品详情页这个 Use Case 为例展示了以领域驱动设计的重构类图:

  1. 增加行为表 ProductExt 用于存储商品的扩展信息,如预约时间段、预约医院。并为表建立一一对应的实体 Entity。
  2. 基础仓库 Repository 通过 Infrastructure 中的 DAO 封装了对实体的操作,如 create()、update()、delete()、findById()、findList()
  3. 商品业务仓库 ProductRepository 扩展了基础仓库,客户程序可以用 productId 为参数,通过 ProductVo.getProduct() 方法获得商品详细信息的业务实现,由于业务仓库的的公开方法对外返回的都是 Value Object,因此不会直接暴露 Entity 类型给客户程序
  4. GetProductService 服务类通过 invoke() 服务方法 对外(商品详情页面)提供服务,它通调用业务仓库中的业务方法,并将接口规格化。
  5. 事务配置在 DomainService 的 invoke() 方法上,即事务控制以 Use Case 为粒度进行控制。

尾声

在 Spark 的帮助下,Jack Chen 成功的脱离了困境。现在他正在公司里积极推行自己的领域驱动设计框架,他们公司的网站正在以每三周一次的重构速度快速迭代演进。他象 Spark 一样,成为了一个领域驱动的布道者。


感谢郑柯对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2012-03-27 00:0010575

评论

发布
暂无评论
发现更多内容

11Labs 发布 MCP 服务器,在 Claude 秒建语音智能体;通义开源 3D 数字人,集成实时互动对话全链路 SDK

声网

zk基础—zk实现分布式功能

不在线第一只蜗牛

分布式

CAD"二维多段线"出现原因

极客天地

PHP开发效率提升利器:通义灵码在VSCode中的应用与技巧

阿里巴巴云原生

php #云计算

CrossOver玩游戏兼容性怎么样?CrossOver无法运行游戏怎么办?

阿拉灯神丁

游戏 兼容性测试 M2芯片 CrossOver Mac下载 Mac电脑软件

JavaScript AI 通义灵码 VSCode插件安装与功能详解

阿里云云效

JavaScript 云计算

一键美化PPT的AI工具怎么用?PPT自动美化全攻略!

职场工具箱

人工智能 效率工具 PPT AIGC AI生成PPT

文本情感分析预处理教程:从数据采集到可视化

电子尖叫食人鱼

数据库 数据分析

CAD怎么进行图纸间复制粘贴

极客天地

区块链智能合约的安全性

北京木奇移动技术有限公司

智能合约 区块链技术 软件外包公司

为什么学习设计模式?

电子尖叫食人鱼

学习 设计模式

腾讯Bugly:当AI大模型为鸿蒙应用体验注入「智慧基因」

新消费日报

安全的企业局域网聊天工具哪个好用?

BeeWorks

即时通讯 IM 私有化部署 企业级应用

TON生态游戏开发全攻略:Web3超级入口的实战指南

区块链软件开发推广运营

交易所开发 dapp开发 链游开发 公链开发 代币开发

AidaV2荣获全球DEAI黑客松奖项,革新去中心化金融生态

科技汇

【双周会】就在今晚,Apache SeaTunnel Community Call 会议通知

Apache SeaTunnel

AI 编程时代的核心驱动力 ——iVX 平台的创新实践与未来展望

代码制造者

无代码

JavaScript AI 通义灵码 VSCode插件安装与功能详解

阿里巴巴云原生

JavaScript

私有化IM即时通讯,稳定安全的企业内部聊天软件BeeWorks

BeeWorks

即时通讯 IM 私有化部署 企业级应用

Web3游戏全栈开发实战指南:智能合约与去中心化生态构建全解析

区块链软件开发推广运营

交易所开发 dapp开发 链游开发 公链开发 代币开发

USDT支付系统开发,OTC承兑商支付系统开发

区块链软件开发推广运营

dapp 交易所开发 链游开发 公链开发 代币开发

2025年最新盘点:国内外70家主流低代码/零代码开发平台

优秀

低代码 零代码

PHP开发效率提升利器:通义灵码在VSCode中的应用与技巧

阿里云云效

php

Java AI智能编码助手:通义灵码安装和使用指南

阿里巴巴云原生

Java 人工智能 云计算

CAD多段线夹点编辑的方法

极客天地

HTML 开发者的智能助手:通义灵码在 VSCode 中的应用

阿里巴巴云原生

html 前端

2025杭州国际机器人展览会

AIOTE智博会

机器人展 智能机器人展 人形机器人展

Java AI智能编码助手:通义灵码安装和使用指南

阿里云云效

Java AI

CAD怎么将相连的线条合并

极客天地

Python并发总结:多线程、多进程与异步编程

不在线第一只蜗牛

Python Linux

JVM实战—频繁YGC和频繁FGC的后果

量贩潮汐·WholesaleTide

Java JVM

大型网站复杂业务持续重构之道——全程领域建模实践_架构_孙兵_InfoQ精选文章