← Назад к вопросам

Как документируешь свои доработки или разработки?

1.0 Junior🔥 131 комментариев
#Soft Skills

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Подход к документированию кода и разработок

Документация — это критический элемент качественной разработки. Я применяю многоуровневый подход документирования, в зависимости от контекста и аудитории.

1. Docstrings для функций и классов

Использую Google-style docstrings с указанием типов, параметров, возвращаемого значения и примеров:

def calculate_discount(price: float, discount_percent: float) -> float:
    """Рассчитать цену с учётом скидки.
    
    Args:
        price: Исходная цена товара в рублях.
        discount_percent: Процент скидки (0-100).
    
    Returns:
        Финальная цена с учётом скидки.
    
    Raises:
        ValueError: Если цена отрицательная или скидка вне диапазона.
    
    Example:
        >>> calculate_discount(1000, 10)
        900.0
        >>> calculate_discount(500, 50)
        250.0
    """
    if price < 0:
        raise ValueError("Цена не может быть отрицательной")
    if not 0 <= discount_percent <= 100:
        raise ValueError("Скидка должна быть от 0 до 100%")
    
    return price * (1 - discount_percent / 100)

2. Type hints для самодокументирования

Полная типизация — это уже часть документации:

from typing import Protocol, Iterator, Optional
from dataclasses import dataclass
from datetime import datetime

@dataclass
class User:
    """Пользователь системы."""
    id: int
    name: str
    email: str
    created_at: datetime
    is_active: bool = True

class UserRepository(Protocol):
    """Интерфейс репозитория пользователей."""
    
    def find_by_id(self, user_id: int) -> Optional[User]:
        """Найти пользователя по ID."""
        ...
    
    def find_all_active(self) -> Iterator[User]:
        """Получить всех активных пользователей."""
        ...
    
    def save(self, user: User) -> None:
        """Сохранить пользователя в БД."""
        ...

3. Комментарии для сложной логики

Комментарии описывают ПОЧЕМУ, а не ЧТО:

def find_optimal_partition(items: list[int], target_sum: int) -> Optional[list[int]]:
    """
    Найти подмножество элементов с суммой, максимально близкой к целевой.
    
    Используется dynamic programming вместо brute force (O(2^n)) 
    для производительности O(n*sum).
    """
    n = len(items)
    # dp[i][j] = True если можно достичь суммы j используя первые i элементов
    dp = [[False] * (target_sum + 1) for _ in range(n + 1)]
    
    # Base case: сумма 0 всегда достижима (пустое подмножество)
    for i in range(n + 1):
        dp[i][0] = True
    
    # Fill DP table
    for i in range(1, n + 1):
        for j in range(target_sum + 1):
            # Либо не берём текущий элемент
            dp[i][j] = dp[i-1][j]
            # Либо берём (если возможно)
            if j >= items[i-1]:
                dp[i][j] = dp[i][j] or dp[i-1][j - items[i-1]]
    
    # Backtrack чтобы найти само подмножество
    if not dp[n][target_sum]:
        return None
    
    result = []
    i, j = n, target_sum
    while i > 0 and j > 0:
        # Если элемент был использован
        if not dp[i-1][j]:
            result.append(items[i-1])
            j -= items[i-1]
        i -= 1
    
    return result

4. Архитектурные диаграммы и README

Для крупных проектов создаю документацию с диаграммами:

# Project Architecture

## Layered Architecture

┌─────────────────────────────────┐ │ Presentation (API) │ │ FastAPI routes, responses │ └──────────────┬──────────────────┘

┌──────────────▼──────────────────┐ │ Application (Use Cases) │ │ Business logic, orchestration │ └──────────────┬──────────────────┘

┌──────────────▼──────────────────┐ │ Domain (Models) │ │ Entities, value objects │ └──────────────┬──────────────────┘

┌──────────────▼──────────────────┐ │ Infrastructure (Database) │ │ Repositories, migrations │ └─────────────────────────────────┘


