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

Что важно в подходах разработки?

2.0 Middle🔥 241 комментариев
#DevOps и инфраструктура#Django

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

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

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

Что важно в подходах разработки

Главное: процесс важнее инструментов

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

1. Test-Driven Development (TDD)

Это не просто писать тесты. Это философия:

RED → GREEN → REFACTOR

Что это значит:

# ШАГ 1: RED — Написать ПАДАЮЩИЙ тест
def test_user_creation():
    user = User(name="Alice", email="alice@example.com")
    assert user.is_valid()  # Тест падает — User не существует

# ШАГ 2: GREEN — Написать минимальный код
class User:
    def __init__(self, name: str, email: str):
        self.name = name
        self.email = email
    
    def is_valid(self) -> bool:
        return bool(self.name and self.email)  # Тест проходит

# ШАГ 3: REFACTOR — Улучшить без изменения логики
class User:
    def __init__(self, name: str, email: str):
        if not name or not email:
            raise ValueError("Name and email are required")
        self.name = name
        self.email = email
    
    def is_valid(self) -> bool:
        return True  # Уже гарантировано в __init__

Почему это важно:

  • Заставляет думать о требованиях ДО кода
  • Код автоматически тестируемый (слабо связанный)
  • Невозможно написать untestable код
  • 100% coverage естественно

2. Clean Architecture / Layered Architecture

Источник: Robert C. Martin (Uncle Bob)

Суть: зависимости только в одну сторону

Presentation → Application → Domain → Infrastructure
       ↑             ↑          ↑           ↑
    (HTTP)      (UseCase)    (Entity)   (Database)

Правило: внешние слои зависят от внутренних, но не наоборот

# ❌ НЕПРАВИЛЬНО — нарушение слоёв
from presentation.http import request  # Представление
from infrastructure.database import db  # Инфраструктура

class UserService:  # Application слой
    def create_user(self):
        user_data = request.json()  # Presentation зависит от HTTP!
        db.save(user_data)          # Application зависит от БД!

# ✅ ПРАВИЛЬНО — чистая архитектура
class CreateUserUseCase:
    """Application слой — бизнес-логика"""
    def __init__(self, repository: UserRepository):
        self.repository = repository
    
    def execute(self, name: str, email: str) -> User:
        """Не знает про HTTP, не знает про БД"""
        user = User(name=name, email=email)
        self.repository.save(user)
        return user

class UserRepository:  # Domain слой — интерфейс
    def save(self, user: User) -> None:
        raise NotImplementedError

class PostgresUserRepository(UserRepository):  # Infrastructure
    def __init__(self, db_connection):
        self.db = db_connection
    
    def save(self, user: User) -> None:
        self.db.execute("INSERT INTO users ...")

# Presentation слой
from fastapi import FastAPI

app = FastAPI()
use_case = CreateUserUseCase(PostgresUserRepository(db_conn))

@app.post("/users")
async def create_user(name: str, email: str):
    user = use_case.execute(name, email)
    return {"id": user.id, "name": user.name}

Преимущества:

  • Легко менять инструменты (PostgreSQL → MongoDB)
  • Легко тестировать (mock repository)
  • Бизнес-логика независима от фреймворков

3. SOLID принципы

Это не отдельный подход, а правила хорошего дизайна:

S — Single Responsibility Principle

# ❌ ПЛОХО — слишком много ответственности
class UserService:
    def create_user(self, data):
        # Валидация
        if not data.email:
            raise ValueError("Email required")
        
        # Преобразование
        user = User(**data)
        
        # Сохранение
        db.save(user)
        
        # Отправка письма
        send_email(user.email, "Welcome!")
        
        # Логирование
        logger.info(f"User {user.id} created")
        
        return user

# ✅ ХОРОШО — каждый класс — одна ответственность
class CreateUserValidator:
    def validate(self, data: dict) -> None:
        if not data.get("email"):
            raise ValueError("Email required")

class CreateUserUseCase:
    def __init__(self, validator, repository, event_bus):
        self.validator = validator
        self.repository = repository
        self.event_bus = event_bus
    
    def execute(self, data: dict) -> User:
        self.validator.validate(data)
        user = User(**data)
        self.repository.save(user)
        self.event_bus.publish("user.created", user)
        return user

class UserCreatedEventHandler:
    def handle(self, user: User):
        send_email(user.email, "Welcome!")
        logger.info(f"User {user.id} created")

O — Open/Closed Principle

# ❌ ПЛОХО — нужно менять класс при добавлении нового типа
class NotificationService:
    def send(self, user: User, method: str):
        if method == "email":
            self.send_email(user)
        elif method == "sms":
            self.send_sms(user)
        elif method == "telegram":
            self.send_telegram(user)
        # Каждый новый способ требует изменения класса!

# ✅ ХОРОШО — открыт для расширения, закрыт для модификации
class Notification:
    def send(self, user: User) -> None:
        raise NotImplementedError

