LabHub

블로그

영어 테크니컬 라이팅: API 문서와 RFC 작성 실전 가이드 2026

한국어English日本語

영어 테크니컬 라이팅: API 문서와 RFC 작성 실전 가이드 2026

개요: 왜 개발자에게 영어 테크니컬 라이팅이 필요한가

코드는 기계가 읽지만, 문서는 사람이 읽는다. API를 아무리 잘 설계해도 문서가 부실하면 채택률은 떨어진다. Stripe가 "개발자 경험(DX)" 1위로 꼽히는 이유는 뛰어난 API 설계뿐 아니라, 읽기 쉽고 정확한 문서 때문이다. GitHub의 2025 Octoverse 보고서에 따르면, 오픈소스 프로젝트의 컨트리뷰터 수와 문서 품질 사이에 강한 양의 상관관계가 있다.

한국 개발자가 영어 기술 문서 작성에서 겪는 어려움은 크게 세 가지다.

  1. 문법보다 구조의 문제: 영어 실력이 충분해도 "어떤 순서로 무엇을 써야 하는지" 모르면 문서 품질이 낮다
  2. 스타일 가이드 부재: 팀 내 일관된 문체 규칙 없이 각자의 스타일로 쓰면 문서 전체가 혼란스러워진다
  3. 도구와 포맷의 장벽: OpenAPI spec, RFC 형식, changelog 규약 등 표준 포맷에 대한 이해 부족

이 글은 일반적인 영작문 팁이 아니라, 개발자가 실무에서 마주치는 구체적인 문서 유형별 작성법을 다룬다. OpenAPI 3.1 기반 API 문서, IETF 스타일 RFC/디자인 문서, README, changelog까지 실제 템플릿과 코드 예시를 중심으로 정리했다.

테크니컬 라이팅의 핵심 원칙

Diataxis 프레임워크: 문서의 4가지 유형

Daniele Procida가 제안한 Diataxis 프레임워크는 기술 문서를 네 가지 유형으로 분류한다. Python 공식 문서, Django, Canonical(Ubuntu) 등이 이 프레임워크를 채택했다.

유형목적독자 상태예시
Tutorial학습(Learning)처음 시작하는 사용자"Getting Started" 가이드
How-to Guide목표 달성(Goal)특정 문제를 해결하려는 사용자"How to paginate API results"
Reference정보 참조(Information)정확한 스펙이 필요한 사용자API endpoint 목록, 파라미터 표
Explanation이해(Understanding)배경과 맥락을 알고 싶은 사용자"Why we chose eventual consistency"

API 문서를 쓸 때 가장 흔한 실수는 Reference(스펙 나열)만 제공하고 Tutorial이나 How-to Guide를 빠뜨리는 것이다. Stripe, Twilio 같은 성공적인 API 제품들은 네 가지 유형을 모두 갖추고 있다.

3대 스타일 가이드 비교

영어 기술 문서 작성의 표준이 되는 세 가지 스타일 가이드를 비교한다.

항목Google Developer Docs Style GuideMicrosoft Writing Style GuideApple Style Guide
Friendly but not informalWarm and relaxed, crisp and clearSimple and direct
인칭2인칭(you) 권장2인칭(you) 권장2인칭(you) 권장
능동태강력 권장강력 권장강력 권장
문장 길이26단어 이하 권장짧고 간결하게간결성 강조
옥스포드 콤마사용사용사용
축약형허용(it's, you're)허용제한적 허용
코드 표기backtick으로 코드 감싸기code formatting 사용코드 폰트 사용
접근성높은 우선순위높은 우선순위높은 우선순위

세 가이드 모두 공통적으로 강조하는 핵심은 명확성(clarity), 간결성(conciseness), 일관성(consistency)이다. 팀에서 하나를 선택해 기준으로 삼되, 프로젝트 내부 스타일 가이드를 우선하는 것이 Google의 권장 사항이다.

API 문서 작성법

OpenAPI 3.1 스펙 기반 문서화

