Communitygithub.com

Razsk/VideoStudio

用於設計深層模組的共同詞彙。當使用者想要設計或改進模組介面、尋找深化機會、決定接縫位置、讓程式碼更易於測試或 AI 導航,或其他技能需要深層模組詞彙時使用。

VideoStudio 是什麼?

這項技能提供一套精確且一致的詞彙與設計原則,專注於設計「深層模組」:即透過小型介面提供豐富行為的模組,並將其放置在清晰的接縫(Seam)處,使其可透過該介面進行測試。其核心目標是為呼叫者創造槓桿效應(Leverage)、為維護者提供局部性(Locality),並為所有人提升可測試性。技能明確定義了「模組(Module)」、「介面(Interface)」、「實作(Implementation)」、「深度(Depth)」、「接縫(Seam)」與「轉接器(Adapter)」等關鍵術語,並強調使用統一詞彙以避免歧義。此外,它還提供了深度與淺層模組的視覺化對比、具體的設計原則(如刪除測試、介面即測試面)以及提升可測試性的實用程式碼範例。此技能適用於任何需要設計、重構或評估模組介面的場景,支援 TypeScript 等語言,並透過 `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」或「邊界」。一致的語言是關鍵。

模組 (Module):任何具有介面與實作的事物。刻意地尺度中立:可以是一個函式、類別、套件或跨層級的切片。避免使用:單元、元件、服務。

介面 (Interface):呼叫者為正確使用模組而需知道的一切事物:型別簽名,但也包括不變量、排序約束、錯誤模式、必要設定與效能特性。避免使用:API、簽名(過於狹隘,僅指型別層級的表面)。

實作 (Implementation):模組內部的事物,其程式碼主體。與轉接器 (Adapter) 不同:一個東西可以是一個帶有大型實作的小型轉接器(例如 Postgres 儲存庫),或是一個帶有小型實作的大型轉接器(例如記憶體中的假物件)。當討論焦點是接縫時,請使用「轉接器」;其他情況則使用「實作」。

深度 (Depth):介面上的槓桿效應。呼叫者(或測試)每學習一個介面單位,所能運用的行為量。當大量行為位於小型介面之後時,模組即為深層;當介面幾乎與實作一樣複雜時,模組即為淺層。

接縫 (Seam) (Michael Feathers):一個你可以在不修改該處程式碼的情況下改變行為的位置;也是模組介面所處的位置。接縫要放在哪裡本身就是一個設計決策,與放在它後面是什麼東西是分開的。避免使用:邊界(與 DDD 的限界上下文過度重載)。

轉接器 (Adapter):滿足接縫處介面的具體事物。描述其角色(填補什麼插槽),而非本質(內部是什麼)。

槓桿效應 (Leverage):呼叫者從深度中獲得的效益。每學習一個介面單位,就能獲得更多能力。一個實作在 N 個呼叫點與 M 個測試中回報其價值。

局部性 (Locality):維護者從深度中獲得的效益。變更、錯誤、知識與驗證集中在一個地方,而不是分散到多個呼叫者。修復一處,處處修復。

深度 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):會獎勵填充實作。我們改用深度即槓桿效應。
  • 將「介面」視為 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.

相關技能