21  기술 보고서와 문서화

중요코드에서 문서로

API 문서, 기술 보고서, 정부 제출 보고서까지 코드와 함께 자동 생성되는 살아있는 문서를 만들어봅시다.

21.1 Document as Code로 해결하는 기술문서 문제

21.1.1 전통적 기술 문서의 한계

개발 조직에서 반복적으로 겪는 문제들:

1. 동기화 문제

  • 코드 vs 문서 불일치: 코드는 v2.3인데 문서는 v1.8 버전
  • API 변경 미반영: 엔드포인트가 변경되었지만 문서는 그대로
  • 데이터 스키마 불일치: DB 구조 변경이 문서에 반영 안됨

2. 산재한 정보

  • 여러 곳에 둘러쌓인 정보: Wiki, Confluence, GitHub, Slack에 중복 정보
  • 찾기 어려운 정보: 중요한 API 명세가 5개 사이트에 분산
  • 안같은 예제: 같은 기능에 대해 서로 다른 예제 코드

3. 수동 유지보수

  • 개발자의 기억에 의존: “배포할 때 문서도 업데이트해야지”
  • 과도한 인지 부하: 코드 변경 + 테스트 + 문서 업데이트 동시 수행
  • 버전 불일치: 각 문서의 버전 관리가 각각 다름

4. 협업과 일관성 문제

  • 스타일 불일치: 팀원A는 Markdown, 팀원B는 Word, 팀원C는 Confluence
  • 리뷰 누락: 코드리뷰는 엄격하지만 문서리뷰는 느슨하게
  • 성과 추적 어려움: 어떤 문서가 얼마나 유용한지 측정 불가

21.1.2 Document as Code 패러다임의 해결책

핵심 원칙: Single Source of Truth

graph TD
    A[소스코드] --> B[자동 문서 추출]
    B --> C[쿼토 문서]
    C --> D[다중 출력]
    
    E[API 코드] --> F[OpenAPI 스펙]
    F --> C
    
    G[테스트 코드] --> H[예제 추출]
    H --> C
    
    I[GitHub Actions] --> J[자동 배포]
    D --> J
    
    D --> K[HTML 웹사이트]
    D --> L[PDF 보고서]
    D --> M[Word 문서]

21.2 1. API 문서: 코드에서 문서로

21.2.1 OpenAPI 명세 자동 생성

현대적 API 개발에서는 코드와 문서를 동기화하는 것이 필수입니다. FastAPI, Django REST Framework, Express.js 등은 코드에서 직접 문서를 생성하는 기능을 제공합니다.

FastAPI를 활용한 예시

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
import uvicorn

app = FastAPI(
    title="Text Classification API",
    description="Document as Code 패러다임을 적용한 텍스트 분류 API",
    version="1.0.0",
    contact={
        "name": "이광춘",
        "email": "kwangchun@r2bit.com",
        "url": "https://r2bit.com"
    },
    license_info={
        "name": "MIT License",
        "url": "https://opensource.org/licenses/MIT"
    }
)

class TextInput(BaseModel):
    """텍스트 분류를 위한 입력 모델
    
    Attributes:
        text: 분류할 텍스트 (최대 1000자)
        model: 사용할 모델명 (기본값: 'random_forest')
    """
    text: str
    model: Optional[str] = "random_forest"
    
    class Config:
        schema_extra = {
            "example": {
                "text": "이것은 분류할 텍스트 예시입니다.",
                "model": "random_forest"
            }
        }

class ClassificationResult(BaseModel):
    """분류 결과 모델
    
    Attributes:
        category: 예측된 카테고리
        confidence: 예측 신뢰도 (0-1)
        model_used: 사용된 모델명
        processing_time: 처리 시간 (초)
    """
    category: str
    confidence: float
    model_used: str
    processing_time: float

