TechLead
Lesson 19 of 20
5 min read
DevTools & Productivity

Documentation as Code

Write and maintain technical documentation using code-first approaches with JSDoc, TypeDoc, Storybook, and MDX

Documentation as Code

"Documentation as code" means treating documentation with the same rigor as source code: it lives in the repository, goes through code review, is versioned with Git, and is generated or validated automatically. This approach keeps documentation accurate and up-to-date because it is maintained alongside the code it describes.

Documentation Types

  • API Reference: Auto-generated from TypeScript types and JSDoc comments
  • Component Docs: Visual, interactive documentation with Storybook
  • Architecture Docs: Decision records, diagrams, and system overview
  • Guides and Tutorials: Step-by-step instructions for common tasks
  • Inline Documentation: JSDoc comments that appear in editor tooltips

JSDoc for Inline Documentation

JSDoc comments appear in VS Code tooltips, providing instant documentation without leaving the editor. They work with TypeScript to add rich descriptions to types, functions, and parameters.

/**
 * Formats a number as a currency string.
 *
 * @param amount - The numeric amount to format
 * @param currency - ISO 4217 currency code (default: 'USD')
 * @param locale - BCP 47 locale string (default: 'en-US')
 * @returns Formatted currency string (e.g., "$1,234.56")
 *
 * @example
 * ```ts
 * formatCurrency(1234.5)           // "$1,234.50"
 * formatCurrency(1234.5, 'EUR')    // "€1,234.50"
 * formatCurrency(1234.5, 'JPY', 'ja-JP') // "¥1,235"
 * ```
 *
 * @throws {RangeError} If currency code is invalid
 * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat | Intl.NumberFormat}
 */
export function formatCurrency(
  amount: number,
  currency: string = 'USD',
  locale: string = 'en-US',
): string {
  return new Intl.NumberFormat(locale, {
    style: 'currency',
    currency,
  }).format(amount);
}

/**
 * A paginated API response wrapper.
 *
 * @typeParam T - The type of items in the response
 *
 * @example
 * ```ts
 * const response: PaginatedResponse<User> = {
 *   data: [{ id: '1', name: 'Alice' }],
 *   meta: { page: 1, limit: 20, total: 100 },
 * };
 * ```
 */
export interface PaginatedResponse<T> {
  /** The array of items for the current page */
  data: T[];
  /** Pagination metadata */
  meta: {
    /** Current page number (1-indexed) */
    page: number;
    /** Number of items per page */
    limit: number;
    /** Total number of items across all pages */
    total: number;
  };
}

TypeDoc for API Documentation

TypeDoc generates HTML documentation from TypeScript source code and JSDoc comments. It reads your types, interfaces, and functions to create navigable API reference documentation.

# Install TypeDoc
npm install -D typedoc

# Generate documentation
npx typedoc --entryPoints src/index.ts --out docs

# With configuration file
npx typedoc
// typedoc.json
{
  "entryPoints": ["src/index.ts"],
  "out": "docs",
  "plugin": ["typedoc-plugin-markdown"],
  "exclude": ["**/*.test.ts", "**/*.spec.ts"],
  "excludePrivate": true,
  "excludeProtected": true,
  "readme": "none",
  "githubPages": false
}

Storybook for Component Documentation

Storybook creates an interactive, visual documentation site for your React components. Each "story" renders a component in a specific state, serving as both documentation and a visual test.

# Initialize Storybook in your project
npx storybook@latest init

# Run Storybook
npm run storybook
// src/components/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';

const meta: Meta<typeof Button> = {
  title: 'Components/Button',
  component: Button,
  tags: ['autodocs'], // Auto-generate docs page
  argTypes: {
    variant: {
      control: 'select',
      options: ['primary', 'secondary', 'destructive'],
      description: 'Visual style variant',
    },
    size: {
      control: 'radio',
      options: ['sm', 'md', 'lg'],
    },
    disabled: { control: 'boolean' },
  },
};

export default meta;
type Story = StoryObj<typeof Button>;

export const Primary: Story = {
  args: {
    children: 'Click me',
    variant: 'primary',
    size: 'md',
  },
};

export const Secondary: Story = {
  args: {
    children: 'Secondary',
    variant: 'secondary',
  },
};

export const AllSizes: Story = {
  render: () => (
    <div style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
      <Button size="sm">Small</Button>
      <Button size="md">Medium</Button>
      <Button size="lg">Large</Button>
    </div>
  ),
};

Architecture Decision Records (ADRs)

ADRs document the "why" behind significant technical decisions. They are short Markdown files stored in the repository that capture context, alternatives considered, and the rationale for each choice.

# docs/adr/001-use-app-router.md
# ADR 001: Use Next.js App Router

## Status
Accepted

## Context
We need to choose between the Next.js Pages Router and App Router
for our new project. The team has experience with Pages Router
but App Router offers React Server Components and improved
data fetching patterns.

## Decision
We will use the App Router because:
- React Server Components reduce client JavaScript bundle size
- Nested layouts improve code organization
- Server Actions simplify form handling
- It is the recommended approach for new Next.js projects

## Consequences
- Team needs to learn new patterns (RSC, Server Actions)
- Some libraries may not yet support Server Components
- We accept the migration cost for long-term benefits

README Templates

# Essential README sections for a project

## Project Name
Brief description of what the project does.

## Quick Start
```bash
git clone 
cd project-name
npm run setup     # Installs deps, sets up DB, checks env
npm run dev       # Starts dev server at http://localhost:3000
```

## Prerequisites
- Node.js 20+
- Docker (for local database)
- npm 10+

## Environment Variables
Copy `.env.example` to `.env.local`:
```
DATABASE_URL=postgresql://...
NEXTAUTH_SECRET=your-secret-here
```

## Scripts
| Command | Description |
|---------|-------------|
| npm run dev | Start development server |
| npm run build | Build for production |
| npm run test | Run tests |
| npm run lint | Run ESLint |

## Architecture
See [docs/architecture.md](docs/architecture.md) for system overview.

Documentation Best Practices

  • Document the "why", not the "what": Code shows what happens. Comments and docs should explain why.
  • Keep docs close to code: JSDoc in source files, stories next to components, ADRs in the repo. Docs in a separate wiki get outdated.
  • Automate what you can: Use TypeDoc, Storybook autodocs, and OpenAPI generators to reduce manual documentation.
  • Review docs in PRs: When code changes, the related documentation should change in the same PR.
  • Include examples: Every function, component, and API endpoint should have at least one usage example.

Continue Learning