← Назад к вопросам
Что важно в подходах разработки?
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
Итог
Важнейшие подходы в разработке:
- TDD — гарантия качества
- Clean Architecture — долгоживающие системы
- SOLID — гибкие системы
- Code Review — распределённое знание
- CI/CD — надёжность
- Мониторинг — понимание production
Всё остальное — инструменты для достижения этих целей.