@app.post(
    "/classify",
    response_model=ClassificationResult,
    summary="텍스트 분류",
    description="입력된 텍스트를 사전 학습된 모델로 분류합니다."
)
async def classify_text(input_data: TextInput):
    """
    텍스트를 분류하여 카테고리를 예측합니다.
    
    - **text**: 분류할 텍스트 (필수)
    - **model**: 사용할 모델명 (선택, 기본값: random_forest)
    
    지원 모델:
    - `random_forest`: Random Forest 분류기
    - `logistic_regression`: 로지스틱 회귀
    - `transformer`: Transformer 기반 모델
    
    Returns:
        ClassificationResult: 분류 결과와 메타데이터
    """
    
    # 실제 분류 로직은 여기에 구현
    import time
    start_time = time.time()
    
    # 모의 분류 결과
    result = ClassificationResult(
        category="positive",
        confidence=0.85,
        model_used=input_data.model,
        processing_time=time.time() - start_time
    )
    
    return result

@app.get(
    "/models",
    response_model=List[str],
    summary="사용 가능한 모델 목록",
    description="API에서 사용 가능한 모든 분류 모델의 목록을 반환합니다."
)
async def list_models():
    """사용 가능한 분류 모델 목록을 반환합니다."""
    return ["random_forest", "logistic_regression", "transformer"]

21.2.2 자동 생성된 API 문서 통합

library(jsonlite)
library(knitr)
library(gt)

# OpenAPI 스펙 읽기
openapi_spec <- fromJSON("http://localhost:8000/openapi.json")

# API 엔드포인트 정보 추출
endpoints <- openapi_spec$paths

# 엔드포인트 테이블 생성
endpoint_info <- map_dfr(names(endpoints), function(path) {
  methods <- names(endpoints[[path]])
  
  map_dfr(methods, function(method) {
    info <- endpoints[[path]][[method]]
    
    tibble(
      path = path,
      method = toupper(method),
      summary = info$summary %||% "",
      description = str_trunc(info$description %||% "", 100)
    )
  })
})

endpoint_info %>%
  gt() %>%
  tab_header(
    title = "API 엔드포인트 목록",
    subtitle = "자동 생성된 API 문서"
  ) %>%
  cols_label(
    path = "경로",
    method = "메서드", 
    summary = "요약",
    description = "설명"
  ) %>%
  fmt_markdown(columns = everything()) %>%
  tab_style(
    style = cell_text(weight = "bold"),
    locations = cells_column_labels()
  )

21.3 2. 정부/공공 보고서: 표준화와 자동화

21.3.1 한국 정부 보고서 표준 오엘

정부 보고서는 엄격한 표준 양식을 따라야 합니다. 이를 Document as Code로 처리하면 일관성과 효율성을 동시에 달성할 수 있습니다.

주요 요구사항

  • 표준 양식 준수: 공공기관에서 요구하는 보고서 양식
  • 예산 및 성과 추적: 정량적 지표와 ROI 분석
  • 투명성과 검증가능성: 모든 데이터와 분석 과정 공개
  • 한글 타이포그래피: 공식 문서에 적합한 글꼴 및 레이아웃
---
title: "AI 기반 텍스트 분류 시스템 개발"
subtitle: "2024년도 디지털 혁신 과제 최종보고서"

# 정부 보고서 메타데이터
report_meta:
  project_name: "AI 기반 텍스트 분류 시스템 개발"
  project_code: "2024-DT-001"
  period: "2024년 3월 ~ 2024년 12월"
  budget: "50,000만원"
  
  # 참여기관
  institutions:
    lead: "공익법인 한국 R 사용자회"
    partners: 
      - "한국대학교 AI연구소"
      - "㈜데이터테크"
  
  # 연구진
  researchers:
    pm: "이광춘 (공익법인 한국 R 사용자회)"
    members:
      - "김연구 (한국대학교)"
      - "박개발 (㈜데이터테크)"

