Communitygithub.com

Razsk/VideoStudio

用于设计深度模块的共享词汇表。当用户想要设计或改进模块接口、寻找深化机会、决定接缝位置、使代码更可测试或更易于AI导航,或其他技能需要深度模块词汇时使用。

VideoStudio 是什么?

该技能为软件模块设计提供了一套精确的共享词汇表,核心目标是设计“深度模块”:以小型接口暴露大量行为,并放置在清晰的接缝处。它定义了“模块”“接口”“深度”“接缝”“适配器”等术语,并强调用一致的术语代替“组件”“服务”“API”“边界”等模糊概念。该技能支持在Claude Code、Cursor等AI代理工具中使用,通过提供设计原则(如“接口是测试表面”“一个适配器是假设接缝,两个才是真正接缝”)、深度与浅度模块对比图,以及代码示例(如依赖注入、返回结果而非副作用),帮助开发者创建可测试、可维护且易于AI导航的代码结构。它还包含指向DEEPENING.md和DESIGN-IT-TWICE.md的链接,以支持进一步深化模块设计或探索多种接口方案。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Razsk/VideoStudio/tree/HEAD/.agents/skills/codebase-design

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

代码库设计

设计深度模块:将大量行为放在小型接口后面,放置在干净的接缝处,并通过该接口进行测试。无论代码正在被设计还是重构,都使用此语言和这些原则。目标是调用者的杠杆作用、维护者的局部性以及所有人的可测试性。

术语表

务必使用这些术语,不要用“组件”“服务”“API”或“边界”替代。一致的语言是关键。

模块:任何具有接口和实现的事物。有意跨缩放级别通用:一个函数、类、包或跨层切片。避免:单元、组件、服务。

接口:调用者在正确使用模块时必须知道的一切:类型签名,还有不变性、顺序约束、错误模式、所需配置和性能特征。避免:API、签名(过于狭窄,仅指类型层面的表面)。

实现:模块内部的内容,其代码体。与适配器不同:一个东西可以是小型适配器+大型实现(如Postgres仓库),也可以是大型适配器+小型实现(如内存模拟)。当接缝是主题时用“适配器”;否则用“实现”。

深度:接口处的杠杆作用。调用者(或测试)每学会一个接口单位所能行使的行为量。当大量行为隐藏在小型接口后面时,模块是深度的;当接口几乎和实现一样复杂时,则是浅度的。

接缝(Michael Feathers):可以在不编辑该位置的情况下改变行为的地方;模块接口所在的位置。在哪里放置接缝本身是一个设计决策,与接口背后放什么无关。避免:边界(在DDD的限界上下文中过度使用)。

适配器:满足接缝处接口的具体事物。描述角色(填充什么位置),而不是实质(内部有什么)。

杠杆作用:调用者从深度中获得的好处。每学会一个接口单位获得更多能力。一个实现偿还给N个调用点和M个测试。

局部性:维护者从深度中获得的好处。变更、错误、知识和验证集中在一个地方,而不是散布在调用者之间。一次修复,处处生效。

深度与浅度

深度模块 = 小型接口 + 大量实现:

┌─────────────────────┐
│   小型接口          │  ← 少数方法,简单参数
├─────────────────────┤
│                     │
│  深度实现           │  ← 隐藏的复杂逻辑
│                     │
└─────────────────────┘

浅度模块 = 大型接口 + 少量实现(避免):

┌─────────────────────────────────┐
│       大型接口                  │  ← 许多方法,复杂参数
├─────────────────────────────────┤
│  薄实现                         │  ← 仅透传
└─────────────────────────────────┘

设计接口时,问:

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

原则

  • 深度是接口的属性,而不是实现的属性。 深度模块内部可以由小的、可模拟的、可替换的部件组成;它们只是不在接口中。模块可以有内部接缝(对实现私有,供其自身测试使用)以及其接口处的外部接缝。
  • 删除测试。 想象删除该模块。如果复杂性消失,它只是一个透传。如果复杂性重新出现在N个调用者中,说明它值得存在。
  • 接口是测试表面。 调用者和测试跨越相同的接缝。如果你想测试越过接口,模块很可能形状不对。
  • 一个适配器意味着假设的接缝。两个适配器意味着真正的接缝。 除非有东西实际在接缝处变化,否则不要引入接缝。

为可测试性设计

好的接口使测试自然:

  1. 接受依赖,不要创建它们。

    // 可测试
    function processOrder(order, paymentGateway) {}
    
    // 难以测试
    function processOrder(order) {
      const gateway = new StripeGateway();
    }
    
  2. 返回结果,不要产生副作用。

    // 可测试
    function calculateDiscount(cart): Discount {}
    
    // 难以测试
    function applyDiscount(cart): void {
      cart.total -= discount;
    }
    
  3. 小表面积。 更少的方法 = 更少的测试需求。更少的参数 = 更简单的测试设置。

关系

  • 模块恰好有一个接口(它呈现给调用者和测试的表面)。
  • 深度是模块的属性,相对于其接口来衡量。
  • 接缝是模块的接口所在的位置。
  • 适配器位于接缝处,并满足接口。
  • 深度为调用者产生杠杆作用,为维护者产生局部性。

拒绝的框架

  • 深度作为实现行数与接口行数之比(Ousterhout):奖励填充实现。我们使用深度即杠杆作用的框架。
  • 将“接口”当作TypeScript的interface关键字或类的公共方法:过于狭窄:这里的接口包含调用者必须知道的每一个事实。
  • “边界”:在DDD的限界上下文中过度使用。使用接缝或接口。

深入探索

  • 根据依赖关系深化集群,参见DEEPENING.md:依赖分类、接缝纪律以及替换而非分层的测试。
  • 探索替代接口,参见DESIGN-IT-TWICE.md:启动并行子代理,以多种根本不同的方式设计接口,然后在深度、局部性和接缝放置方面进行比较。

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

相关技能