Files
2nd/10_Wiki/Topics/Architecture/Executable_Documentation.md
T
2026-05-10 22:08:15 +09:00

6.6 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-executable-documentation Executable Documentation 10_Wiki/Topics verified self
Living Documentation
Runnable Docs
Doc Tests
none A 0.92 applied
documentation
bdd
doctest
testing
ai
2026-05-10 pending
language framework
polyglot docs-as-code

Executable Documentation

매 한 줄

"매 docs 의 CI 의 run — 매 stale 의 fail". 매 docs 의 prose 의 not — 매 examples / scenarios / API specs 의 매 actually-execute. 매 1990s Donald Knuth literate programming + Python doctest 의 origin, 매 2020s Cucumber/BDD 의 popularize, 매 2026 의 매 LLM-assisted doc generation + verification 의 standard practice.

매 핵심

매 종류

  1. Doctest — 매 docstring 안의 example 의 run (Python doctest, Rust doctests).
  2. BDD — Gherkin (Given/When/Then) 의 step 의 bind (Cucumber, Behave).
  3. API docs from spec — OpenAPI → contract test (Schemathesis, Dredd).
  4. Notebook docs — Jupyter / Quarto / Marimo 의 매 cell 의 run.
  5. Markdown code-fence testmdsh, mdocc, markdown-doctest.
  6. AI-verified docs — 매 LLM 의 docs 의 read + code 의 inspect + drift 의 detect.

매 왜 valuable

  • 매 docs 의 truth = code 의 truth.
  • 매 onboarding example 의 매 always working.
  • 매 API contract 의 single source of truth.
  • 매 refactor 시 docs 의 break — 매 catch.

매 응용

  1. SDK / library docs (매 examples 의 always-correct).
  2. API contract testing (OpenAPI + Schemathesis).
  3. BDD acceptance tests (매 PM-readable).
  4. Tutorial CI (매 step-by-step 의 verify).

💻 패턴

Pattern 1: Python doctest

def fibonacci(n: int) -> int:
    """Return the n-th Fibonacci number.

    >>> fibonacci(0)
    0
    >>> fibonacci(10)
    55
    >>> [fibonacci(i) for i in range(7)]
    [0, 1, 1, 2, 3, 5, 8]
    """
    a, b = 0, 1
    for _ in range(n): a, b = b, a + b
    return a

# pytest --doctest-modules

Pattern 2: Rust doctest

/// Adds two numbers.
///
/// # Examples
/// ```
/// use mycrate::add;
/// assert_eq!(add(2, 3), 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 { a + b }

// cargo test --doc

Pattern 3: Cucumber BDD (TS)

# features/checkout.feature
Feature: Checkout
  Scenario: Successful purchase
    Given a cart with 2 items totaling $50
    And a valid Stripe token "tok_visa"
    When the user submits checkout
    Then the order status should be "paid"
    And a confirmation email is queued
// step defs
import { Given, When, Then } from "@cucumber/cucumber";
Given("a cart with {int} items totaling ${int}", function (n, total) {
  this.cart = makeCart(n, total);
});
When("the user submits checkout", async function () {
  this.result = await checkout(this.cart, this.token);
});
Then("the order status should be {string}", function (status) {
  expect(this.result.status).toBe(status);
});

Pattern 4: OpenAPI contract test (Schemathesis)

schemathesis run https://api.example.com/openapi.json \
  --checks all \
  --hypothesis-deadline 5000
# 매 매 endpoint 의 spec 의 conform 의 verify (property-based).

Pattern 5: Markdown code-fence test

// scripts/test-readme.ts
import { readFileSync } from "fs";
import { execSync } from "child_process";

const md = readFileSync("README.md", "utf8");
const blocks = [...md.matchAll(/```typescript\n([\s\S]*?)\n```/g)];

for (const [, code] of blocks) {
  const tmp = `/tmp/snippet-${Date.now()}.ts`;
  require("fs").writeFileSync(tmp, code);
  execSync(`tsx ${tmp}`, { stdio: "inherit" });
}

Pattern 6: Quarto / Marimo notebook

# 매 marimo notebook — 매 reactive, 매 git-friendly
import marimo as mo

@mo.cell
def fetch():
    import requests
    return requests.get("https://api.example.com/users").json()

@mo.cell
def show(fetch):
    return mo.ui.table(fetch)

# 매 marimo run notebook.py — 매 docs + working app.

Pattern 7: AI-verified doc drift (2026)

import Anthropic from "@anthropic-ai/sdk";
const ai = new Anthropic();

async function checkDocDrift(docPath: string, codeGlob: string) {
  const docs = readFileSync(docPath, "utf8");
  const code = await loadFiles(codeGlob);

  const res = await ai.messages.create({
    model: "claude-opus-4-7",
    max_tokens: 2000,
    system: "You verify docs match code. Output JSON: {drifts:[{location, doc_says, code_actually}]}",
    messages: [{
      role: "user",
      content: `DOCS:\n${docs}\n\nCODE:\n${code}\n\nFind drift.`,
    }],
  });
  return JSON.parse(res.content[0].text);
}
// CI 의 매 fail 의 drift 의 found 시.

Pattern 8: Architecture decision record (ADR) with assertion

# ADR-0042: Use Postgres for primary store

## Decision
PostgreSQL 16 의 single-tenant DB.

## Verification (run in CI)
\`\`\`bash
# 매 docs 의 claim 의 verify
psql $DATABASE_URL -c "SELECT version();" | grep -q "PostgreSQL 16"
\`\`\`

매 결정 기준

상황 Approach
Library / SDK doctest (Python/Rust)
REST API OpenAPI + Schemathesis
Acceptance test (PM) Cucumber BDD
Tutorial / book Markdown code-fence test
Data analysis Quarto / Marimo
Architecture docs AI drift detector

기본값: 매 README 예제 의 매 CI 의 run, 매 API 의 OpenAPI 의 contract test.

🔗 Graph

🤖 LLM 활용

언제: 매 docs drift detection, 매 example generation 의 verify, 매 BDD step 의 generate. 언제 X: 매 internal scratchpad notes — 매 over-engineering.

안티패턴

  • Doctest 의 too many: 매 docstring 의 cluttered — 매 separate test 가 better.
  • BDD 의 implementation detail: 매 Given/When/Then 이 SQL 의 mention — 매 wrong abstraction.
  • Spec drift: 매 OpenAPI 의 stale — 매 generate-from-code or test 의 mandatory.
  • No CI: 매 executable 의 X — 매 prose docs 의 same.

🧪 검증 / 중복

  • Verified (Knuth literate programming, Python doctest stdlib, Cucumber.io, Schemathesis docs, Marimo docs).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — doctest/BDD/OpenAPI/Marimo/AI-drift