format:
  pdf:
    documentclass: article
    fontsize: 12pt
    geometry: 
      - left=3cm
      - right=2cm
      - top=2.5cm
      - bottom=2.5cm
    number-sections: true
    toc: true
    toc-depth: 3
    fig-pos: 'H'
    include-in-header:
      - text: |
          \usepackage{kotex}
          \usepackage{fancyhdr}
          \pagestyle{fancy}
          \fancyhead[L]{2024년도 디지털 혁신 과제}
          \fancyhead[R]{최종보고서}
          \fancyfoot[C]{\thepage}
  
  html:
    theme: cosmo
    css: styles/gov-report.css
    number-sections: true
    toc: true

lang: ko-KR
bibliography: references.bib
---

21.3.2 정부 보고서 본문 구조

# 연구개발 과제 개요

## 연구개발 목표

### 최종 목표
AI 기반 텍스트 분류 시스템을 개발하여 정부 문서 처리의 자동화와 효율성을 향상시킨다.

### 세부 목표
1. **기술적 목표**
   - 한국어 텍스트 분류 정확도 95% 이상 달성
   - 실시간 처리 성능 1,000건/분 이상
   - Document as Code 패러다임 적용

2. **활용적 목표**
   - 정부 민원 자동 분류 시스템 구축
   - 정책 문서 자동 태깅 시스템 개발
   - 공공 데이터 품질 향상

## 연구개발 필요성

### 기술적 필요성
현재 정부 기관에서 사용하는 문서 분류 시스템의 한계...

### 경제적 필요성  
수작업 문서 분류로 인한 연간 인건비 손실 규모...

### 사회적 필요성
시민 서비스 품질 향상과 행정 효율성 증대...

# 연구개발 내용 및 방법

## 연구개발 추진전략

### 단계별 추진 계획

gantt
    title 연구개발 추진 일정
    dateFormat  YYYY-MM-DD
    section 1단계
    요구사항 분석     :done, req, 2024-03-01, 2024-04-30
    기술 검토        :done, tech, 2024-04-01, 2024-05-31
    section 2단계  
    시스템 설계      :active, design, 2024-05-01, 2024-07-31
    프로토타입 개발   :proto, after design, 60d
    section 3단계
    시스템 구현      :impl, after proto, 90d
    성능 최적화      :opt, after impl, 30d
    section 4단계
    시험 운영        :test, after opt, 60d
    최종 평가        :eval, after test, 30d

21.3.3 기술 개발 방법론

Document as Code 적용

21.4 3. 기업 기술 문서: 체계적 지식 관리

21.4.1 소프트웨어 아키텍처 문서의 진화

기업의 기술 문서는 단순한 사용 설명서를 넘어 전략적 자산이 되고 있습니다. Document as Code 접근법을 통해 지식을 체계적으로 관리하고 공유할 수 있습니다.

체계적 문서 구조

  1. 아키텍처 개요: 전체 시스템 구조와 컴포넌트 간 관계
  2. API 명세: 자동 생성되는 엔드포인트 문서
  3. 데이터 모델: 데이터베이스 스키마와 관계
  4. 배포 가이드: CI/CD 파이프라인과 인프라 설정
  5. 모니터링: 성능 지표와 경고 설정

21.4.2 다이어그램을 통한 시스템 설명

import diagrams
from diagrams import Diagram, Cluster, Edge
from diagrams.aws.compute import ECS, Lambda
from diagrams.aws.database import RDS, ElastiCache
from diagrams.aws.network import ELB, CloudFront
from diagrams.aws.storage import S3

with Diagram("텍스트 분류 시스템 아키텍처", show=False, direction="TB"):
    
    with Cluster("사용자 인터페이스"):
        web_app = CloudFront("Web Application")
        
    with Cluster("API 레이어"):
        api_gateway = ELB("API Gateway")
        api_servers = [
            ECS("API Server 1"),
            ECS("API Server 2")
        ]
    
    with Cluster("비즈니스 로직"):
        ml_service = Lambda("ML Service")
        
    with Cluster("데이터 저장소"):
        database = RDS("PostgreSQL")
        cache = ElastiCache("Redis Cache")
        storage = S3("Model Storage")
    
    # 연결 관계
    web_app >> api_gateway >> api_servers
    api_servers >> ml_service
    ml_service >> [database, cache, storage]