OpenAPI 3.1은 JSON Schema 2020-12와 완전히 호환되며, 웹훅(Webhook) 지원이 추가되어 현재 API 문서화의 사실상 표준이다. 다음은 사용자 관리 API의 OpenAPI 스펙 예시다.

openapi: 3.1.0
info:
  title: User Management API
  version: 2.1.0
  description: |
    Manages user accounts, authentication, and profile data.

    ## Authentication
    All endpoints require a Bearer token in the Authorization header.
    Obtain a token via `POST /auth/token`.

    ## Rate Limiting
    - Authenticated requests: 1000 requests per minute
    - Unauthenticated requests: 60 requests per minute
  contact:
    name: API Support
    email: api-support@example.com
    url: https://developer.example.com/support

servers:
  - url: https://api.example.com/v2
    description: Production
  - url: https://staging-api.example.com/v2
    description: Staging

paths:
  /users:
    get:
      operationId: listUsers
      summary: List all users
      description: |
        Returns a paginated list of users. Results are sorted by
        creation date in descending order by default.
      parameters:
        - name: page
          in: query
          description: Page number (1-indexed)
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: per_page
          in: query
          description: Number of results per page (max 100)
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: status
          in: query
          description: Filter by account status
          schema:
            type: string
            enum: [active, inactive, suspended]
      responses:
        '200':
          description: A paginated list of users
          headers:
            X-Total-Count:
              description: Total number of users matching the query
              schema:
                type: integer
            X-Rate-Limit-Remaining:
              description: Number of requests remaining in the current window
              schema:
                type: integer
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

components:
  schemas:
    User:
      type: object
      required: [id, email, created_at]
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for the user
          examples: ['550e8400-e29b-41d4-a716-446655440000']
        email:
          type: string
          format: email
          description: User's email address
        display_name:
          type: ['string', 'null']
          description: User's display name. Null if not set.
          maxLength: 100
        status:
          type: string
          enum: [active, inactive, suspended]
          description: Current account status
        created_at:
          type: string
          format: date-time
          description: Account creation timestamp (ISO 8601)

    Pagination:
      type: object
      properties:
        current_page:
          type: integer
        total_pages:
          type: integer
        total_count:
          type: integer

  responses:
    Unauthorized:
      description: Authentication credentials are missing or invalid
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: 'UNAUTHORIZED'
              message: 'Bearer token is missing or expired'

    RateLimited:
      description: Too many requests
      headers:
        Retry-After:
          description: Seconds to wait before retrying
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: 'RATE_LIMITED'
              message: 'Rate limit exceeded. Retry after 30 seconds.'

    Error:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: string
              description: Machine-readable error code
            message:
              type: string
              description: Human-readable error description
            details:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                  reason:
                    type: string

이 스펙에서 주목할 포인트를 정리한다.

엔드포인트 문서 작성 규칙

개별 엔드포인트를 문서화할 때 따라야 할 규칙이다.

1. Summary는 동사로 시작한다

Good:  "List all users"
Good:  "Create a new payment intent"
Good:  "Delete a webhook endpoint"

Bad:   "This endpoint lists all users"
Bad:   "Getting user information"
Bad:   "User list"

2. Description은 "무엇을 하는가"와 "주의할 점"을 포함한다

Good:
  Returns a paginated list of users. Results are sorted by creation
  date in descending order by default. Only returns users within
  the authenticated organization's scope.

Bad:
  Gets users.

3. 파라미터에는 제약 조건과 기본값을 반드시 명시한다

Good:
  per_page (integer) - Number of results per page.
  Minimum: 1, Maximum: 100, Default: 20

Bad:
  per_page (integer) - Page size.

에러 코드 문서화

API 에러 응답은 개발자가 가장 자주 참조하는 문서 중 하나다. 다음은 에러 코드를 체계적으로 문서화하는 구조다.

