Communitygithub.com

pedro-oscar/shorts-ai

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

shorts-ai 是什么?

这是一个专注于代码库设计的AI技能,源于“深度模块”概念:将大量行为隐藏在小接口之后,放置在清晰的切面(Seam)处,并通过该接口进行测试。它提供了精确的设计词汇表(如模块、接口、实现、深度、切面、适配器、杠杆效应和局部性),代替模糊的术语(如组件、服务、API),从而在团队和AI代理之间建立一致的沟通语言。 该技能适用于任何需要设计或重构接口的场景——无论是函数、类、包还是跨层切片。它强调接口是测试表面,深度通过接口的简洁性衡量(而非实现代码行数),并通过“删除测试”等原则避免浅层模块。技能还提供了可测试性设计的具体模式(如接受依赖而非创建、返回结果而非产生副作用),并描述了各概念的精确关系。 它支持在任何编程语言或平台(如Claude Code、Cursor、Codex等AI代理)中使用,但依赖另一份名为“DEEPENING.md”的深化指南和“DESIGN-IT-TWICE.md”的替代接口设计技能。该技能的核心价值在于让设计讨论无歧义,使代码维护和测试更高效。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/pedro-oscar/shorts-ai/tree/HEAD/.claude/skills/codebase-design

在你喜欢的 AI 中提问

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

文档

代码库设计

设计深度模块:将大量行为隐藏在小接口之后,放置在清晰的切面处,并通过该接口进行测试。在任何设计或重构代码的地方,使用此语言和这些原则。目标是:调用方获得杠杆效应,维护方获得局部性,所有人都获得可测试性。

词汇表

请精确使用这些术语:不要替换为“组件”、“服务”、“API”或“边界”。一致的语言是核心要义。

模块:任何具有接口和实现的东西。有意保持规模无关:函数、类、包或跨层切片。避免使用:单元、组件、服务。

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

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

深度:接口处的杠杆效应。调用者(或测试)每学习一个单位的接口所能利用的行为量。当一个模块在小接口后面隐藏了大量行为时,它深度;当接口几乎和实现一样复杂时,它浅薄。

切面(Michael Feathers):可以在不修改该处代码的情况下改变行为的地方;模块接口所在的位置。把切面放在哪里本身就是一个设计决策,与放在它后面的东西不同。避免使用:边界(与DDD的限界上下文含义重叠)。

适配器:一个具体的、满足切面处接口的东西。描述角色(它填充什么槽位),而不是实质(里面有什么)。

杠杆效应:调用者从深度中获得的东西。每学习一个单位的接口,获得更多能力。一份实现回报N个调用点和M个测试。

局部性:维护者从深度中获得的东西。变更、缺陷、知识和验证集中在单个位置,而不是散布在调用者之间。一次修复,处处生效。

深度 vs. 浅薄

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

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

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

┌─────────────────────────────────┐
│       大接口                    │  ← 大量方法,复杂参数
├─────────────────────────────────┤
│   薄实现                        │  ← 只是传递
└─────────────────────────────────┘

设计接口时,问:

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

原则

  • 深度是接口的属性,而不是实现的属性。 一个深度模块内部可以由小的、可模拟的、可替换的部分组成;它们只是不属于接口的一部分。模块可以有内部切面(对其实现私有,供其自身测试使用)以及其接口处的外部切面。
  • 删除测试。 想象删除该模块。如果复杂性消失,它是一个透传。如果复杂性重新出现在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):奖励padding实现。我们改用深度即杠杆效应。
  • “接口”作为TypeScript的 interface 关键字或类的公共方法:太窄;这里的接口包括调用者必须知道的每一个事实。
  • “边界”:与DDD的限界上下文含义重叠。请说切面或接口。

深入探讨

  • 在给定依赖的情况下深化一个集群,参见 DEEPENING.md:依赖分类、切面纪律和替换而非层叠测试。
  • 探索替代接口,参见 DESIGN-IT-TWICE.md:启动并行子代理以数种根本不同的方式设计接口,然后比较深度、局部性和切面放置。

Individual skills in this repo

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

相关技能