21.4.3 코드 문서화

class TextClassifier:
    """텍스트 분류를 위한 메인 클래스
    
    이 클래스는 Document as Code 패러다임을 적용하여
    모델 훈련부터 예측까지의 전체 파이프라인을 관리합니다.
    
    Attributes:
        model_type (str): 사용할 모델 타입
        is_trained (bool): 모델 훈련 상태
        
    Example:
        >>> classifier = TextClassifier(model_type="random_forest")
        >>> classifier.train(X_train, y_train)
        >>> predictions = classifier.predict(X_test)
    """
    
    def __init__(self, model_type: str = "random_forest"):
        """분류기 초기화
        
        Args:
            model_type: 사용할 모델 타입. 
                      'random_forest', 'logistic_regression', 
                      'transformer' 중 선택
        """
        self.model_type = model_type
        self.is_trained = False
        self._model = None
        
    def train(self, X, y, **kwargs):
        """모델 훈련 메서드
        
        Args:
            X: 훈련 특성 데이터
            y: 훈련 라벨 데이터
            **kwargs: 모델별 추가 파라미터
            
        Returns:
            self: 메서드 체이닝을 위한 self 반환
            
        Raises:
            ValueError: 지원하지 않는 모델 타입인 경우
            
        Example:
            >>> classifier.train(X_train, y_train, n_estimators=100)
        """
        
        if self.model_type == "random_forest":
            from sklearn.ensemble import RandomForestClassifier
            self._model = RandomForestClassifier(**kwargs)
        elif self.model_type == "logistic_regression":
            from sklearn.linear_model import LogisticRegression
            self._model = LogisticRegression(**kwargs)
        else:
            raise ValueError(f"지원하지 않는 모델 타입: {self.model_type}")
            
        self._model.fit(X, y)
        self.is_trained = True
        
        return self
    
    def predict(self, X):
        """텍스트 분류 예측
        
        Args:
            X: 예측할 특성 데이터
            
        Returns:
            numpy.ndarray: 예측 결과 배열
            
        Raises:
            RuntimeError: 모델이 훈련되지 않은 경우
        """
        if not self.is_trained:
            raise RuntimeError("모델이 훈련되지 않았습니다. train() 메서드를 먼저 실행하세요.")
            
        return self._model.predict(X)

21.4.4 자동 코드 문서 생성

library(reticulate)

