
1. 三种建模到底是什么先搞清楚它们各自解决什么大概三年前我在一次项目评审会上被问到这个模块的建模怎么做结果产品、算法、后端三拨人各说各话产品在讲订单状态怎么流转算法在讲配送时长怎么预估后端在讲服务怎么拆分整场会开了两个小时也没对齐。从那以后我才真正意识到建模这个词在不同人嘴里根本不是一回事——领域建模、数学建模、架构建模名字里都带建模但解决的问题、服务的对象、产出的东西完全不同。这篇文章就用一个贯穿始终的实例——外卖配送平台——把三种建模分别拆开讲一遍再用同一个例子把它们串起来。适合的人群很明确对软件工程有一定了解但概念容易混淆的开发者、刚入行的产品经理、以及写论文时需要做建模但搞不清楚该选哪种建模方法的同学。1.1 三种建模的核心判断标准要区分三种建模不要从定义入手要从它回答什么问题入手。建模类型回答的问题核心产出物主要使用者评判标准领域建模这个业务里有哪些概念、规则、状态业务词汇表、实体关系、业务规则业务专家、产品经理、开发是否真实反映了业务本身数学建模如何用数字和公式描述问题并求得最优解目标函数、约束方程、算法方案算法工程师、数据分析师是否可量化、可求解、可验证架构建模系统在技术层面如何组织才能稳定且可演进模块划分、依赖关系、数据流、部署方案架构师、开发工程师、运维是否平衡了当前需求与未来变化判断一个建模属于哪种最直接的办法就是问自己如果我拿着这个模型去找业务专家他能看懂吗如果他能看懂并确认对这就是我们的业务逻辑那是领域建模。如果这个模型是一组数学公式业务专家看不懂但算法工程师能据此实现一个调度算法那是数学建模。如果这个模型画的是系统模块和服务依赖只有技术人员能看懂那是架构建模。1.2 它们不是三选一而是三个维度的投影很多人会问做项目时到底该做哪种建模答案是一个正经项目通常三种建模都需要只是在不同阶段、由不同角色主导。你可以把同一件真实世界的事看成一块不规则的多面体三种建模都是对这个多面体的投影。领域建模投影的是业务规则面数学建模投影的是可量化计算面架构建模投影的是技术实现面。它们各自简化掉一部分细节才能让特定角色专注解决特定问题。明白这一点再往下走就不容易把三种建模搅在一起了。下面用同一个外卖场景把三套建模完整地做一遍。2. 用外卖配送场景做一次完整的领域建模现在假设我们要做的是一个外卖配送平台。业务不算特别复杂但也足够典型顾客逛商家、下单、支付、商家出餐、骑手取餐配送、顾客确认收货、平台结算。要做领域建模第一步不是画图而是把业务语言收集齐、定义清楚。2.1 领域建模的产出物业务词汇表与边界领域建模的第一步是建立一份业务词汇表。这听起来很基础但绝大多数项目不做或者做得很随意导致开发里的命名五花八门——有人叫订单有人叫单子有人叫order还有人把待支付和待接单混在一起一聊天就对不上。我整理出的外卖平台核心词汇大致是这样顾客下单、取消、支付、评价的主体商家上架商品、接单/拒单、出餐、发起退款的主体骑手接单、取餐、送达的配送执行者订单贯穿整个业务生命周期的核心实体结算单订单完成或取消后平台与商家/骑手之间的财务记录配送费根据距离、时段、天气等因素计算出的配送服务价格词汇一旦确定后续的系统命名、数据库表名、接口字段名都应该尽量沿用这些词不要另造新词。这是领域建模最容易体现价值的地方——它不是画几张好看的关系图而是建立一套让业务和技术通用的普通话。2.2 实体之间不是画线而是建立业务动词画实体关系图时大部分人喜欢画方框和连线但仅仅画出顾客 下单 订单这种箭头信息密度太低。真正有经验的领域建模会特别关注连线上那些动词因为动词背后才是业务逻辑。我还原一下外卖平台里最核心的几个业务动作顾客创建订单订单初始状态是待支付此时订单还不算真正生效。顾客支付订单支付成功后订单状态变为待商家接单。商家接受或拒绝订单接受则进入商家备餐拒绝则订单取消并自动退款。骑手接单接单后进入待取餐骑手到店取餐后变为配送中。顾客确认收货或系统自动确认订单进入已完成。订单取消可以由顾客发起、商家发起、平台超时自动触发。如果你只画实体和连线你看不出这些状态约束但你把动词写清楚业务规则就浮出水面了。比如取消不是任何时刻都能做——已出餐的订单取消需要商家同意已配送的订单取消会触达骑手和赔付逻辑。这一步的实际产出是一份带行为动作的领域图。领域建模面对的是业务语言它关心的不是数据库外键不是算法效率而是这个业务世界里到底有哪些事会发生、按什么顺序发生、受什么条件限制。2.3 业务规则才是领域模型的灵魂如果说词汇和实体是骨架业务规则就是血液。同一个外卖平台如果业务规则不同领域模型会完全不同。规则一普通订单在下单后15分钟内可以无责取消超时取消则要按距离收取违约金。这条规则直接影响订单状态机的设计——状态待支付和待接单必须区分开否则无法判断取消的时机。规则二商家出餐超时20分钟系统自动改派骑手原骑手不再对该订单负责。这条规则会引出改派事件出餐倒计时骑手与订单的松耦合关系等设计点。规则三平台对超时送达的用户给予赔付赔付金额由配送时长差值决定。这条规则会导致领域模型中增加赔付单实体而且引入预计送达时间这个业务概念。我见过不少团队做领域建模时就画四五个实体、几条连线然后直接进入数据库设计结果业务方一细问就漏洞百出。真正合格的领域模型做完以后应该能拿给业务方看让他用手在图上走一遍下单到收货的完整流程并且挑不出毛病。这一步做到了后面做数学建模和架构建模才有一块坚实的地基。3. 同一场景下的数学建模把派单优化做成可算的数字领域模型让我们知道了业务世界有哪些要素和规则但外卖平台的核心竞争力之一是怎么把订单高效地派给骑手。这个问题已经不是有哪些实体能回答的了它需要数学建模把配送效率抽象成目标函数和约束条件然后设计可计算的求解方法。3.1 从模糊目标到明确的目标函数派单要高效这个说法没法计算。数学建模要做的第一件事就是给高效一个可量化的定义。常见的目标函数有两种选择最小化平均送达时长公式表达为min (ΣT_i)/NT_i代表第i个订单从下单到送达的时长N为统计周期内订单总数。最小化超时率也就是min (超时订单数/总订单数)这会重点关注那批最危险的订单。实际做派单策略时通常不是只盯一个指标。更通用的做法是定义一个加权得分比如成本评分 w1×预计配送时长 w2×骑手空驶距离 w3×预计超时惩罚 - w4×顺路奖励。这里的w1到w4是权重怎么定不能拍脑袋要靠历史数据回归或者人工设定后做AB实验。我一直觉得权重参数的确定本身就是一个小型数学建模问题它需要你定义清楚时长、空驶、超时这三者对业务损失的相对大小。3.2 约束条件怎么量化有了目标函数还不够真实世界有一堆边界条件也就是约束。数学建模如果不把约束写清楚求出来的最优解在现实中根本不可行。对外卖派单场景我把常用约束列成了一张表约束项数学表达业务含义骑手同时在途订单上限每个骑手并行订单数 ≤ 3防止骑手接太多单导致整体超时配送距离上限骑手与商家的距离 ≤ D_max超出范围取餐时间不可接受骑手载具能力电动车、汽车不同载具速度不同影响预计送达时间商家出餐时间出餐时长估计 E_i影响取餐时刻不能只看配送距离服务时间窗用户期望送达时间 [L_i, R_i]超时会有赔付和差评成本约束不是越多越好每加一个约束求解难度都会上升。初学者做数学建模最容易犯的错就是试图把现实中所有细节都塞进模型。技术上的正解是先把最关键的3到5个约束放进模型让模型先跑起来再逐步增加约束观察求解时间和效果变化。3.3 可落地的求解思路与模型验证外卖派单的数学模型求解方法非常多取决于规模。如果你只是做一个课程设计级别的Demo用贪心分配就够了每个新订单到达时计算所有可用骑手的得分把订单派给得分最高的那个每30秒做一次批量滚动分配。如果你要做一个稍微认真点的版本可以把问题建模为带权二分图最优匹配订单作为一侧节点骑手作为另一侧节点边权就是上面那个加权得分然后用匈牙利算法或最小费用流求解。这种方法的优势是能考虑全局最优而不是单个订单局部最优。但需要注意的是它要求订单和骑手数量都不能太大否则计算时间会失控。我实际做的时候采取的折中方案是先按商圈把骑手和订单分成若干组每组内订单量控制在20以内然后组内用匈牙利算法求解。这样既保证了实时性又比纯贪心效果好。模型做完必须验证不能只在训练集上看数字。至少要做三件事一是用历史数据回放对比模型推荐方案和人工实际派单方案的送达时长二是做仿真把不同时段的订单流灌进模型看超时率是否超标三是小流量上线拿真实业务AB测试。数学模型永远是现实的简化没有经过真实数据验证的模型再漂亮也只能停留在论文里。4. 再把同一个场景做架构建模系统怎么组织才能长期演进业务规则搞清楚了派单算法也想明白怎么算了接下来才是技术人最熟悉的环节——架构建模。架构建模处理的不再是业务怎么运转而是系统在技术层面如何组织。这一步做得好不好直接决定这个平台后续加功能、扛流量、修故障的时候是轻松还是痛苦。4.1 模块划分的出发点领域边界与业务生命周期架构设计最忌讳一上来就画微服务架构图。正确的做法是先回到领域模型找到自然的业务边界。在外卖场景里我划分模块的依据有两个一是领域模型里的核心实体和业务规则边界二是业务生命周期的不同节奏。按这个思路外卖平台可以拆分为以下核心模块用户端服务顾客注册、登录、地址管理、下单入口。商家端服务商家菜单管理、接单/拒单、出餐状态同步。骑手端服务骑手接单、取餐确认、送达上报。订单中心订单的创建、状态流转、取消与改派逻辑。这是整个系统最核心的模块。派单引擎承载上一章说的数学建模算法输入订单和骑手位置输出派单建议。结算中心配送费计算、商家结算、骑手佣金、赔付单处理。营销中心优惠券、满减、会员体系。这些逻辑和核心交易链路无关独立成模块。模块划分完要关注的不是我分了几个模块而是边界是否清晰。订单中心和结算中心之间只通过订单完成事件通信而不是让结算逻辑直接操作订单表。派单引擎不关心用户用没用优惠券只关心这单要从哪里送到哪里、什么时候能取到餐。4.2 依赖方向与数据流转的硬约束架构建模中模块间依赖方向是我每次评审必问的问题。好的架构模块依赖应该形成单向的层次结构上层可以依赖下层下层绝不能反向依赖上层。比如用户端服务和商家端服务都依赖订单中心但订单中心绝不能反向调用用户端服务去查用户是否会员。如果需要会员信息应该由用户端服务把必要的身份信息带在请求里或者订单中心通过事件订阅获得一份数据副本。还有一条重要原则能异步的不要同步。订单创建后营销中心需要知道订单完成才能发积分、结算中心需要订单完成才能触发结算但这些都不需要在下单请求的响应链路里完成。正确的做法是订单中心发一个订单完成事件营销中心和结算中心各自订阅处理。这样即使结算服务临时故障也不会影响用户下单主流程。数据存储也需要建模。订单表的数据量会非常大按订单ID分库分表几乎不可避免派单引擎需要快速读写骑手实时位置适合用缓存结算数据对一致性要求极高必须放在事务性强的存储里。架构建模要画出这些数据流而不是只画几个方框表示模块就完事。4.3 体量不同架构建模的尺度完全不同架构方案永远不能脱离规模谈。我见过不少团队照抄大厂的微服务架构结果日订单量只有几千服务拆了二十来个连排查一个问题都要翻五六个系统的日志。如果你服务的体量是日订单一千单做单体应用加一个独立派单模块完全足够连消息队列都可以省略靠定时任务轮询搞定。如果日订单量到了十万级那订单中心、派单引擎、结算中心就值得拆开了引入消息队列做异步解耦也顺理成章。到了百万级这时候你不仅要拆服务还要考虑每个服务内部的读写分离、缓存策略、熔断降级、多活部署等架构建模的深度和复杂度就完全不同了。我做架构建模时有个习惯先写清楚当前体量再写清楚半年后的预期体量方案至少要在设计上能支撑三倍增长。超出三倍的规划不要提前做因为业务形态随时会变过度设计是架构腐化的第一根源。5. 三种建模在同一个项目里的协作顺序与产物映射到现在为止三种建模在一个外卖平台上各自怎么做的已经讲完了但实际项目中它们不是孤立开展的而是有明确的先后顺序和承接关系。5.1 推荐的建模顺序我会用一个三段式流程这也是我个人项目里反复验证过比较顺的顺序第一步领域建模先行。目标只有一个和业务方对齐这个世界的运行规则。这个阶段完全不考虑数据库、不考虑微服务、不考虑算法效率只回答业务上有什么、允许什么、禁止什么。产出物是业务词汇表、实体关系、状态机、业务规则清单。第二步针对关键瓶颈做数学建模。领域建模做完你会看到业务里最复杂、最需要决策的位置。对外卖平台来说就是派单和配送时长预估对电商来说可能是库存分配和定价对物流来说是路径规划。只有这些位置才值得动用数学建模其他普通位置用简单规则处理就好。第三步用架构建模承接前两者。架构建模不是凭空设计而是把领域模型里的边界翻译成技术模块界限把数学模型的输入输出定义成算法模块的接口。领域模型里的实体和规则决定了模块怎么拆数学模型决定了派单引擎的输入输出格式和性能要求。这个顺序不能乱。我见过一个项目先画架构图定好了服务边界然后才去了解业务结果发现订单状态流转和最初设计完全不一样架构返工。先架构后业务等于没看图就搭积木。5.2 三种模型互相对照产物如何映射到落地上三种建模的产物绝不是相互独立的三份文档它们之间存在清晰的映射关系。我把这个映射整理成了一张表领域建模产物数学建模产物架构建模落地订单实体与状态机订单状态变化时间点作为目标函数参数订单中心模块、订单状态字段与API设计配送费规则配送费计算作为数学模型的成本系数结算中心独立服务被订单和派单引擎调用出餐超时改派规则出餐时长作为调度约束输入派单引擎里的改派触发任务超时赔付规则超时惩罚项进入目标函数结算中心赔付单处理逻辑用户期望送达时间窗调度约束中的硬/软时间窗订单中心到派单引擎的接口字段拿出餐超时改派这一条举例你就明白了没有领域建模你根本不知道有出餐超时20分钟自动改派这条规则没有数学建模你不知道改派时该把哪些骑手列为候选、按什么打分没有架构建模你不知道出餐倒计时该由哪个模块维护、改派指令通过什么事件通道发给骑手端。三者一环扣一环缺一个整条链路就断掉了。6. 最常见的混淆与自查清单写到这里把三种建模的概念、实践和协作关系都过了一遍。最后我想把过去几年见过的高频混淆集中说一遍再给你一份动手前可以先自查的清单能帮你省下不少开会吵架的时间。6.1 常见混淆第一种混淆是把领域建模当成画数据库表。领域模型里的实体和数据库表有对应关系但它们是两回事。领域模型里的订单包含业务行为和规则数据库表只是它的持久化形态。如果你画领域模型时满脑子都是主键外键、索引、字段类型你的图业务方一定看不懂这个模型就失败了。第二种混淆是想用数学建模解决业务规则问题。有人问订单取消规则怎么建模这本质是一个状态机规则描述问题不是数学问题。它该用领域建模的状态图来表达而不是套一个目标函数。数学建模只适合有好坏程度可以量化这类的决策问题不适合允许不允许这类规则问题。第三种混淆是认为架构建模一步到位。架构不是画完一张大图就固定不变了而是随着业务规模和技术演进而持续调整。日订单量一千的时候做微服务十有八九是灾难不是先进。架构建模要保持演进的眼光但绝不是越复杂越好。第四种混淆也是最普遍的是把三种建模放在同一个讨论里互相绑架。我参加过的评审会里产品拿着领域模型问为什么这个服务不在左侧算法拿着数学公式问为什么不按这个权重排序架构拿着部署图问这个规则怎么没有在接口里限制——每一项单独看都对但放在同一个时空里谁也说服不了谁。明确讨论当下属于哪种建模是我能给你的最实用的会议沟通技巧。6.2 动手前的自查清单无论你做的是哪种建模动手之前都可以按这份清单过一遍。也不用全对但至少要能回答其中大部分问题这个模型要解决的核心问题是什么目标是否单一且明确谁会消费这个模型他能否独立理解还是必须由你解释才能看懂如果是对业务的建模业务方能看懂并且会认可吗如果是对问题的数学描述目标函数和约束条件是否都能被数据验证如果你是做架构模块划分是否来自领域边界还是拍脑袋分的模块依赖是单向的吗有没有反向依赖方案里是不是塞进了当前根本用不上的复杂组件你能说出这个模型最简化的假设是什么以及这个假设什么时候会失效吗模型是否预留了变化空间而不是把所有细节都焊死拿这些问题去审视很多建模方案其实撑不过半轮追问就会露馅。建模不是画图比赛而是为决策服务的抽象——抽象对了后面的开发、算法、运维都轻松抽象错了后面每一步都在还债。我个人的做法是每次建模前先在白板左上角写一行小字标明本次是领域建模/数学建模/架构建模讨论过程跑偏了就指着那行字拉回来。看起来有点机械但非常管用。建模这件事真正难的不是技巧而是始终知道自己到底在解决哪一类问题。