这篇文章,想记录的是:当我面对一个新技术时,我是怎么决定要不要深入学习它的。
起因是工作流引擎。最近项目里要用 Flowable,我像往常一样,准备花几周时间啃源码、画类图、写笔记。但动手之前,我突然问了自己一个问题:
这个技术,真的值得我投入这么多精力吗?
这个问题让我停下来,重新审视了一遍自己的学习策略。慢慢地,我形成了一套判断标准------就像我们挑选书籍一样:有些值得精读,有些略读即可,有些直接跳过。
这不是说工作流不重要,而是说:不是所有技术都需要用同样的深度去学习。
一、技术学习的困境:什么都想学,什么都学不深
我们都经历过这种焦虑:
- 听说团队要引入工作流引擎,赶紧去看 Flowable 文档
- 看到别人讨论规则引擎,担心自己落后了,马上去研究 Drools
- 刷到一篇 Netty 源码解析,觉得"高并发必备",收藏准备周末啃
- Redis 的跳表、Kafka 的零拷贝、MySQL 的 MVCC......技术清单越列越长
结果就是:每个都学了一点,每个都没学透。更糟糕的是,花了大量时间研究的东西,可能在实际工作中根本用不上,或者只是当黑盒用一下就够了。
问题出在哪?我觉得是没有分层学习的意识。
就像读书一样:
- 工具书,查到需要的就行(字典)
- 经典著作,值得反复精读(红楼梦)
- 畅销小说,快速翻完即可(爽文)
- 有些书,看目录就够了
技术学习也应该这样。
二、我的判断框架:三个问题决定学习深度
经过这次对工作流的思考,我给自己总结了三个判断标准:
问题1:它的核心是算法/理论创新,还是工程组合?
值得精读的技术,通常包含计算机科学的核心知识:
- MySQL 的 B+ 树:理解索引为什么这样设计,为什么范围查询快,为什么联合索引有顺序要求
- Redis 的跳表:理解概率平衡的巧妙,为什么比红黑树更适合有序集合
- Raft 算法:理解分布式共识的本质,为什么需要日志复制
- Netty 的 Reactor 模型:理解 I/O 多路复用,为什么能高并发
这些技术学到的是可迁移的知识------学会了跳表,你就理解了概率数据结构的思想;学会了 Raft,你就掌握了一类共识问题的解法。
只需略读或黑盒使用的技术,更多是工程堆砌:
- Swagger:注解解析 + 模板渲染,没什么核心算法
- Hibernate:ORM 映射 + SQL 生成,工程复杂但理论简单
- Spring:依赖注入 + AOP + 一堆整合,庞大但不深奥
这类技术的复杂度来自需求的累积,而不是算法本身的难度。学会用比学实现重要。
问题2:理解它的本质模型,需要看源码吗?
有些技术,你只要抓住了核心抽象,就已经理解了 80% 的本质。剩下的 20% 是工程细节,看不看源码区别不大。
这就是我给自己的第二个判断标准:能不能通过抽象推导出它的大致实现?
如果答案是"能",那就没必要深挖源码。
问题3:我的目标是解决问题,还是掌握技术本身?
最后一个问题,也是最容易被忽略的:
你学这个技术,到底是为了什么?
- 如果是为了在项目里用好它,那学会 API、理解适用场景、知道坑在哪,就够了
- 如果是为了成为这个领域的专家、写技术书、做开源贡献,那确实需要深入源码
大部分时候,我们只是要用好一个工具,而不是成为工具的制造者。
三、用工作流引擎验证我的判断框架
现在,让我用工作流引擎来验证一下这三个问题。
它的核心是算法创新,还是工程组合?
我试着不看任何文档,靠直觉推导一下工作流引擎可能是怎么实现的。
在我看来,工作流本质上就是三样东西:
1. 一张通用的"骨干图"(流程定义)
图里描述了有哪些节点、哪些连线、哪些条件判断、哪些分支。这张图是所有实例共享的模板。
就像游戏地图:定义了城市A、城市B、城市C,以及它们之间的道路和传送门。
2. 一条"复刻这张图"的数据实例(流程实例)
每来一条业务数据,相当于在这张图上跑一个"实例"。这个实例记录着:
- 当前走到哪个节点了
- 哪些节点已经走过(亮的)
- 哪些还没走(灰的)
- 携带的业务数据(订单号、申请人、金额等)
用一个更直观的比喻:图是地图,实例就是地图上的小人和高亮路径。你玩游戏时,已探索的区域是亮的,未探索的是灰的,你的角色站在某个位置上。工作流实例就是这样一个"存档"。
3. 外部事件触发这张"静止的图"向前推进
这些外部事件可能是:
- main 方法里的一次调用
- 一个定时任务扫到该执行了
- 用户点了前端页面上的"同意/提交/下一步"按钮
- 外部系统的回调
本质动作只有一个:读取当前实例的状态,根据图上的定义和条件,算出下一步到哪个节点,然后更新状态。
从这个角度看,工作流就是一套"持久化的状态机 + 事件驱动推进"的通用框架。
核心无非就是:
- 表达式引擎(判断条件)
- 字符串解析(解析 XML/JSON)
- 状态机(节点流转)
- 持久化(保存状态到数据库)
这些东西单独拿出来都不难,难的是把它们组合起来,处理各种边界情况,做得稳定、易用、可监控。
结论:工作流属于"工程组合型"技术,没有特别核心的算法。
能通过抽象推导出实现吗?
我甚至可以写个最简单的工作流验证我的理解:
场景:根据用户的性别和年龄,推荐游戏
流程图:
markdown
开始 → 获取用户数据 → 性别=男?
↓ 是
年龄<18?
↓ 是
推荐王者荣耀
↓
结束
代码实现:
java
// 1. 流程定义(图)
WorkflowDefinition def = new WorkflowDefinition();
def.addNode("start", new StartNode("getData"));
def.addNode("getData", new TaskNode(() -> loadUserData(), "gateway1"));
def.addNode("gateway1", new GatewayNode(Map.of(
data -> "男".equals(data.get("性别")) && (int)data.get("年龄") < 18,
"recommend1"
)));
def.addNode("recommend1", new TaskNode(
() -> System.out.println("推荐:王者荣耀"),
null
));
// 2. 创建流程实例(图 + 数据)
Map<String, Object> userData = Map.of(
"性别", "男",
"年龄", 16
);
// 3. 执行流程(事件推进)
WorkflowEngine engine = new WorkflowEngine();
engine.run(def, userData);
// 输出:推荐:王者荣耀
这可能就是工作流的本质了。无非就是:
- 根据数据的条件,判断往哪走
- 走到哪,就来到了预定义的框框里,执行框框里的语句
结论:能。理解了核心抽象后,剩下的就是工程细节。
我的目标是什么?
我要做的是:
- 在项目里用好 Flowable
- 知道什么场景适合用工作流,什么场景不适合
- 遇到问题时知道怎么排查
我不需要:
- 成为工作流引擎的专家
- 给 Flowable 贡献代码
- 从零实现一个工作流引擎
结论:黑盒使用 + 理解边界,就够了。
四、什么场景适合工作流?什么场景不适合?
既然决定了把工作流当黑盒用,那就要搞清楚它的适用边界。
我给自己定了一个判断原则:
更适合交给工作流的:
- 多步骤、长生命周期的过程(跨小时、跨天,甚至跨周)
- 多角色或多系统参与的过程
- 可复用的通用流程骨架
- 需要强运营、可视化、审计能力的场景
不那么适合交给工作流的:
- 单系统内的核心领域逻辑(定价规则、促销规则、库存扣减算法)
- 短生命周期、一次性的小流程(几行同步逻辑,用 if-else 就够了)
- 变化频繁、需要灵活调整的核心算法
举两个例子,感受一下区别:
场景1:请假审批(适合)
这是工作流的经典场景:
- 员工提交请假申请
- 主管审批
- 如果超过3天,需要HR审批
- 审批通过,发邮件通知
- 超时未处理,自动提醒
画成图就是:
markdown
提交申请 → 主管审批 → (天数>3?) → HR审批 → 结束
↓ 拒绝
驳回
这种场景特别适合工作流:
- 多步骤,跨时间(可能要等好几天)
- 多角色参与(员工、主管、HR)
- 需要记录历史(谁审批的、什么时候审批的)
- 需要可视化(看当前卡在哪个环节)
场景2:电商订单定价(不适合)
订单计价逻辑:
- 商品原价
- 会员折扣
- 优惠券
- 满减活动
- 运费计算
这些逻辑虽然也是多步骤,但它们是核心领域模型,应该用代码、用领域对象来表达,而不是画在流程图里。
如果把定价规则也塞进工作流,就有问题了:
- 变化频繁(促销活动天天变)
- 需要灵活组合(今天满减+优惠券,明天换成秒杀)
- 需要单元测试(定价逻辑必须测得很细)
这些特征决定了它不适合用工作流,而应该用策略模式、责任链模式等代码来实现。
场景3:电商发货流程(适合)
订单支付成功后,要开始发货:
- 选择最近的仓库
- 仓库出库
- 调用第三方物流接口
- 回写物流单号
- 如果物流接口调用失败,重试3次
- 还失败,转人工处理
这个流程适合用工作流来做。因为:
- 跨系统(订单系统、仓库系统、物流系统)
- 长生命周期(从出库到签收可能好几天)
- 需要容错和重试
- 需要知道当前走到哪了
在这种划分下:
- 订单服务专注核心领域逻辑和状态管理
- 发货工作流服务是一个黑盒编排器,对外暴露"创建发货流程实例"、"查询发货状态"、"触发某些人工/系统步骤"等接口
五、推而广之:其他技术的分类
理解了工作流的学习策略之后,我试着把同样的思路应用到其他技术上。
值得精读的技术(有核心算法/理论)
| 技术 | 核心价值 | 可迁移的知识 |
|---|---|---|
| MySQL B+ 树 | 为什么范围查询快 | 树形索引结构的通用设计思想 |
| Redis 跳表 | 为什么有序集合高效 | 概率数据结构的巧妙 |
| Kafka 日志结构 | 为什么吞吐量大 | 顺序写、零拷贝等高性能技巧 |
| Netty Reactor | 为什么高并发 | I/O 多路复用的本质 |
| Raft 算法 | 分布式共识 | 一类共识问题的解法 |
这些技术的学习投入产出比高,因为学到的是底层原理,可以迁移到其他场景。
适合略读的技术(工程组合型)
| 技术 | 本质 | 学习策略 |
|---|---|---|
| 工作流引擎 | 状态机 + 持久化 + 事件驱动 | 理解模型 + 黑盒使用 |
| 规则引擎 | 条件匹配 + 动作执行 | 理解适用场景即可 |
| Spring | 依赖注入 + AOP + 整合 | 会用 + 知道原理 |
| Swagger | 注解解析 + 模板渲染 | 会配置就行 |
这些技术的复杂度在我看来,更多来自工程需求的堆砌,而不是算法本身的难度。学会用可能比学实现重要。
六、一个类比:Akka 和工作流
聊到这,我想起之前尝试理解 Akka 的经历。
刚听说 Akka 的时候,看到各种术语:Actor 模型、消息传递、监督策略、位置透明......当时觉得很玄乎。
但我试着剥开这些术语,慢慢发现可能本质就是:
- 每个 Actor 像一个独立的小工人
- 有自己的邮箱(消息队列)
- 工人之间不共享数据,只通过发消息交流
- 底层是线程池 + 阻塞队列
换句话说,Akka 的核心在我看来,可能就是:"线程池 + 消息队列 + 事件回调"的高级封装。
理解了这个之后,我觉得:
- Akka 的原理可能不复杂
- 但它在这个基础上做了大量工程化:监督策略、集群、远程通信、背压控制
- 我可能不需要从零造一个 Akka,但我可以理解它的适用场景
工作流给我的感觉也是一样的。
七、我的学习策略总结
基于前面的思考,我给自己定了一个学习策略:
对于"值得精读"的技术(算法/理论型):
- 看书、看论文、看源码
- 手写实现一遍(自己实现个 LRU、跳表、简易 Raft)
- 深入理解为什么这样设计
- 目标:掌握可迁移的核心知识
对于"适合略读"的技术(工程组合型):
- 理解核心抽象和适用场景
- 会用 API,知道坑在哪
- 遇到问题时,看一小段源码/表结构,确认行为
- 目标:能解决问题 + 知道边界
对于"可以跳过"的技术:
- 看官方文档的 Quick Start
- 遇到问题再查
- 目标:知道有这么个东西,能快速上手
工作流引擎,在我看来,显然属于第二类。
八、为什么我决定"不手写工作流引擎"
理解了本质之后,我面临一个选择:要不要自己实现一个简单的工作流引擎?
说实话,我确实有过这个冲动。毕竟理解了原理,写个玩具版本也不难。
但想了想,我的判断是:
工作流的核心思想不复杂,但工程实现很重
流程定义解析、运行时表设计、事务一致性、并发控制、作业调度、可视化、边界事件、补偿机制......这些东西做一个"够用"的版本都不轻松,做一个"好用又稳定"的版本更是长期工程。
对我个人来说,我觉得更划算的是:
- 理解本质(图 + 实例 + 事件推进 + 适用场景)
- 学会合理地使用和评估现成引擎(Flowable/Camunda 等)
- 在真有需要时:
- 用工作流引擎做多步骤、多系统、多角色的长流程编排
- 用任务调度/重试系统做分布式执行保障
- 用自己的业务代码承载核心领域逻辑
所以我给自己的结论是:
工作流对我来说,可能不值得"从零手写一个完整引擎",更适合作为一个可替换的黑盒组件,被我理解、评估、使用、测试,而不是重造一遍。
这不是说手写没有价值,而是说对我当前的阶段和目标来说,ROI 不高。
九、最后的思考:技术人的成熟,是学会战略性放弃
写到这里,我想起一句话:
真正的高手,不是什么都会,而是知道什么值得学,什么可以不学。
技术的海洋太大了,我们的时间和精力有限。如果每个技术都要深挖源码、手写实现、成为专家,那最后的结果只能是:什么都学了一点,什么都没学深。
更重要的是,我们学技术的目的是什么?
- 是为了解决实际问题
- 是为了提升系统的质量
- 是为了构建自己的知识体系
而不是为了"掌握所有技术"这个虚无的目标。
所以,我给自己的建议是:
像挑选书籍一样挑选技术:
- 有些技术,值得精读,反复咀嚼(MySQL、Redis、分布式算法)
- 有些技术,略读即可,知道大概(工作流、规则引擎、Spring)
- 有些技术,看目录就够,用到再查(Swagger、各种小工具)
判断的标准是:
- 它包含核心算法/理论吗?(是否有可迁移的知识)
- 理解它的本质,需要看源码吗?(是否能通过抽象推导)
- 我的目标是解决问题,还是掌握技术本身?(投入产出比)
对于工作流引擎,我的答案是:
- 理解核心抽象:图 + 实例 + 事件推进
- 搞清楚适用场景:多步骤、长流程、多角色、需要可视化
- 黑盒使用 Flowable/Camunda,遇到问题再看源码
这样,我的学习目标就基本完成了。
十、结语
这篇文章,从工作流引擎出发,但想表达的不只是工作流。
更重要的是:面对任何新技术,我们都应该先问自己三个问题,再决定要投入多少精力。
不是所有技术都值得深挖,也不是所有技术都可以浅尝辄止。关键是找到适合自己的学习节奏和深度。
对我来说:
- 理解技术的本质和边界,比精通它的所有细节更重要
- 知道什么时候用、什么时候不用,比会用更重要
- 把时间花在真正有价值的技术上,比什么都学更重要
当然,这只是我个人在现阶段的判断。不同场景、不同阶段,可能会有不同的选择。
但至少,我现在有了一个判断框架。
下次再遇到新技术时,我会先问自己:
这本"技术书",我该精读、略读,还是直接跳过?