# Error Response Documentation Template
errors:
  - code: 'VALIDATION_ERROR'
    status: 400
    description: 'Request body or query parameters failed validation'
    causes:
      - 'Required field is missing'
      - 'Field value exceeds maximum length'
      - 'Invalid enum value'
    example:
      error:
        code: 'VALIDATION_ERROR'
        message: 'Validation failed'
        details:
          - field: 'email'
            reason: 'must be a valid email address'
          - field: 'display_name'
            reason: 'must not exceed 100 characters'

  - code: 'RESOURCE_NOT_FOUND'
    status: 404
    description: 'The requested resource does not exist or you lack permission to access it'
    causes:
      - 'Resource was deleted'
      - 'Resource ID is malformed'
      - 'Resource belongs to a different organization'
    example:
      error:
        code: 'RESOURCE_NOT_FOUND'
        message: 'User 550e8400-e29b-41d4-a716-446655440000 not found'

  - code: 'CONFLICT'
    status: 409
    description: 'The request conflicts with the current state of the resource'
    causes:
      - 'Email address already registered'
      - 'Concurrent modification detected (stale ETag)'
    example:
      error:
        code: 'CONFLICT'
        message: 'A user with this email already exists'
        details:
          - field: 'email'
            reason: 'already_exists'

  - code: 'INTERNAL_ERROR'
    status: 500
    description: 'An unexpected server error occurred. The team has been notified.'
    causes:
      - 'Unhandled exception'
      - 'Downstream service failure'
    example:
      error:
        code: 'INTERNAL_ERROR'
        message: 'An internal error occurred. Reference ID: req_abc123'

에러 문서화에서 핵심 규칙은 다음과 같다.

API 문서 도구 비교

도구유형OpenAPI 지원주요 특징가격
Swagger UI오픈소스3.0, 3.1인터랙티브 테스트 콘솔, 가장 큰 커뮤니티무료
Redoc오픈소스3.0, 3.13-panel 레이아웃, 깔끔한 디자인, 주간 100만 다운로드무료 (Redocly Pro 유료)
StoplightSaaS3.0, 3.1Design-first 접근, 모킹, 거버넌스유료 (SmartBear 인수)
MintlifySaaS3.0, 3.1MDX 기반, 커스터마이징 용이무료 플랜 존재
ReadMeSaaS3.0, 3.1인터랙티브 문서, API 메트릭스유료
Bump.shSaaS3.0, 3.1Git 연동 자동 배포, diff 추적무료 플랜 존재

스타트업이나 오픈소스 프로젝트라면 Redoc으로 시작하는 것을 권장한다. 설정 없이 빠르게 배포 가능하며, 프로덕션 수준의 문서를 즉시 생성한다. 엔터프라이즈 환경에서는 Redocly Pro나 ReadMe가 API 메트릭스와 버전 관리를 지원해 적합하다.

RFC/디자인 문서 작성법

RFC의 목적과 구조

소프트웨어 엔지니어링에서 RFC(Request for Comments)는 IETF의 인터넷 표준 문서에서 유래했지만, 현재는 사내 기술 의사결정 문서로 널리 사용된다. Google, Meta, Uber 등 대형 테크 기업들이 주요 기술 결정을 RFC로 문서화한다.

RFC의 핵심 가치는 "말"이 아닌 "글"로 기술 결정을 내리는 것이다. 회의에서는 목소리 큰 사람이 이기지만, RFC에서는 논리가 이긴다.

다음은 실무에서 바로 사용할 수 있는 RFC 템플릿이다.

# RFC: [Title]

- **Author(s):** [Names]
- **Status:** Draft | In Review | Accepted | Rejected | Superseded
- **Created:** YYYY-MM-DD
- **Last Updated:** YYYY-MM-DD
- **Reviewers:** [Names]
- **Decision Deadline:** YYYY-MM-DD

## Summary

[2-3 sentences describing the proposal. A reader should understand
the core idea after reading only this section.]

## Motivation

[Why is this change necessary? What problem does it solve?
Include data, metrics, or user feedback that supports the need.]

### Current State

[Describe the current system/process and its limitations.]

### Desired State

[Describe the target state after implementing this proposal.]

## Detailed Design

### Architecture Overview

[High-level architecture diagram or description]

### API Changes