# Python 모듈 임포트
py_run_string("
import inspect
import ast

def extract_docstrings(source_file):
    '''파이썬 소스 파일에서 독스트링 추출'''
    
    with open(source_file, 'r', encoding='utf-8') as f:
        source = f.read()
    
    tree = ast.parse(source)
    
    docstrings = {}
    
    for node in ast.walk(tree):
        if isinstance(node, (ast.FunctionDef, ast.ClassDef)):
            docstring = ast.get_docstring(node)
            if docstring:
                docstrings[node.name] = {
                    'type': 'class' if isinstance(node, ast.ClassDef) else 'function',
                    'docstring': docstring,
                    'lineno': node.lineno
                }
    
    return docstrings

# 사용 예
docs = extract_docstrings('text_classifier.py')
")

# R에서 추출된 독스트링 처리
docstrings <- py$docs

# 문서화 테이블 생성
doc_table <- map_dfr(names(docstrings), function(name) {
  info <- docstrings[[name]]
  
  tibble(
    이름 = name,
    타입 = info$type,
    설명 = str_trunc(str_split(info$docstring, "\n")[[1]][1], 100),
    라인 = info$lineno
  )
})

doc_table %>%
  gt() %>%
  tab_header(
    title = "자동 추출된 코드 문서",
    subtitle = "Python 독스트링 기반 API 문서"
  ) %>%
  cols_label(
    이름 = "함수/클래스명",
    타입 = "타입",
    설명 = "설명",
    라인 = "라인번호"
  )

21.5 4. 데이터 제품 문서: 측정과 모니터링

21.5.1 Living Dashboard: 살아있는 보고서

전통적인 성능 보고서는 정적인 스냅샷에 그쳐지만, Document as Code 접근법으로는 실시간 업데이트되는 대시보드를 만들 수 있습니다.

핵심 요소

  • 실시간 데이터 연결: API, 데이터베이스, 모니터링 도구와 직접 연결
  • 자동 경고 시스템: 임계치 초과시 자동 알림 및 보고서 생성
  • 이력 추적: 모든 데이터 변경과 의사결정 과정 기록
  • 대화형 분석: 대시보드를 통해 드릴다운 분석 가능
library(plotly)
library(DT)

# 성능 데이터 시뮬레이션
generate_performance_data <- function(days = 30) {
  
  dates <- seq.Date(Sys.Date() - days, Sys.Date(), by = "day")
  
  tibble(
    date = rep(dates, each = 24),
    hour = rep(0:23, times = length(dates)),
    requests_per_hour = rpois(length(dates) * 24, 100),
    avg_response_time = rnorm(length(dates) * 24, 200, 50),
    error_rate = pmax(0, rnorm(length(dates) * 24, 0.02, 0.01)),
    cpu_usage = pmax(0, pmin(100, rnorm(length(dates) * 24, 65, 15))),
    memory_usage = pmax(0, pmin(100, rnorm(length(dates) * 24, 70, 20)))
  ) %>%
    mutate(
      datetime = as.POSIXct(paste(date, paste0(hour, ":00:00"))),
      avg_response_time = pmax(50, avg_response_time),
      error_rate = pmax(0, pmin(0.1, error_rate))
    )
}

perf_data <- generate_performance_data()

# 요청량 트렌드
p1 <- perf_data %>%
  group_by(date) %>%
  summarise(daily_requests = sum(requests_per_hour), .groups = "drop") %>%
  plot_ly(x = ~date, y = ~daily_requests, type = 'scatter', mode = 'lines+markers',
          name = '일일 요청수', line = list(color = '#1f77b4')) %>%
  layout(
    title = "일일 API 요청량 추이",
    xaxis = list(title = "날짜"),
    yaxis = list(title = "요청수")
  )

# 응답시간 분포
p2 <- perf_data %>%
  plot_ly(y = ~avg_response_time, type = 'box', name = '응답시간') %>%
  layout(
    title = "API 응답시간 분포",
    yaxis = list(title = "응답시간 (ms)")
  )

# 에러율 추이
p3 <- perf_data %>%
  group_by(date) %>%
  summarise(daily_error_rate = mean(error_rate), .groups = "drop") %>%
  plot_ly(x = ~date, y = ~daily_error_rate, type = 'scatter', mode = 'lines+markers',
          name = '에러율', line = list(color = '#ff7f0e')) %>%
  layout(
    title = "일일 에러율 추이", 
    xaxis = list(title = "날짜"),
    yaxis = list(title = "에러율 (%)", tickformat = ".1%")
  )

# 대시보드 조합
subplot(p1, p2, p3, nrows = 3, shareX = FALSE) %>%
  layout(title = "시스템 성능 모니터링 대시보드")

21.5.2 SLA 준수 보고서

library(tibble)

# SLA 기준
sla_targets <- tibble(
  metric = c("가용성", "응답시간", "에러율", "처리량"),
  target = c("99.9%", "< 300ms", "< 1%", "> 1000 req/min"),
  unit = c("percent", "milliseconds", "percent", "requests")
)

# 실제 성능 계산
actual_performance <- perf_data %>%
  summarise(
    availability = 0.998,  # 99.8%
    avg_response = mean(avg_response_time),
    avg_error_rate = mean(error_rate),
    avg_throughput = mean(requests_per_hour) * 60
  )

# SLA 비교 테이블
sla_report <- tibble(
  지표 = c("가용성", "평균 응답시간", "평균 에러율", "평균 처리량"),
  목표 = c("99.9%", "< 300ms", "< 1%", "> 1000 req/min"),
  실제값 = c(
    paste0(round(actual_performance$availability * 100, 1), "%"),
    paste0(round(actual_performance$avg_response, 1), "ms"),
    paste0(round(actual_performance$avg_error_rate * 100, 2), "%"),
    paste0(round(actual_performance$avg_throughput, 0), " req/min")
  ),
  준수여부 = c(
    ifelse(actual_performance$availability >= 0.999, "✅", "❌"),
    ifelse(actual_performance$avg_response <= 300, "✅", "❌"),
    ifelse(actual_performance$avg_error_rate <= 0.01, "✅", "❌"),
    ifelse(actual_performance$avg_throughput >= 1000, "✅", "❌")
  )
)

sla_report %>%
  gt() %>%
  tab_header(
    title = "SLA 준수 현황 보고서",
    subtitle = paste("기준일:", Sys.Date() - 30, "~", Sys.Date())
  ) %>%
  tab_style(
    style = cell_text(weight = "bold"),
    locations = cells_column_labels()
  ) %>%
  tab_style(
    style = cell_fill(color = "lightgreen"),
    locations = cells_body(
      columns = 준수여부,
      rows = 준수여부 == "✅"
    )
  ) %>%
  tab_style(
    style = cell_fill(color = "lightcoral"),
    locations = cells_body(
      columns = 준수여부, 
      rows = 준수여부 == "❌"
    )
  )
표 21.1: SLA 준수 현황

21.6 5. DevOps 문서: 자동화를 통한 신뢰성

21.6.1 인프라 as Code와 문서 동기화

CI/CD 파이프라인과 문서가 분리되면 운영 위험이 급격히 높아집니다. 인프라 코드와 문서를 함께 관리하면 변경사항이 자동으로 동기화됩니다.

통합 대상

  • GitHub Actions/Jenkins 워크플로우: 빌드 및 배포 과정 문서화
  • Docker/Kubernetes 설정: 컨테이너와 오케스트레이션 설정 설명
  • Terraform/CloudFormation: 인프라 코드와 문서의 일반화
  • 애플리케이션 설정: 환경별 설정과 비밀 관리
# .github/workflows/docs.yml
name: Documentation Build and Deploy

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build-docs:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup Quarto
      uses: quarto-dev/quarto-actions/setup@v2
      
    - name: Setup R
      uses: r-lib/actions/setup-r@v2
      
    - name: Setup Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.11'
        
    - name: Install R dependencies
      run: |
        install.packages(c("rmarkdown", "knitr", "gt", "plotly"))
      shell: Rscript {0}
      
    - name: Install Python dependencies
      run: |
        pip install -r requirements.txt
        
    - name: Render documentation
      run: |
        quarto render
        
    - name: Deploy to GitHub Pages
      if: github.ref == 'refs/heads/main'
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: ./docs

21.6.2 배포 프로세스 추적

library(gh)
library(lubridate)

# GitHub API를 통한 배포 이력 조회
get_deployment_history <- function(repo, days = 30) {
  
  deployments <- gh(
    "GET /repos/{owner}/{repo}/deployments",
    owner = str_split(repo, "/")[[1]][1],
    repo = str_split(repo, "/")[[1]][2],
    per_page = 100
  )
  
  map_dfr(deployments, function(deploy) {
    statuses <- gh(
      "GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses",
      owner = str_split(repo, "/")[[1]][1],
      repo = str_split(repo, "/")[[1]][2], 
      deployment_id = deploy$id
    )
    
    latest_status <- statuses[[1]]
    
    tibble(
      deployment_id = deploy$id,
      environment = deploy$environment,
      created_at = ymd_hms(deploy$created_at),
      status = latest_status$state,
      description = latest_status$description %||% ""
    )
  }) %>%
    filter(created_at >= Sys.Date() - days) %>%
    arrange(desc(created_at))
}

# 배포 이력 테이블
deployment_history <- get_deployment_history("username/text-classifier-api")

deployment_history %>%
  gt() %>%
  tab_header(
    title = "배포 이력",
    subtitle = "최근 30일간 배포 현황"
  ) %>%
  fmt_datetime(
    columns = created_at,
    date_style = 6,
    time_style = 3
  )

21.7 모범 사례: 통합 기술 문서 시스템

21.7.1 사례 1: 스타트업 API 문서

# .github/workflows/docs-sync.yml
name: Documentation Sync
on:
  push:
    paths:
      - 'src/**'
      - 'api/**'
      - 'docs/**'
      
jobs:
  sync-docs:
    runs-on: ubuntu-latest
    steps:
      - name: Extract API Changes
        run: |
          # OpenAPI 명세 자동 추출
          swagger-codegen generate -i api/openapi.yaml -l html2 -o docs/api/
          
      - name: Update Architecture Diagrams  
        run: |
          # 코드에서 아키텍처 다이어그램 생성
          python scripts/generate_architecture_diagrams.py
          
      - name: Render Documentation
        run: |
          quarto render docs/ --to html
          
      - name: Deploy to GitHub Pages
        uses: peaceiris/actions-gh-pages@v3

21.7.2 사례 2: 대기업 기술 문서 체계

graph TD
    A[코드 저장소] --> B[자동 분석]
    B --> C[API 명세 추출]
    B --> D[아키텍처 매핑]
    B --> E[데이터 스키마 추출]
    
    C --> F[통합 문서 사이트]
    D --> F
    E --> F
    
    F --> G[역할별 맞춤형 뷰]
    G --> H[개발자용]
    G --> I[기획자용]
    G --> J[운영자용]

21.7.3 사례 3: 오픈소스 프로젝트

한국 R 사용자회의 프로젝트들은 Document as Code 체계를 사용합니다:

  • 자동 README 생성: pkgdown을 사용한 R 패키지 문서 생성
  • 비네트 문서: pkgdown + GitHub Actions로 코드 변경 시 자동 업데이트
  • 다국어 지원: 한글과 영어 문서 동시 유지
  • 커뮤니티 기여: 이슈와 PR을 통한 문서 개선

21.8 기술 문서에서 커뮤니케이션으로: 다음 도약

체계적으로 구축된 기술 문서를 이제 다양한 청중과 목적에 맞게 변환할 차례입니다. 다음 장에서는 One Source, Multiple Outputs 전략을 통해 효율적인 과학기술 커뮤니케이션을 실현하는 방법을 배웁니다.

21.8.1 문서에서 커뮤니케이션으로의 진화

기술 문서의 한계 극복 - 정적인 문서 → 인터랙티브한 경험 - 단일 포맷 → 다중 포맷 동시 지원
- 내부용 → 외부 커뮤니케이션까지

새로운 가능성들 - 학술 발표: 컨퍼런스와 세미나용 프레젠테이션 - 교육 자료: 단계별 학습 모듈과 워크숍 자료 - 대중 소통: 일반인을 위한 블로그와 인포그래픽 - 정책 지원: 의사결정자를 위한 요약과 권고안 - 실시간 대시보드: 살아있는 데이터와 모니터링

Document as Code의 진정한 힘은 한 번의 작성으로 모든 커뮤니케이션 채널을 지원한다는 점입니다.


힌트실습 과제

현재 담당하고 있는 프로젝트나 시스템의 기술 문서를 Document as Code 방식으로 작성해보세요. 코드에서 자동으로 추출되는 정보와 수동으로 작성해야 하는 내용을 구분하여 관리하는 것이 핵심입니다.

경고보안 주의사항

자동 문서 생성 시 코드에서 API 키나 비밀번호 등의 민감한 정보가 노출되지 않도록 주의하세요. 환경변수나 설정 파일을 통해 민감한 정보를 분리하는 것이 중요합니다.