SuperAPI AI 工具集

codebase-design

编程与开发

查看项目

更新于 10-16 04:00

技能介绍

用途

Codebase Design 提供一套用于设计深模块(deep modules)的共享词汇。当用户想要设计或改进某个模块的接口、寻找“加深”(deepening)机会、决定接缝(seam)该放在哪里、让代码更易测试或更利于 AI 导航,或者当另一个技能需要深模块词汇时,可使用本工作流。其目标是为调用方带来杠杆效应,为维护者带来局部性,为所有人带来可测试性。

核心理念

设计深模块:把大量行为放在一个小接口之后,置于干净的接缝处,并可通过该接口进行测试。无论在哪里设计或重构代码,都应使用这套语言和这些原则。

术语表

文中要求严格使用以下术语,不要用“component”“service”“API”或“boundary”替代,一致的用语正是重点所在。

  • Module(模块):任何具有接口和实现的东西。刻意与尺度无关:可以是一个函数、类、包,或跨层切片。避免使用 unit、component、service。
  • Interface(接口):调用方正确使用模块所必须知道的一切:类型签名,以及不变量、顺序约束、错误模式、所需配置和性能特征。避免使用 API、signature(过于狭窄,仅指类型层面的表面)。
  • Implementation(实现):模块内部的内容,即其代码主体。与 Adapter 不同:一个东西可以是小适配器加大实现(如 Postgres 仓库),也可以是大适配器加小实现(如内存假实现)。当话题是接缝时用“adapter”,否则用“implementation”。
  • Depth(深度):接口层面的杠杆效应,即调用方(或测试)每学习一单位接口所能触发的行为量。当大量行为位于小接口之后时,模块是深的;当接口几乎与实现一样复杂时,模块是浅的。
  • Seam(接缝,Michael Feathers):一个可以在不编辑该处的情况下改变行为的地方;即模块接口所在的位置。接缝放在哪里本身就是一个设计决策,与接缝之后放什么不同。避免使用 boundary(与 DDD 的限界上下文混淆)。
  • Adapter(适配器):在接缝处满足某个接口的具体事物。它描述的是角色(填补哪个槽位),而非实质(内部是什么)。
  • Leverage(杠杆):调用方从深度中获得的东西:每学习一单位接口就能获得更多能力。一个实现可在 N 个调用点和 M 个测试中得到回报。
  • Locality(局部性):维护者从深度中获得的东西:变更、缺陷、知识和验证集中在一处,而不是散布到各调用方。修一次,处处修复。

深与浅

深模块 = 小接口 + 大量实现:小接口(少量方法、简单参数),深度实现(隐藏复杂逻辑)。

浅模块 = 大接口 + 少量实现(应避免):大接口(许多方法、复杂参数),单薄实现(只是透传)。

设计接口时可以问:

  • 我能减少方法数量吗?
  • 我能简化参数吗?
  • 我能把更多复杂性藏在内部吗?

原则

  • 深度是接口的属性,而不是实现的属性。深模块内部可以由小的、可模拟的、可替换的部分组成——它们只是不属于接口。模块可以有内部接缝(实现私有,供自身测试使用),也可以有位于其接口处的外部接缝。
  • 删除测试:想象删除该模块。如果复杂性消失了,它就是个透传;如果复杂性在 N 个调用方处重新出现,它就物有所值。
  • 接口即测试面。调用方和测试跨越同一个接缝。若想越过接口去测试,模块的形状可能就是错的。
  • 一个适配器意味着假想的接缝,两个适配器才意味着真实的接缝。除非确实有东西在接缝两侧变化,否则不要引入接缝。

面向可测试性的设计

好的接口让测试变得自然:

  • 接受依赖,而不是创建依赖。可测试写法:function processOrder(order, paymentGateway) {};难以测试的写法:function processOrder(order) { const gateway = new StripeGateway(); }
  • 返回结果,而不是产生副作用。可测试写法:function calculateDiscount(cart): Discount {};难以测试的写法:function applyDiscount(cart): void { cart.total -= discount; }
  • 缩小接口面积。更少方法 = 需要更少测试;更少参数 = 更简单的测试准备。

关系

  • 一个 Module 恰好有一个 Interface(呈现给调用方和测试的表面)。
  • Depth 是 Module 的属性,相对于其 Interface 衡量。
  • Seam 是 Module 的 Interface 所在之处。
  • Adapter 位于 Seam 处并满足 Interface。
  • Depth 为调用方产生 Leverage,为维护者产生 Locality。

被否定的说法

  • 把深度视为实现行数与接口行数的比率(Ousterhout):会奖励填充实现。此处改用“深度即杠杆”。
  • 把“Interface”理解为 TypeScript 的 interface 关键字或类的公共方法:过于狭窄——此处接口包括调用方必须知道的每个事实。
  • “Boundary”:与 DDD 的限界上下文混淆。应说 seam 或 interface。

深入阅读

  • 给定依赖时加深一个集群——见 DEEPENING.md:依赖类别、接缝纪律,以及“替换而非分层”的测试方式。
  • 探索替代接口——见 DESIGN-IT-TWICE.md:启动并行子代理,以若干截然不同的方式设计接口,然后按深度、局部性和接缝位置进行比较。

限制

  • 当工作流指名上游工具、账号、API 密钥或本地环境时,需要具备这些条件。
  • 除非用户明确批准,不授权破坏性、生产、付费或对外消息类操作。
  • 在把生成的产物或建议当作最终结果之前,应针对用户的真实来源进行验证。
  • 官方文本暂未提供。