## Class Diagram

Repository <|-- UserRepository Repository <|-- ProductRepository

UseCase <|-- CreateUserUseCase UseCase <|-- GetUserUseCase

5. Inline примеры использования

class EmailService:
    """Сервис отправки email.
    
    Example:
        service = EmailService(smtp_host="smtp.gmail.com")
        
        # Простое письмо
        service.send(
            to="user@example.com",
            subject="Добро пожаловать",
            body="Спасибо за регистрацию"
        )
        
        # С HTML и вложениями
        service.send_html(
            to="user@example.com",
            subject="Счёт",
            html="<h1>Счёт</h1>",
            attachments=["invoice.pdf"]
        )
    """
    
    def send(self, to: str, subject: str, body: str) -> None:
        """Отправить простое текстовое письмо."""
        pass
    
    def send_html(self, to: str, subject: str, html: str, 
                  attachments: list[str] | None = None) -> None:
        """Отправить HTML письмо с вложениями."""
        pass

6. Тесты как документация

Хорошие тесты показывают, как использовать код:

import pytest
from app.services import PaymentService, PaymentError

class TestPaymentService:
    """Тесты для сервиса платежей."""
    
    def test_successful_payment(self, payment_service):
        """Успешный платёж уменьшает баланс пользователя."""
        result = payment_service.charge(
            user_id=1,
            amount=1000.0,
            currency="RUB"
        )
        
        assert result.status == "success"
        assert result.transaction_id is not None
    
    def test_insufficient_funds(self, payment_service):
        """Платёж отклоняется если недостаточно средств."""
        with pytest.raises(PaymentError) as exc_info:
            payment_service.charge(
                user_id=1,
                amount=999999.0,
                currency="RUB"
            )
        
        assert "insufficient_funds" in str(exc_info.value)
    
    def test_concurrent_payments(self, payment_service):
        """Система обрабатывает конкурентные платежи корректно."""
        # Это тест как документация параллельного поведения
        pass

7. API документация (OpenAPI/Swagger)

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI(
    title="User API",
    description="API для управления пользователями",
    version="1.0.0"
)

class User(BaseModel):
    """Модель пользователя."""
    id: int
    name: str
    email: str

@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
    """
    Получить пользователя по ID.
    
    - **user_id**: ID пользователя в системе
    
    Returns:
        User объект с информацией о пользователе
    
    Raises:
        404: Пользователь не найден
    """
    pass

8. Commit messages как документация

fix: исправить race condition в find_opponent

Проблема: при одновременном запросе от двух пользователей
они могут быть сопоставлены друг с другом несколько раз.

Решение: использовать SELECT FOR UPDATE SKIP LOCKED
для атомарного выбора и блокировки соперника.

Тест: test_concurrent_find_opponent проверяет это

9. Change logs и migration guides

# CHANGELOG.md

## v2.0.0 (Breaking Changes)

### Removed
- `UserService.get_user_by_email()` → используй `UserRepository.find_by_email()`

### Changed
- `User.created_at` теперь DateTime вместо Unix timestamp

### Migration
```sql
ALTER TABLE users 
ALTER COLUMN created_at TYPE TIMESTAMPTZ USING 
  to_timestamp(created_at);

## Инструменты документации

- **Pydantic** — автоматическая валидация и документация
- **Sphinx** — для больших проектов
- **MkDocs** — для вики-стиля документации
- **Swagger/OpenAPI** — для API
- **Type hints + mypy** — для типизации

## Best Practices

- ✅ Docstrings для ВСЕХ public функций
- ✅ Type hints везде
- ✅ Примеры в docstrings
- ✅ Тесты как живая документация
- ✅ Комментарии для ПОЧЕМУ, не ЧТО
- ❌ Устаревшие комментарии (синхронизируйте с кодом)
- ❌ Очевидные комментарии
- ❌ Излишняя документация для простого кода