[Any new or modified API endpoints, schemas, or contracts]

### Data Model Changes

[Database schema changes, migration strategy]

### Implementation Plan

[Phased rollout plan with milestones]

| Phase | Scope | Timeline | Success Criteria |
| ----- | ----- | -------- | ---------------- |
| 1     |       |          |                  |
| 2     |       |          |                  |

## Alternatives Considered

### Alternative 1: [Name]

[Description, pros, cons, and why it was not chosen]

### Alternative 2: [Name]

[Description, pros, cons, and why it was not chosen]

## Risks and Mitigations

| Risk | Likelihood | Impact | Mitigation |
| ---- | ---------- | ------ | ---------- |
|      |            |        |            |

## Security Considerations

[Authentication, authorization, data privacy impacts]

## Backward Compatibility

[Breaking changes, migration path, deprecation timeline]

## Observability

[Logging, monitoring, alerting changes needed]

## Open Questions

- [ ] [Question 1]
- [ ] [Question 2]

## References

- [Link to related RFC, design doc, or external resource]

RFC 작성 핵심 규칙

1. Summary를 먼저 쓰고 나머지를 채운다

바쁜 시니어 엔지니어는 Summary만 읽고 리뷰할지 결정한다. Summary가 불명확하면 문서 전체가 무시된다. 다음 구조를 따른다.

Good Summary:
  This RFC proposes replacing our current Redis-based session store
  with a JWT-based stateless authentication system. This change
  reduces infrastructure costs by ~40% and eliminates the session
  store as a single point of failure.

Bad Summary:
  This document discusses authentication improvements.

2. Alternatives Considered는 필수다

대안을 고려하지 않은 RFC는 설득력이 없다. 최소 2가지 대안을 제시하고, 각각의 장단점을 명확히 기술한 뒤 현재 제안이 더 나은 이유를 설명한다.

3. 명확한 Decision Deadline을 설정한다

기한 없는 RFC는 영원히 리뷰되지 않는다. "Please review by March 15"처럼 구체적 날짜를 명시한다.

4. Open Questions로 논의를 유도한다

모든 것을 결정한 RFC보다, 의도적으로 열린 질문을 남긴 RFC가 더 좋은 피드백을 받는다.

README 작성법

README는 프로젝트의 첫인상이다. 오픈소스 프로젝트의 경우 README 품질이 곧 프로젝트의 신뢰도를 결정한다. 다음은 필수 섹션을 포함한 README 템플릿이다.

# Project Name

