← Назад к вопросам
Расшифруй аббревиатуру YAGNI
1.2 Junior🔥 151 комментариев
#Python Core#Soft Skills#Архитектура и паттерны
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
YAGNI: You Aren't Gonna Need It
YAGNI (Вам это не понадобится) — это принцип разработки, который говорит: **не добавляй функционал, пока он реально не нужен**. Это одна из самых важных идей чистого кода.
Суть принципа
YAGNI = не предугадывай — решай текущие проблемы
# Вопрос для себя:
# "Нужна ли мне эта функция СЕЙЧАС?"
# - Если ДА → добавляй
# - Если НЕТ (может быть нужна в будущем) → не добавляй!
Пример YAGNI нарушения
# ❌ ПЛОХО: Переинженерство
# Пишешь общий фреймворк "на будущее"
class BaseDataProcessor:
"""Универсальный процессор данных"""
def __init__(self):
self.filters = []
self.transformers = []
self.validators = []
self.handlers = []
self.cache = {}
self.metrics = {}
self.logger = None
self.config = {}
def add_filter(self, filter_func):
self.filters.append(filter_func)
def add_transformer(self, transformer_func):
self.transformers.append(transformer_func)
def process(self, data):
# Очень сложная логика с поддержкой всего на свете
pass
# Но на самом деле нужно было только:
class SimpleDataProcessor:
def process(self, data):
return [item * 2 for item in data]
# ❌ 500 строк кода
# ✅ 1 строка кода
Правильное применение YAGNI
# ✅ ХОРОШО: Решаешь текущую задачу
# Требование: "Обработать CSV файл с продуктами"
class ProductLoader:
"""Загружает продукты из CSV"""
def load(self, filename):
import csv
products = []
with open(filename) as f:
reader = csv.DictReader(f)
for row in reader:
products.append({
'id': row['id'],
'name': row['name'],
'price': float(row['price'])
})
return products
# Простая функция, которая решает проблему
# Если потом понадобится JSON, Excel, БД → добавишь
Сценарий: Расширение функционала
# Этап 1: CSV работает
class ProductLoader:
def load(self, filename):
import csv
# CSV логика
# Месяц спустя...
# Требование: "Нужна загрузка из JSON тоже"
# ✅ Правильный путь: рефакторим, добавляем
from abc import ABC, abstractmethod
class DataLoader(ABC):
@abstractmethod
def load(self, filename):
pass
class CSVProductLoader(DataLoader):
def load(self, filename):
import csv
# CSV логика
class JSONProductLoader(DataLoader):
def load(self, filename):
import json
# JSON логика
class ExcelProductLoader(DataLoader):
def load(self, filename):
import openpyxl
# Excel логика
class ProductService:
def __init__(self, loader: DataLoader):
self.loader = loader
def load_products(self, filename):
return self.loader.load(filename)
# Использование
csv_service = ProductService(CSVProductLoader())
json_service = ProductService(JSONProductLoader())
excel_service = ProductService(ExcelProductLoader())
# ❌ НЕ ДОБАВЛЯЙ СРАЗУ. Только когда нужно!
Типичные нарушения YAGNI
1. Универсальные параметры
# ❌ YAGNI нарушение
def send_notification(message, medium=None, retry_count=None,
retry_delay=None, priority=None,
timeout=None, callback=None, metadata=None):
"""Отправить уведомление (со всеми возможными опциями)"""
# 100 строк кода для обработки всех параметров
# ✅ YAGNI: делай просто
def send_notification(message):
# Отправить по Email (текущее требование)
send_email(message)
# Если потом нужно будет SMS, retry и т.д. → тогда добавишь
2. Предусмотрительные абстракции
# ❌ YAGNI нарушение
class Logger:
def __init__(self):
self.handlers = []
self.filters = []
self.formatters = {}
def add_handler(self, handler):
self.handlers.append(handler)
def add_filter(self, filter_fn):
self.filters.append(filter_fn)
def set_formatter(self, name, formatter):
self.formatters[name] = formatter
# ... ещё 50 методов ...
# ✅ YAGNI: используй встроенное
import logging
logger = logging.getLogger(__name__)
logger.info("Something happened")
3. Готовизация к масштабированию
# ❌ YAGNI нарушение
class UserRepository:
def __init__(self):
self.cache = {}
self.read_replicas = []
self.write_replicas = []
self.circuit_breaker = CircuitBreaker()
self.metrics = MetricsCollector()
def get_user(self, user_id):
# Проверяет кеш
# Проверяет circuit breaker
# Логирует метрики
# Балансирует нагрузку
# Кеширует результат
# Отправляет события
# ... и ещё 20 операций ...
# ❌ ОДИН пользователь на API → ВСЁ ЭТО ЗАЧЕМ?
# ✅ YAGNI: начни с простого
def get_user(user_id):
user = User.objects.get(id=user_id)
return user
# Когда 10000 пользователей → ТОГДА добавляй кеш, реплики и т.д.
YAGNI vs. Подготовка
Когда МОЖНО "подготовиться":
# ✅ Если это стандарт или best practice
from typing import Optional, List
def process_users(users: List[dict]) -> List[dict]:
"""Типизация — стандарт, используй всегда"""
return users
# ✅ Если это требует минимальных усилий
class User:
def __init__(self, name, email):
self.name = name
self.email = email
def __repr__(self):
return f"User(name={self.name})"
# __repr__ — это правило, не переинженерство
# ✅ Если это требование безопасности
def get_user(user_id):
if not isinstance(user_id, int):
raise ValueError("user_id must be int")
# Валидация — всегда нужна
Когда НЕЛЬЗЯ "подготавливаться":
# ❌ Целые новые модули на будущее
# ❌ Конфигурационные системы, которые может никто не использовать
# ❌ Абстрактные интерфейсы без реальной необходимости
# ❌ Многоуровневый кеширование на ранних стадиях
Цикл разработки с YAGNI
# Этап 1: Делай минимум
def calculate_total(items):
return sum(item['price'] * item['quantity'] for item in items)
# Месяц спустя...
# Требование: "Нужны скидки на основе суммы"
# Этап 2: Расширяй ПОТОМ
def calculate_total(items, discount_percent=0):
total = sum(item['price'] * item['quantity'] for item in items)
return total * (1 - discount_percent / 100)
# Ещё месяц...
# Требование: "Нужны разные скидки для разных категорий"
# Этап 3: Рефакторишь
class PricingEngine:
def __init__(self, discount_rules):
self.discount_rules = discount_rules
def calculate_total(self, items):
# Логика с разными скидками
pass
# Путь развития:
# Простая функция → параметры → объект → паттерны
# НЕ наоборот!
Как распознать YAGNI нарушение
Красные флаги:
# 🚩 "Нам потом это точно понадобится"
class SomeClass:
# Куча методов для гипотетических сценариев
def future_feature_1(self): pass
def future_feature_2(self): pass
def future_feature_3(self): pass
# 🚩 "На всякий случай добавлю параметр"
def process(data, optional_param_1=None, optional_param_2=None):
# Но никто это не использует
pass
# 🚩 "Сделаю это максимально гибким"
class ConfigurationEngine:
# 300 строк кода конфигурации для одного простого случая
# 🚩 "Добавлю слой абстракции"
# Но он нужен только для одной конкретной реализации
class DataHandler(ABC): # ❌ не нужна
@abstractmethod
def handle(self, data): pass
class CSVDataHandler(DataHandler): # ❌ только один класс
def handle(self, data):
# CSV логика
YAGNI в контексте SOLID
YAGNI — это упрощение без нарушения SOLID:
# ✅ Простой класс (YAGNI) + SOLID
class EmailService:
def send(self, to: str, subject: str, body: str):
# Одна ответственность (S)
# Легко раскрыть для расширения (O)
# Может быть переопределён (L)
pass
# ❌ Сложный класс (нарушение YAGNI) + SOLID
class NotificationService:
def send_email(self, to, subject, body): pass
def send_sms(self, phone, text): pass
def send_push(self, device_id, message): pass
def send_webhook(self, url, payload): pass
def send_telegram(self, chat_id, message): pass
def send_slack(self, channel, message): pass
def send_discord(self, webhook_url, content): pass
def send_whatsapp(self, phone, message): pass
# Слишком много ответственности (S нарушена)
Баланс: YAGNI vs. SOLID vs. DRY
# ✅ ХОРОШО: Баланс
class UserRepository:
def get(self, user_id):
return User.objects.get(id=user_id)
def filter_by_email(self, email):
return User.objects.filter(email=email)
def save(self, user):
user.save()
return user
# Простой, не переинженерный, но полезный
# YAGNI: нет лишних фич
# SOLID: одна ответственность
# DRY: не дублируем запросы
# ❌ ПЛОХО: Нарушение YAGNI + SOLID
class BaseRepository(ABC):
@abstractmethod
def get(self, id): pass
@abstractmethod
def filter(self, **kwargs): pass
@abstractmethod
def save(self, obj): pass
# ... 20 других методов ...
class UserRepository(BaseRepository):
# Реализует методы, большинство из которых не используются
Вывод
YAGNI заповеди:
- Пиши код для текущих требований, не для будущих
- Начинай просто, рефакторишь потом
- Если сомневаешься — не добавляй
- Каждая строка кода — это долг (её нужно поддерживать)
- Гибкость имеет цену (сложность кода)
Золотое правило: Лучше иметь 100 строк кода, который решает проблему, чем 1000 строк универсального фреймворка, который может что-то делать когда-нибудь в будущем.