在软件架构中记录用户流程
bug报告看起来很简单:"结账偶尔失败。"
我们有精美的架构图。C4图展示了每个服务、每个数据库、每个集成。但当我们试图追踪用户从"添加到购物车"到"订单确认"的旅程时,没有人能就确切的序列达成一致。涉及哪些服务?什么顺序?库存检查发生在支付之前还是之后?
三个工程师有三种不同的心理模型。我们的静态架构图展示了结构,但没有展示行为。我们能看到方框和箭头,但看不到用户实际如何在系统中移动。
那时我意识到我们需要用户流程。
用户流程到底是什么
用户流程记录用户通过系统完成目标的旅程。不是静态结构(那是C4图的工作),而是动态序列:
- 用户做X
- 系统响应Y
- 用户选择Z
- 依此类推...
这听起来很显然,但令人惊讶的是很少有人把它们记录得很好。大多数团队有架构图(系统结构)和API文档(端点详情),但在两者之间没有从用户角度展示这些部分如何协同工作的内容。
结构与行为之间的差距
这是当时我们C4容器图的简化版本:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Web App │────▶│ API │────▶│ Database │
└─────────────┘ └──────┬──────┘ └─────────────┘
│
┌──────▼──────┐
│ Payment │
│ Service │
└──────┬──────┘
│
┌──────▼──────┐
│ Stripe │
└─────────────┘
这告诉你组件存在以及如何连接。但它不回答:当用户结账时先发生什么?API是否在调用支付之前验证库存?如果支付成功但库存现在不可用怎么办?
这些问题需要理解流程,不仅仅是结构。
有用的用户流程的构成
随着时间推移,我开发了一个适合记录流程的模板:
1. 目标声明
从用户试图完成什么开始:
目标:完成购物车中商品的购买
2. 前置条件
在此流程开始之前必须为真的条件?
- 用户已登录
- 购物车中至少有一件商品
- 购物车中的商品有库存(截至页面加载时)
3. 正常路径
先记录预期的成功路径:
1. 用户点击"结账"按钮
→ Web App 显示收货地址表单
2. 用户输入收货地址,点击"继续"
→ API 验证地址格式
→ API 计算配送选项
→ Web App 显示配送方式选择
3. 用户选择配送方式,点击"继续"
→ API 验证配送方式
→ Web App 显示支付表单
4. 用户输入支付信息,点击"下单"
→ API 在数据库中创建待处理订单
→ API 用订单详情调用 Payment Service
→ Payment Service 调用 Stripe 扣款
→ Payment Service 返回成功给 API
→ API 标记订单为已确认
→ API 触发确认邮件
→ Web App 显示订单确认页面
5. 用户看到带有订单号的确认信息
4. 错误路径和边缘情况
正常路径只是开始。真正的价值来自记录出错时会发生什么:
支付被拒绝:
在步骤4,如果Stripe返回payment_declined:
→ Payment Service 返回错误给 API
→ API 不标记订单为已确认
→ API 删除待处理订单
→ Web App 显示"支付被拒绝"消息
→ 用户可以使用其他支付方式重试
库存变化:
在步骤4,创建待处理订单之前:
→ API 重新检查库存可用性
→ 如果商品现在不可用:
→ API 返回 inventory_error
→ Web App 显示"商品不再可用"并链接到购物车
→ 用户必须移除商品并重新开始结账
这些错误路径是bug隐藏的地方。它们也是大多数文档停止的地方,这就是bug隐藏在那里的原因。
将流程与架构连接
这是最强大的地方:将用户流程链接到你的C4图。
在Archyl中,我们可以标注流程每个步骤涉及哪些组件。这创建了双向可追溯性:
- 查看流程?看到它涉及哪些组件。
- 查看组件?看到哪些流程通过它。
不同类型的流程
用户流程
从UI发起的用户序列:结账流程、注册流程、密码重置流程。
系统流程
机器发起的序列:夜间对账作业、Webhook处理、事件驱动级联。
集成流程
跨系统序列:第三方订单导入、支付结算批处理、与合作伙伴的数据同步。
常见错误
错误1:太多细节
流程文档不应该读起来像代码。如果你在记录单独的数据库查询,你在错误的层级。聚焦于用户可见的步骤和服务级别的交互。
错误2:只记录正常路径
正常路径很简单。错误路径才是bug所在。强迫自己回答:"如果这一步失败会怎样?"
错误3:变更后不更新
不匹配现实的文档流程比没有文档更糟。它创建错误的信心,在调试期间导致错误的假设。
错误4:把流程当作静态的
用户流程会演变。新功能添加步骤。优化移除步骤。把流程视为活文档,而不是一次性产物。
总结
静态架构图告诉你系统由什么组成。用户流程告诉你它如何运行。两者都需要。
下次你在多个服务间调试复杂问题时,问自己:"我们有这个流程的文档吗?"如果答案是否定的,你将花数小时重建这些部分如何组合在一起——这些时间本可以用一个简单的文档来节省。
从最关键的流程开始。对于大多数系统,这可能是认证或主要转化路径。记录正常路径,然后强迫自己至少记录三个错误情况。
你未来的自己——在凌晨2点疯狂调试时——会感谢你的。