[![Build Status](https://img.shields.io/github/actions/workflow/status/org/repo/ci.yml)](link)
[![npm version](https://img.shields.io/npm/v/package-name)](link)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](link)

One-line description: what it does and who it's for.

## Features

- **Feature 1** - Brief description
- **Feature 2** - Brief description
- **Feature 3** - Brief description

## Quick Start

### Prerequisites

- Node.js >= 18.0
- PostgreSQL >= 15

### Installation

npm install package-name

### Basic Usage

import Client from 'package-name';

const client = new Client({ apiKey: process.env.API_KEY });
const result = await client.doSomething({ param: 'value' });
console.log(result);

## Documentation

- [Getting Started Guide](docs/getting-started.md)
- [API Reference](docs/api-reference.md)
- [Configuration](docs/configuration.md)
- [Migration Guide](docs/migration.md)

## Contributing

We welcome contributions. Please read our
[Contributing Guide](CONTRIBUTING.md) before submitting a PR.

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing`)
5. Open a Pull Request

## License

This project is licensed under the MIT License.
See [LICENSE](LICENSE) for details.

README 작성에서 자주 하는 실수와 개선 방법을 정리한다.

문체 가이드라인

능동태(Active Voice) 사용

Google, Microsoft, Apple의 스타일 가이드 모두 능동태를 기본으로 권장한다. 수동태는 문장을 길고 모호하게 만든다.

수동태 (Avoid)능동태 (Prefer)
The file is created by the systemThe system creates the file
The request should be sent by the clientThe client sends the request
Errors can be handled by using try-catchHandle errors with try-catch
The configuration must be updated before deploymentUpdate the configuration before deployment
It is recommended that TLS 1.3 be usedUse TLS 1.3

수동태가 적절한 예외 상황도 있다. 행위자가 중요하지 않거나 의도적으로 생략해야 할 때다.

Passive OK: "The data is encrypted at rest using AES-256."
(누가 암호화하는지보다 암호화 사실 자체가 중요)

Passive OK: "Deprecated endpoints will be removed in v3.0."
(누가 제거하는지보다 제거 사실이 중요)

간결성(Conciseness) 확보

불필요한 단어를 제거하면 문서의 정보 밀도가 올라간다.

장황한 표현간결한 표현
In order toTo
Due to the fact thatBecause
At the present timeNow / Currently
In the event thatIf
It is necessary toYou must / Must
For the purpose ofTo / For
A large number ofMany
Has the ability toCan
Prior toBefore
In addition toAlso

실전 교정 예시:

Before:
  In order to configure the database connection, it is necessary
  to set the DATABASE_URL environment variable prior to starting
  the application server.

After:
  Set the DATABASE_URL environment variable before starting the
  application server.

28단어가 14단어로 줄었다. 정보 손실은 없다.

일관성(Consistency) 유지

같은 개념을 여러 단어로 표현하면 독자가 혼란스러워한다.

Inconsistent:
  "Click the Submit button." ... "Press the Send button."
  ... "Tap the Confirm button."

Consistent:
  "Click Submit." ... "Click Send." ... "Click Confirm."

일관성을 유지하기 위한 규칙은 다음과 같다.

자주 하는 실수와 교정 예시

한국어 사고방식에서 비롯되는 영어 기술 문서의 대표적인 실수를 정리한다.

1. 주어 생략

한국어는 주어를 자주 생략하지만, 영어 기술 문서에서는 주어를 반드시 명시해야 한다.

Bad:  "Can configure by editing the config file."
Good: "You can configure the service by editing the config file."

Bad:  "Must restart after changing settings."
Good: "Restart the server after changing settings."

단, 절차(Procedure) 설명에서는 명령문(imperative)을 사용하므로 주어 "You"를 생략한다. "Configure the database"는 올바른 명령문이다.

2. 관사(a, an, the) 오용

Bad:  "Send request to endpoint."
Good: "Send a request to the endpoint."

Bad:  "The each user has unique ID."
Good: "Each user has a unique ID."

Bad:  "Restart a server." (특정 서버를 가리킬 때)
Good: "Restart the server."

기본 규칙: 처음 언급하면 a/an, 이미 언급했거나 유일한 것이면 the, 일반적 개념이면 무관사(복수형).

3. 불필요한 "please" 사용

기술 문서는 대화가 아니다. 절차 설명에서 "please"는 불필요한 노이즈다.

Bad:  "Please click the Save button."
Good: "Click Save."

Bad:  "Please note that this feature requires admin access."
Good: "This feature requires admin access."

4. 동사-명사 혼동

Bad:  "Do the setup of the environment."
Good: "Set up the environment."

Bad:  "Perform the deletion of old records."
Good: "Delete old records."

Bad:  "Make a configuration change."
Good: "Change the configuration."

동사로 직접 표현할 수 있는 것을 명사화(nominalization)하면 문장이 길어지고 약해진다.

5. 모호한 대명사

Bad:  "The client sends a request to the server. It processes
       the data and returns a response. It then parses the JSON."
       (It이 client인지 server인지 불명확)

Good: "The client sends a request to the server. The server
       processes the data and returns a response. The client
       then parses the JSON."

Changelog 작성 규칙

Changelog는 API 소비자에게 "무엇이 바뀌었는지"를 알리는 문서다. Keep a Changelog(keepachangelog.com) 형식을 따르는 것이 표준이다.

# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/),
and this project adheres to [Semantic Versioning](https://semver.org/).

## [2.1.0] - 2026-03-01

### Added

- `GET /users` endpoint now supports `status` query parameter
  for filtering by account status (#234)
- Rate limit headers (`X-Rate-Limit-Remaining`) included in
  all responses (#241)

### Changed

- Default pagination size changed from 50 to 20 for improved
  response times (#238)
- Error response format unified across all endpoints to use
  the standard error schema (#240)

### Deprecated

- `GET /users/search` endpoint. Use `GET /users` with query
  parameters instead. Will be removed in v3.0. (#235)

### Fixed

- Fixed race condition in concurrent user updates that could
  cause data loss (#237)
- Corrected OpenAPI spec for `PATCH /users` to include
  `display_name` field (#239)

## [2.0.0] - 2026-02-15

### Removed

- Removed `GET /users/list` endpoint (deprecated since v1.5)
- Dropped support for API key authentication. Use Bearer
  tokens instead.

### Changed

- **BREAKING:** User ID format changed from integer to UUID

Changelog에서 지켜야 할 핵심 규칙을 정리한다.

리뷰 체크리스트

기술 문서를 작성한 후, 다음 체크리스트로 셀프 리뷰를 수행한다.

구조 (Structure)

문체 (Style)

코드 및 기술 정보 (Technical Accuracy)

독자 관점 (Reader Experience)

접근성 (Accessibility)

도구 추천

작성 도구

도구용도특징
Vale스타일 린팅Google/Microsoft 스타일 가이드 규칙을 자동 검사. CI/CD 파이프라인에 통합 가능
Grammarly문법/스타일 검사브라우저 확장, IDE 플러그인 지원. Technical writing 톤 설정 가능
Hemingway Editor가독성 검사수동태, 복잡한 문장, 부사 과다 사용을 시각적으로 표시
LanguageTool문법 검사오픈소스 대안. 셀프 호스팅 가능
write-good스타일 린팅npm 패키지. CLI에서 마크다운 파일 검사. weasel words, passive voice 탐지

문서 생성 도구

도구입력출력특징
DocusaurusMDX정적 사이트React 기반, 버전 관리, 검색 내장
MkDocs (Material)Markdown정적 사이트Python 기반, 깔끔한 디자인
NextraMDXNext.js 사이트Next.js 프로젝트에 자연스럽게 통합
Astro StarlightMDX정적 사이트빠른 빌드, 다국어 지원, 접근성 우선
SphinxreStructuredText다양Python 생태계 표준, 크로스 레퍼런싱 강력

CI/CD 통합 파이프라인

문서 품질을 자동으로 검증하는 파이프라인 구성 예시다.

# .github/workflows/docs-lint.yml
name: Documentation Lint

on:
  pull_request:
    paths:
      - 'docs/**'
      - '*.md'
      - 'openapi/**'

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Lint prose with Vale
        uses: errata-ai/vale-action@v2
        with:
          files: docs/
          config: .vale.ini

      - name: Validate OpenAPI spec
        run: |
          npx @redocly/cli lint openapi/spec.yaml

      - name: Check for broken links
        uses: lycheeverse/lychee-action@v2
        with:
          args: --verbose docs/

      - name: Spell check
        uses: streetsidesoftware/cspell-action@v6
        with:
          files: 'docs/**/*.md'

이 파이프라인은 PR이 docs 디렉토리나 마크다운 파일을 수정할 때 자동 실행된다. Vale이 스타일 규칙을 검사하고, Redocly CLI가 OpenAPI 스펙의 유효성을 검증하며, lychee가 깨진 링크를 찾고, cspell이 오타를 검출한다.

실전 적용 로드맵

테크니컬 라이팅 역량을 단계적으로 쌓기 위한 로드맵을 제안한다.

1주차 - 기초 확립

2주차 - API 문서화

3주차 - RFC 연습

4주차 - 자동화 구축

이 과정을 거치면 "영어를 잘 쓰는 것"이 아니라 "좋은 기술 문서를 쓰는 것"에 집중할 수 있게 된다. 기술 문서의 품질은 영어 실력보다 구조적 사고와 독자 관점의 이해에서 결정된다.

참고자료

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다