class EmailNotification(Notification):
    def send(self, user: User) -> None:
        send_email(user.email)

class SMSNotification(Notification):
    def send(self, user: User) -> None:
        send_sms(user.phone)

class NotificationService:
    def __init__(self, notifications: List[Notification]):
        self.notifications = notifications
    
    def send_all(self, user: User):
        for notification in self.notifications:
            notification.send(user)
        # Новый способ? Просто добавляем класс, не меняем сервис

4. DRY (Don't Repeat Yourself)

# ❌ ПЛОХО — дублирование кода
def get_user_by_id(user_id: int):
    try:
        user = db.query("SELECT * FROM users WHERE id = ?", user_id)
        if not user:
            logger.error(f"User {user_id} not found")
            return None
        return user
    except Exception as e:
        logger.error(f"Database error: {e}")
        return None

def get_post_by_id(post_id: int):
    try:
        post = db.query("SELECT * FROM posts WHERE id = ?", post_id)
        if not post:
            logger.error(f"Post {post_id} not found")
            return None
        return post
    except Exception as e:
        logger.error(f"Database error: {e}")
        return None

# ✅ ХОРОШО — абстрагируем паттерн
class Repository:
    def __init__(self, table: str, db):
        self.table = table
        self.db = db
    
    def get_by_id(self, item_id: int):
        try:
            item = self.db.query(f"SELECT * FROM {self.table} WHERE id = ?", item_id)
            if not item:
                logger.error(f"{self.table} {item_id} not found")
                return None
            return item
        except Exception as e:
            logger.error(f"Database error: {e}")
            return None

user_repo = Repository("users", db)
post_repo = Repository("posts", db)

5. Continuous Integration / Continuous Deployment (CI/CD)

Суть: автоматизировать всё

# .github/workflows/test.yml
name: Tests
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Run tests
        run: pytest --cov=src tests/
      - name: Run linter
        run: ruff check src/
      - name: Type checking
        run: mypy src/
      - name: Build
        run: docker build -t myapp:latest .
      - name: Deploy
        if: github.ref == 'refs/heads/main'
        run: docker push myapp:latest

Без CI/CD:

  • Баги проходят в production
  • Нет гарантии что код работает
  • Сложные процессы develop/deploy

6. Code Review

Не менее важное чем писание кода

Код писал один разработчик → его слепые пятна
Код смотрит другой → видит проблемы

Хороший code review:

  • Проверяет логику, не стиль (для стиля — linter)
  • Задаёт вопросы ("Почему так?")
  • Предлагает улучшения
  • Делится знаниями

7. Документирование

# ❌ ПЛОХО — без документации
def calc(x, y, z):
    return (x * y) / z if z != 0 else None

# ✅ ХОРОШО — ясная документация
def calculate_discount_price(
    base_price: Decimal,
    discount_percent: Decimal,
    tax_percent: Decimal
) -> Optional[Decimal]:
    """
    Вычисляет цену с учётом скидки и налога.
    
    Args:
        base_price: Базовая цена в USD
        discount_percent: Скидка в процентах (0-100)
        tax_percent: Налог в процентах (0-100)
    
    Returns:
        Финальная цена с учётом скидки и налога,
        или None если tax_percent == 0 (невозможно)
    """
    if tax_percent == 0:
        return None
    
    discounted = base_price * (1 - discount_percent / 100)
    return discounted * (1 + tax_percent / 100)

8. Мониторинг и логирование

import logging
from structlog import get_logger

logger = get_logger()

class UserService:
    def create_user(self, name: str, email: str):
        logger.info(
            "user_creation_started",
            name=name,
            email=email,
        )
        
        try:
            user = User(name=name, email=email)
            self.repository.save(user)
            
            logger.info(
                "user_creation_succeeded",
                user_id=user.id,
                duration_ms=10  # из timeit
            )
            return user
        
        except Exception as e:
            logger.exception(
                "user_creation_failed",
                email=email,
                error=str(e),
            )
            raise

Иерархия важности

1. Тестируемость (TDD)
2. Читаемость кода (SOLID, Clean Code)
3. Архитектура (Clean Architecture)
4. Производительность (профилирование, а не гадание)
5. Оптимизация (только если измерено)

Практический совет

НЕ ДЕЛАЙ:
- Микрооптимизацию без тестов
- Архитектуру без нужны
- Рефакторинг без тестов
- Code review без уважения

ДЕЛАЙ:
- Сначала тесты, потом код
- Простое решение для текущей задачи
- Refactor когда есть тесты
- Делись знаниями в code review

Итог

Важнейшие подходы в разработке:

  1. TDD — гарантия качества
  2. Clean Architecture — долгоживающие системы
  3. SOLID — гибкие системы
  4. Code Review — распределённое знание
  5. CI/CD — надёжность
  6. Мониторинг — понимание production

Всё остальное — инструменты для достижения этих целей.

Что важно в подходах разработки? | PrepBro