当所有层级的上下文混在一起时
当所有细节同时摆在眼前时,是什么妨碍你看清整体图景?
普通的代码仓库不会按尺度区分信息:业务领域、操作、数据模型、调用顺序、基础设施以及一行行具体代码,全都同时呈现出来。工作记忆必须同时容纳来自不同层级的事实,并自行重建它们之间的关系。注意力不断在系统结构与局部细节之间来回切换,因此中断之后,理解很快就会瓦解。
缺少全局图景会如何影响工作
下面,同一组信息以两种状态呈现:左侧是混在一起的样子,右侧则被整理成五个依次递进的问题。让我们从第一个问题开始:系统中的责任究竟在哪里?
先建立责任地图
责任在哪里?
第一根支柱是一张责任地图。它把控制器、服务、数据模型、基础设施适配器和调用链,围绕系统的主要区域聚拢起来——形成一个骨架,操作、数据和代码之后都可以附着其上。
领域不是按技术层,而是按稳定的责任范围划分系统:订单、支付、通信和分析。数百个看似同等重要的文件,由此变成第一张可理解的系统拓扑。
领域地图带来了什么
图中的四个领域构成应用的最上层。接下来我们会依次展开 StoreDomain:先看它的 Actions,再看一个操作的契约、场景和具体实现。
StoreDomain拥有购物车、订购和交付
BillingDomain拥有付款、发票和退款
MessagingDomain拥有客户沟通和网络钩子
AnalyticsDomain拥有活动、集市和业务报告
地图进一步变成能力目录
系统能做什么?
领域地图说明责任在哪里,却还没有说明系统能做什么。为此,每个领域都会展开为 Action 目录,也就是它向系统其他部分提供的具名能力。
Action 是领域的一项具名公开能力。目录展示的不是内部函数,而是一个领域向系统其他部分提供的操作,以及它们之间的有向关系。每个 Action 都成为一个单一的调用点:调用方按含义挑选它所需要的能力,而不是用一个个单独的方法拼装出这个操作。
Action 目录带来了什么
图中突出显示了启动订单创建的 CreateOrderAction,旁边是 StoreDomain 的其他 Actions 及其关系。一个操作可以依赖另一个操作,但依赖始终有方向,并且不会闭合成环。在这一层只展示 Action 的名称和关系;输入、结果、场景和代码会在后面逐层展开。
CreateOrderAction创建订单:验证、预订和收费
→ ChargePaymentAction
GetOrderAction读取订单的当前状态
CancelOrderAction取消订单并发起退款
→ RefundPaymentAction
ShipOrderAction将确认的订单交给交货
固定操作的边界
操作需要什么,又承诺什么?
这项能力已经有了名称和系统中的位置。要把它当作黑盒使用,还需要准确知道它接收哪些数据,以及必须返回什么结果。
Contract 让 Action 的边界具有明确类型且没有歧义。Params 描述操作接收的全部内容,Result 描述它必须返回的全部内容。调用代码依赖这项承诺,而不是 Action 的内部结构。只要输入、输出和可观察行为保持兼容,实现就可以被替换。
Action 契约带来了什么
熟悉的 CreateOrderAction 现在拥有完整签名:左侧是 CreateOrderParams,右侧是 CreateOrderResult。字段不再是孤立的数据模型,而是属于一个位置和目的都明确的操作。使用这个 Action 仍然不需要打开它的内部实现。
CreateOrderParamsitems: list[Item]
currency: str
CreateOrderAction在一个明确边界内编排订单创建
CreateOrderResultpayment_id: str
status: OrderStatus
把操作展开为场景
场景如何推进?
契约固定了操作的起点和终点,却没有展示两者之间如何转化。为此,我们继续展开业务场景的内部流程。
Pipeline 让主要业务场景变得线性且可见:校验输入、预留库存、扣款、组装结果。这并不意味着错误、分支和补偿不存在;它们会相对于主线获得明确位置。每个步骤也有自己的局部契约:声明从 Params、State 和 Context 中读取什么,以及为后续步骤向 State 中加入什么。
操作场景带来了什么
领域为场景确定位置,Action 为它命名,Contract 固定起点和承诺的结果。Pipeline 进一步加入因果顺序和内部边界。reserve_inventory 被隔离为一次独立的状态变化:它接收已经校验的数据,并留下 reservation_id 供场景继续使用。
最后才进入具体行为
具体行为在哪里?
Pipeline 精确指出所需行为的位置,并大幅缩小搜索范围。现在不必打开整个代码仓库,甚至不必打开整个 Action,只需查看一个目标、输入和输出都已经明确的步骤。
Code 成为第五层,并不是因为细节不重要,而是因为这些细节现在已经被意义包围。我们已经知道行为属于哪个领域、Action 实现什么能力、Contract 承诺什么,以及 reserve_inventory 在 Pipeline 中处于什么位置。实现代码因此成为对具体任务的局部回答,而不是一次无休止代码仓库调查的入口。
将行为隔离在单个步骤中带来了什么
打开 reserve_inventory 时,我们已经知道它的意图、输入以及在场景中的位置。原则仍然相同:外部效果应通过已声明的 Resources 和公开 Actions 发生。架构语法让偏离规则的做法可见、可验证,但并不假装仅凭说明文字就能在物理上阻止所有绕行。
$ uv run python store/actions/create_order.py五个层级不会隐藏代码,也不会把系统简化成一张图。它们保留了从整体模型走向具体细节的路径。新人逐步建立上下文;架构师管理系统语法和边界,而不是逐个管理文件;AI 智能体则在声明的规则内完成局部工作:人设计系统的语言,机器用这种语言行动。
