大家好,我是十三。
很多系统在早期都看起来没什么问题。
需求来了,建表;接口来了,写 service;逻辑复杂一点,就多加几个 if-else;线上出 bug 了,再补几个判断。短期看,这种方式很高效,需求也确实交付了。但只要系统开始进入复杂区,你很快就会发现:
真正拖垮一个系统的,往往不是功能越来越多,而是你从一开始就用错了表达问题的方式。
同样是做业务系统,有的团队越做越顺,新需求只是扩展;有的团队越做越重,每个需求都像是在拆雷。很多人以为这只是代码质量、架构经验或者团队成熟度的差异,但在我看来,更底层的分水岭其实是:
这个团队到底是在“功能驱动写代码”,还是在“范式驱动做开发”。
今天这篇文章,我想系统聊透四个问题:
- 什么是范式驱动开发
- 它和设计模式、架构风格、DDD 到底是什么关系
- 它为什么决定了系统后期的复杂度曲线
- 在真实项目里,到底该怎么落地
一、什么是范式驱动开发?
先给一个尽量准确的定义:
范式驱动开发(Paradigm-Driven Development)是指:在进入具体实现之前,先识别系统的主要复杂性来源,再选择最适合承载这种复杂性的建模范式,并让代码结构、模块边界和演进方式围绕这个范式展开。
这句话有点长,但里面有三个关键词非常重要:
- 复杂性来源
- 建模范式
- 围绕范式展开实现
换句话说,范式驱动开发的核心不是“怎么写代码”,而是先回答:
这个问题,本质上应该被表达成什么?
它可能是:
- 一个状态流转问题
- 一个规则组合问题
- 一个领域边界问题
- 一个异步协同问题
- 一个读写职责分离问题
如果这个判断做错了,后面代码写得再勤奋,系统也会越来越拧巴。
所以范式不是“高级写法”,也不是“架构黑话”。它的本质是:你组织复杂性的第一原则。
二、先把边界说清:范式,不等于设计模式,也不等于技术框架
如果不把这几个概念切清,这篇文章很容易变虚。
1. 范式,不是设计模式
设计模式解决的是局部设计问题。
比如:
- 策略模式,解决一组算法可切换的问题
- 责任链模式,解决一串处理器解耦的问题
- 工厂模式,解决对象创建的问题
这些都很重要,但它们回答的是“这一段代码怎么组织”。
而范式回答的是更上一层的问题:
这个系统的主要复杂性,应该由什么结构来承载?
比如一个营销系统,真正的问题可能不是“策略模式怎么写”,而是:
- 它到底是不是一个规则系统?
- 规则之间有没有优先级、互斥、依赖关系?
- 规则是研发硬编码,还是商家可配置?
- 规则变化的频率,是否已经高到值得独立成规则层?
这就是范式层面的判断。
设计模式是战术,范式是战略。
2. 范式,不是架构风格
微服务、单体、六边形架构、分层架构,这些更偏向技术组织形式。
它们回答的是:
- 服务怎么拆
- 接口怎么隔离
- 依赖怎么反转
- 部署怎么组织
这些属于架构层面的选择。
但你就算用了微服务,也不代表你选对了范式;你就算做成单体,也不代表范式落后。
比如一个审批系统,哪怕是单体,只要你把“状态跃迁”和“节点规则”建模清楚,它依然可能比一个错误拆分的微服务系统更健康。
所以:
- 架构风格解决的是技术结构问题
- 范式选择解决的是业务复杂性表达问题
3. DDD 是一种重要范式,但不是全部
很多人看到这里会说:这不就是 DDD 吗?
只对一半。
DDD 确实是一种非常重要的范式,尤其适合复杂业务语义和边界冲突明显的系统。它强调:
- 统一语言
- 限界上下文
- 聚合边界
- 领域模型优先
但不是所有复杂性都来自领域边界。
有些系统的复杂性主要来自状态变化,比如审批流、工单流、履约流。
有些系统的复杂性主要来自规则组合,比如营销、风控、权限。
有些系统的复杂性主要来自事件协同,比如交易后链路、异步通知、库存同步。
这时候,DDD 可能只是其中一层,而不是全部答案。
所以我更愿意把 DDD 放在一个更大的框架下理解:
DDD 是范式库里的一个核心成员,但范式驱动开发关注的是“如何为问题挑选正确范式”,而不是默认所有问题都用 DDD。
三、为什么很多系统会越做越乱?
因为大多数不是被建模出来的,而是被需求一层层“糊”出来的。
我们看一个很典型的案例:活动系统。
第一阶段:需求很简单
产品说,做一个满 100 减 10。
于是代码很自然:
if order.Amount >= 100 {
discount += 10
}
这时候没有任何问题。
第二阶段:规则开始增加
接下来需求一个个来:
- 新用户首单额外减 5
- 某些类目不参与活动
- 优惠券和满减不能叠加
- 不同渠道活动不同
- 不同商家活动优先级不同
- 某些活动仅限会员
- 活动支持配置开始时间和结束时间
你会发现,系统的本质已经变了。
它不再是“算一个金额”的问题,而开始变成:
- 规则筛选
- 规则命中
- 规则冲突判定
- 规则优先级排序
- 规则组合执行
- 规则配置化管理
也就是说,它已经从一个“计算逻辑”问题,升级成了一个规则系统问题。
第三阶段:团队还在用旧范式写新问题
这时候,如果你还在原来的 service 里不断追加 if-else,最后就会出现典型后果:
- 规则散落在多个 service
- controller 里偷偷写了一部分校验
- 前端为了展示,又复制一遍规则判断
- SQL 里还有一部分过滤条件
- 配置表存在,但只是辅助,真正逻辑还在代码里
- 新增一种活动玩法,需要改五六个地方
最后最危险的不是“代码丑”,而是:
你已经说不清系统真正的决策逻辑在哪里。
这就是很多系统后期难维护的根本原因:
不是需求太复杂,而是系统还在用过去的范式承载今天的问题。
四、范式驱动开发,真正驱动的是什么?
我认为它至少驱动三个层面的决策。
1. 驱动你如何建模业务
先决定“这个系统世界由什么构成”。
还是以活动系统为例。
如果你把它理解成“订单金额加减法”,那系统核心就是一堆计算逻辑。
如果你把它理解成“规则决策系统”,那系统核心就会变成:
- 规则定义
- 规则条件
- 规则动作
- 规则优先级
- 规则冲突策略
- 规则执行链路
这两种理解都会写出能跑的代码,但后续演进成本天差地别。
2. 驱动你如何划边界
范式一旦不同,模块划分也会不同。
如果活动系统的主范式是规则驱动,那么通常就应该显式存在这些边界:
- 活动定义层
- 规则表达层
- 规则执行层
- 冲突裁决层
- 配置管理层
而不是只有一个庞大的 PromotionService。
所以边界不是随便分的,它应该服从主范式。
3. 驱动你如何演进系统
一个系统真正的考验,不是第一次做功能,而是第十次变更时还能不能稳。
范式选得对,新需求大多表现为:
- 新增规则
- 新增状态
- 新增事件
- 新增边界映射
范式选得不对,新需求就会表现为:
- 修改旧逻辑
- 入侵多个模块
- 补更多特判
- 引发一串回归风险
这就是为什么成熟团队看待“扩展性”时,关注点不在代码量,而在主范式是否稳定。
五、一个完整案例:活动系统为什么应该从 if-else 升级到规则驱动?
这一段我想讲具体一点,不然“可落地”容易落空。
1. 最初的问题表达方式
很多活动系统一开始都是这么起步的:
- 输入:订单、用户、渠道、商品
- 输出:优惠金额
- 实现:若干个 if-else
这在早期完全合理,因为需求少、规则少、变化慢。
2. 什么时候说明你该升级范式了?
当你出现以下现象时,说明它已经不再只是简单逻辑,而是规则系统:
- 同一订单可能命中多条活动
- 规则之间存在互斥、叠加、优先级
- 非研发角色要配置活动
- 活动规则变更频繁
- 新增玩法越来越像“配置组合”而不是“写新逻辑”
- 排查一个订单为什么享受了某优惠变得困难
这六条里,只要命中三四条,基本就该警觉了。
3. 规则驱动后,系统应该长什么样?
这时候你至少应该把核心抽象切出来。
规则定义
规则描述“什么条件下触发什么动作”。
例如:
- 条件:订单金额 >= 100 且用户是新客
- 动作:减 15
规则条件层
负责判断是否命中:
- 金额条件
- 用户标签条件
- 商品条件
- 渠道条件
- 时间条件
规则动作层
负责决定命中后的结果:
- 直减
- 折扣
- 赠券
- 包邮
冲突裁决层
负责处理规则之间的关系:
- 是否可叠加
- 谁优先
- 同类型取最大还是可累加
- 券和活动如何互斥
执行引擎
负责把“候选规则集合”变成“最终优惠结果”。
4. 范式升级带来的直接收益是什么?
不是“看起来高级”,而是四个非常实在的收益:
- 新增玩法更像加规则,而不是改旧代码
- 排查问题时更容易解释决策路径
- 配置化能力自然出现
- 研发、产品、运营可以围绕同一套规则语义协作
这就是所谓的“可落地”。因为它不是抽象变漂亮了,而是后续成本真的变低了。
5. 如果你不升级,会怎样?
系统通常会逐步出现以下症状:
- 规则散落在多个地方
- 线上 bug 多数来自特判冲突
- 一个需求改动带来多个链路回归
- 只有老员工知道哪里真正生效
- 配置平台越来越像“假配置”,因为核心逻辑还在代码里
当你看到这些现象时,实际上已经不是“要不要重构”的问题,而是:
你是不是一直在用错误范式拖着系统往前走。
六、怎么判断一个问题适合什么范式?
这是最关键的落地点。
我给你一个实用判断表。
| 主要复杂性来源 | 更适合的主范式 | 典型场景 | 关键信号 |
|---|---|---|---|
| 状态流转复杂 | 状态驱动 / 工作流驱动 | 审批、工单、履约 | 状态多、跃迁规则多、回退/撤销复杂 |
| 规则变化频繁 | 规则驱动 | 营销、风控、权限判定 | 条件组合多、优先级多、配置需求强 |
| 业务边界和语义冲突明显 | 领域驱动 | ERP、用户中心、交易域 | 同名概念跨团队含义不同、边界混乱 |
| 异步链路复杂 | 事件驱动 | 交易后处理、库存同步、通知 | 多系统联动、最终一致性、重试补偿多 |
| 读写诉求差异大 | CQRS / 读写分离 | 报表、搜索、运营分析 | 写模型稳定但读模型多样且重查询 |
| 流程线性且规则稳定 | 面向过程 / 简单分层 | 后台工具、小型内部系统 | 变化少、生命周期短、复杂度低 |
这个表最重要的不是“背答案”,而是建立一个习惯:
先看复杂性来自哪里,再决定让谁做主范式。
不是哪个范式高级就上哪个,而是哪个范式最贴近问题本质,就让它主导。
七、范式驱动开发,真正的落地步骤是什么?
我建议按五步走,比单纯讲理念更有效。
第一步:识别系统的主要复杂性
先不要急着建表和拆接口。
先回答:
- 系统最容易失控的地方在哪里?
- 复杂性来自状态、规则、边界、事件,还是查询?
- 哪一类变化最频繁?
- 哪一类错误最贵?
如果这个判断没做,后面就是盲开。
第二步:确定主范式,而不是堆多个范式
一个系统可以同时存在多种手段,但通常要有一个主范式。
比如:
- 活动系统,以规则驱动为主
- 审批系统,以状态驱动为主
- ERP,以领域驱动为主
- 异步交易后链路,以事件驱动为主
这一步的重点是:
主范式负责承载主要复杂性,其他范式只做辅助,不要互相抢地盘。
第三步:让代码结构体现范式,而不是只写在方案文档里
真正的落地一定要体现在代码上:
- 目录结构是否反映业务语义
- 状态变化是否有统一入口
- 规则是否有独立表达层
- 事件是否是显式对象
- 模型边界是否防止概念泄漏
如果你说系统是规则驱动,但规则还埋在 service 里,那不叫落地。
第四步:用新增需求验证范式是否成立
一个范式好不好,不能看第一次实现有多优雅,要看第 N 次迭代是否依然稳定。
你可以用这几个问题做验收:
- 新增一个规则,要改几个地方?
- 修改一个状态流转,会不会波及无关模块?
- 一个新人能否快速定位决策逻辑?
- 同一个业务概念,在系统里是否只有一个主表达?
- 问“为什么这个结果会这样”,系统能否讲清楚?
如果这些问题的答案都比较健康,说明范式大概率是对的。
第五步:持续观察“复杂性是否被关进笼子里”
范式驱动开发不是一次性决策,它需要持续验证。
真正好的范式会让复杂性:
- 集中
- 可解释
- 可扩展
- 可替换
而不是继续向 controller、service、SQL、前端逻辑四处泄漏。
八、怎么判断你是不是选错了范式?
这部分非常实用,因为很多问题不是不会做,而是做错了却没有意识。
如果系统出现下面这些症状,大概率说明范式没选准。
1. 新需求总是表现为“修改旧逻辑”
如果每次新增功能都要回头改一堆既有分支,那说明系统没有为变化预留正确表达空间。
2. 规则和流程散落在多个层级
controller 有一点,service 有一点,数据库有一点,前端还有一点。
这通常意味着系统没有明确“复杂性归属”。
3. 同一个业务概念出现多个版本
比如“订单状态”在订单服务、履约服务、前端页面里各有一套解释。
这往往是边界范式出了问题。
4. 系统能跑,但讲不清
最危险的系统不是报错多,而是“只能运行,不能解释”。
你问它为什么这样,它只能回答:“历史就是这么写的。”
5. 老员工离开后,改动成本陡增
如果系统高度依赖个别人的隐性认知,而不是显式模型,说明范式没有沉淀成结构。
这几个信号,本质上都在说明一件事:
你的复杂性没有被一个正确范式收束,而是在系统里自由扩散。
九、范式驱动开发,不等于一上来就搞大架构
这里我必须强调一个边界,不然这篇文章很容易把人带偏。
范式驱动开发不是过度设计的许可证。
不是所有系统都值得上“高级范式”。
如果你做的是:
- 生命周期很短的后台工具
- 逻辑稳定的小型内部系统
- 边界简单的单流程应用
那用简单分层、清晰对象、少量模式,往往就是最优解。
真正成熟的判断不是“上不上范式”,而是:
这个问题的复杂度,是否已经值得我引入更强的表达方式。
能用简单对象模型解决的,就不要先上规则引擎。
能用轻量状态机解决的,就不要一开始就上 BPM。
能在单体内划清边界的,就不要急着微服务化。
范式驱动开发的核心不是“重”,而是“准”。
十、从功能实现者到系统建模者,这是工程师认知层级的跃迁
为什么有些工程师写了很多年代码,依然停留在“接需求—写接口—改 bug”的循环里?
因为他的关注点始终停留在“功能怎么实现”。
而真正开始拉开差距的工程师,会习惯性地问:
- 这个需求背后重复出现的模式是什么?
- 它真正的复杂性来自哪里?
- 现在是在解决问题,还是在继续堆补丁?
- 这个系统最适合由哪种范式来主导?
这是一个非常重要的分水岭。
低阶开发,关注代码怎么写。
中阶开发,关注模块怎么分。
高阶开发,关注问题应该如何表达。
而我理解的范式驱动开发,本质上就是这最后一层能力。
总结
范式驱动开发,不是为了让系统看起来更高级,而是为了让复杂性有秩序地落位。
它真正回答的问题不是“这段代码怎么写”,而是:
这个系统里最复杂、最易变、最容易失控的部分,究竟应该由什么结构来承载。
当你把一个规则问题建模成规则系统,把一个状态问题建模成状态系统,把一个边界冲突问题建模成领域问题,你会发现很多原本靠补丁维持的复杂度,开始变得可解释、可扩展、可演进。
在我看来,优秀工程师和普通工程师的差距,很多时候不在于会不会写代码,而在于能不能透过需求表象,看见问题真正应当归属的范式。
代码只是最后一层落地。
而范式,才是决定系统命运的第一推动力。