Skill 的整洁之道:软件架构原则在 AI 时代的新生
软件开发领域有两本经典:《代码整洁之道》和《架构整洁之道》。前者讲怎么写好一个函数,后者讲怎么组织一个系统。
AI 时代来了,编码交给 AI 了,《代码整洁之道》的直接受益者变成了 AI——在函数命名、结构分层这个层面,AI 的输出已经相当稳定,你只需要给它提示和约束。
但《架构整洁之道》的命运不同。它没有被 AI 取代,而是在一个新的层面上重新活了一遍。
程序员的 scope 在扩张
程序员当然一直都在理解需求、拆解任务、设计方案——这些不是 AI 带来的新事物。
变化的是时间分配。编码执行这件事,以前占据了工作日的大部分;现在这部分被 AI 大幅压缩了,人的精力自然向其他环节倾斜。同样是”全栈”,以前意味着你要写前端也写后端,现在意味着你要覆盖从需求到上线的整条链路——不是因为你更厉害了,而是执行层有了 AI 来扛。
更关键的变化是形式。这不是简单地”用 AI 工具辅助”,而是一种 AI native 的形式:把每个环节封装成 skill,让 Claude Code 之类的 agent 作为执行主体,人退到设计和调度的位置。
这种模式下,”程序员”实际上在做的事情变了:
- 不再只是写代码,而是设计执行代码的 agent 的工作方式
- 不再只是管理函数和模块,而是管理 skill 的分工和协作
- 不再只是思考技术架构,而是同时思考 agent 团队的架构
当 skill 多了之后,新的问题出现了:skill 怎么分工?skill 之间怎么协作?agent 怎么组织?这是一个新的层面的”架构”问题。
而这时候,《架构整洁之道》里那些原则,开始显示出它们真正的价值。
一个真实的例子
先从一个具体的问题说起。
我们在做一个 AI 辅助研发工作流的探索,其中有一个环节是提测前用例检查:在代码提测之前,用 AI 自动从测试用例管理平台拉取用例,然后对照代码实现逐条检查,发现遗漏或错误。
最初,这个功能被写成一个 skill,叫 code-checker。它的工作流程是:
- 从测试平台拉取用例列表和详情
- 按组件分组,生成检查批次
- 读取对应代码文件,逐批次检查
- 输出检查报告
这个 skill 能用,跑通了。
但当我们把这个功能迁移到更完整的工作流平台时,发现了一个问题:拉取用例这个操作,不只有代码检查这一个下游。测试报告生成、用例覆盖率统计、自动化测试执行——这些流程都需要先拉用例。
如果每个下游 skill 都自己实现一遍”拉用例”,代码重复是小事,真正的问题是:测试平台的接口一旦变化,所有 skill 都要改。
所以我们做了一个拆分:
base/test-case-fetcher:只负责从测试平台拉取用例,输出结构化 JSONcode-checker:依赖test-case-fetcher的输出,只负责业务相关的代码检查逻辑
拆分之后,test-case-fetcher 成了一个通用的基础 skill,任何需要用例数据的流程都可以复用。code-checker 专注于业务知识,不再关心数据怎么来。
这个拆分,其实就是经典的单一职责原则。
把架构原则翻译到 skill 层面
《架构整洁之道》里的 SOLID 原则,每一条都能直接映射到 skill 设计上。
单一职责:一个 skill 只做一件事
原则:一个模块应该只有一个变化的理由。
翻译到 skill:一个 skill 的职责应该单一,它的变化原因应该只有一个。
上面的例子里,原来的 code-checker 有两个变化的理由:测试平台接口变了(数据获取逻辑要改),或者检查规则变了(业务逻辑要改)。拆分之后,各自只有一个变化理由。
实践中容易犯的错误是把”方便”当”内聚”。”反正这两件事经常一起做,放一个 skill 里更方便”——这个逻辑在功能少的时候成立,skill 多了之后会变成维护噩梦。
开闭原则:base skill 是稳定的接口
原则:对扩展开放,对修改关闭。
翻译到 skill:base skill 定义稳定的输出格式(接口),上层 skill 通过扩展来满足新需求,而不是修改 base skill。
test-case-fetcher 的输出格式一旦稳定下来,就不应该随意改变——因为所有依赖它的下游 skill 都在依赖这个格式。新的需求应该通过新增字段(向后兼容)或者新建 skill 来满足,而不是修改现有输出格式。
这和 API 设计的道理完全一样。base skill 就是你的内部 API。
依赖倒置:业务 skill 依赖协议,不依赖具体实现
原则:高层模块不应该依赖低层模块,两者都应该依赖抽象。
翻译到 skill:业务 skill 不应该关心数据怎么来、工具怎么调用,它只关心输入数据的格式和输出的结果格式。
这里的”抽象”在 skill 场景里,对应的是数据格式约定——文件路径、JSON schema、字段命名。code-checker 不关心用例是通过 HTTP 接口拉的还是从本地缓存读的,它只关心 .check-work/cases.json 里有什么。这个文件路径和格式约定,就是两个 skill 之间共同依赖的”接口”。
一旦建立了这个约定,你可以随时替换 test-case-fetcher 的实现——换个接口、改个认证方式、加个缓存——下游 skill 完全不需要改。
精简上下文:只传 skill 真正需要的信息
SOLID 里有接口隔离原则(ISP):不应该强迫客户端依赖它不使用的接口。在 skill 设计里,这个精神体现在另一个维度:传给 skill 的上下文要精准,不要把整个项目背景都塞进去。
这在 AI agent 的场景里格外重要。上下文越大,token 消耗越高,更关键的是,AI 的注意力是有限的,无关信息会稀释它对关键信息的关注。
一个好的 skill 设计应该明确说明:它需要什么输入,产出什么输出,中间不依赖任何隐式的环境状态。这样的 skill 是可以独立测试的,也是可以在不同项目里复用的。
agent 团队也是团队
Conway’s Law 说的是:系统的架构,往往是设计这个系统的组织的沟通结构的镜像。
原话来自 Melvin Conway,大意是:如果你有四个团队来开发一个编译器,你会得到一个四遍的编译器。这个规律成立,是因为跨组织边界的沟通成本高,接口自然沿着摩擦最小的地方形成——而那个地方通常就是组织边界。
agent 之间没有这种沟通摩擦,所以 Conway’s Law 的原始机制在这里并不直接适用。但有一个相关的工程实践,叫 Inverse Conway Maneuver(逆康威操作):不是让架构被动地跟随组织,而是主动设计组织结构,来驱动你想要的系统架构。
这个思路在 agent 设计里非常有用。
Anthropic 工程师在设计多 agent 编程系统时,把分工设计成 Planner-Generator-Evaluator 三角(见这篇博客):Planner 把模糊需求扩展成具体规格,Generator 按 sprint 逐功能实现,Evaluator 用 Playwright 点击运行中的应用逐条验证。这三个 agent 的分工,直接对应了传统团队里的产品经理、开发工程师、测试工程师。
这不是偶然。agent 团队的分工方式,决定了系统的架构形态——因为设计 agent 团队的人是人类,人类习惯用自己熟悉的组织模型来切分职责。想要什么样的系统架构,就先想清楚你要组建一个什么样的 agent 团队。
技术架构服务于组织架构
有一个观察我觉得很准确:技术架构是服务于组织架构的,组织架构怎么设计,技术架构就会往那个方向演化。
换句话说,真正的架构决策权在组织设计者手里,而不只在技术人员手里。
这个逻辑在 AI 时代有了新的含义。
传统软件开发里,组织架构的变化是慢的——重组一个团队需要几个月,调整汇报关系需要走流程,跨部门协作需要建立正式的接口协议。技术架构跟着组织架构走,但有相当大的滞后。
AI agent 团队的组织架构变化是快的。你今天可以让 agent 扮演 QA,明天可以让它扮演架构师,后天可以给它加一个新的专业角色。组织结构的调整成本接近零。
这意味着架构决策的频率和粒度都在提高。你不再是每隔几年做一次大的架构调整,而是每隔几天就在做小的 agent 团队组织决策。
这对”程序员”的要求变了:不只是会写代码,还要会设计组织——哪些工作应该由哪类 agent 负责,agent 之间的接口怎么定义,职责边界在哪里。
这是一种新的架构思维,但它的底层原则和《架构整洁之道》是一脉相承的。
几个具体的 skill 架构范式
把上面的原则落地,有几个在实践中有用的模式。
分层架构
把 skill 分成三层:
1 | 业务 skill(知道"做什么",不知道"怎么做") |
code-checker 是业务 skill,它知道”要检查用例对应的代码实现”,但不关心用例怎么拉取。test-case-fetcher 是通用 skill,它知道”怎么从测试平台拉数据”,但不关心数据被用来做什么。底层的 HTTP 请求、认证处理,是工具层的事。
这个分层的好处是:业务逻辑的变化不会影响通用层,通用层的优化不需要改业务层。
明确的交接协议
skill 之间通过文件或结构化数据交接,而不是隐式的环境状态。
test-case-fetcher 输出到 .check-work/cases.json 和 .check-work/case-details/,这是一个明确的约定。code-checker 从这个位置读数据,不关心数据是怎么生成的。
明确的交接协议有几个好处:可以单独测试每个 skill,可以缓存中间结果,可以替换任意一个 skill 的实现而不影响其他 skill。
生成与验证分离
这是 Anthropic 工程师总结的核心模式,也是 SOLID 原则在 AI 场景里最重要的体现。
让 AI 自我评估刚生成的内容,几乎总是给好评。把生成和验证分给两个独立的 agent,用不同的 prompt 调教,效果要好得多。
这不只是工程技巧,背后是职责分离的原则:生成 skill 的职责是”尽可能生成好的结果”,验证 skill 的职责是”尽可能发现问题”。这两个目标天然有张力,放在同一个 skill 里会相互妥协。
渐进式细化
不要一开始就把 skill 设计得很细。先做一个能跑通的粗粒度 skill,在实际使用中发现哪些部分需要复用、哪些部分变化频繁,再做有针对性的拆分。
上面的例子就是这样来的:先有一个能跑通的 code-checker,在迁移过程中发现拉取用例这个部分需要复用,才做了拆分。过早的细化往往是错的细化。
脚本与 AI 的边界
skill 内部同样需要分工:结果确定、逻辑固定的步骤交给脚本,需要理解和判断的步骤交给 AI。
判断准则很简单——问一句”这个步骤有唯一正确答案吗?”有的话用脚本,没有的话用 AI。构建产物、拉取数据、读写文件,答案确定,脚本做;理解代码逻辑、判断设计质量、推断边界场景,答案模糊,AI 做。
混淆的代价是真实的。用 AI 做确定性操作,token 浪费,结果还不如一行脚本稳定。用脚本处理模糊判断,规则越写越长,最后发现边界情况永远枚举不完,只能靠人工兜底——这本身就是信号:这个步骤该交给 AI。
这不是新知识,是旧知识的新应用
我在想这些问题的时候,有一种奇怪的感觉:这些原则都不新,它们在《架构整洁之道》里写得很清楚。但当我把它们应用到 skill 设计上的时候,感觉像是第一次真正理解了它们。
也许是因为,代码层面的架构问题通常很抽象——“高内聚低耦合”听起来像废话,直到你真的在一个大系统里被耦合折磨过。
skill 层面的架构问题更具体,更直接。一个 skill 做了两件事,你会在两周后感受到痛苦:测试平台接口变了,你发现要改三个 skill。一个 skill 的上下文太大,你会立刻看到 token 消耗翻倍。
这种即时反馈,让架构原则从抽象变成了具体。
AI 时代没有废掉《架构整洁之道》,它只是把战场从函数和模块移到了 skill 和 agent 团队。
原则还是那些原则。只是现在,你有机会以更快的速度、更低的成本,在一个新的层面上把它们应用一遍。