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

Какие знаешь антипаттерны?

1.7 Middle🔥 131 комментариев
#Архитектура и паттерны

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

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

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

Антипаттерны в программировании

Антипаттерны — это повторяющиеся ошибки архитектуры, дизайна и кода. Их нужно избегать.

1. God Object (Божественный объект)

Один класс делает слишком много:

# ❌ Плохо: классический God Object
class User:
    def authenticate(self): pass           # Аутентификация
    def send_email(self): pass             # Отправка email
    def process_payment(self): pass        # Платежи
    def generate_report(self): pass        # Отчёты
    def backup_database(self): pass        # Резервное копирование
    # 500+ методов!

# ✅ Хорошо: разделение ответственности
class User:
    def __init__(self, id, name, email):
        self.id = id
        self.name = name
        self.email = email

class UserAuthenticator:
    def authenticate(user, password): pass

class EmailService:
    def send(email, subject, body): pass

class PaymentProcessor:
    def process(user, amount): pass

2. Primitive Obsession (Примитивная одержимость)

Использование примитивов вместо объектов:

# ❌ Плохо: строки везде
def process_user(name, email, phone, age, role):
    if role == "admin":
        # Какая роль? "admin", "Admin", "ADMIN"?
        pass

# ✅ Хорошо: объект для представления сущности
from enum import Enum
from dataclasses import dataclass

class UserRole(Enum):
    ADMIN = "admin"
    USER = "user"
    GUEST = "guest"

@dataclass
class PhoneNumber:
    number: str
    
    def __post_init__(self):
        if not self.is_valid():
            raise ValueError("Invalid phone")

@dataclass
class User:
    name: str
    email: str
    phone: PhoneNumber
    age: int
    role: UserRole

3. Long Method (Длинный метод)

Метод делает слишком много:

# ❌ Плохо: монолитный метод (200 строк)
def create_order(user_id, items):
    # Валидация
    if not user_id:
        raise ValueError("...")
    for item in items:
        if not item.get('quantity'):
            raise ValueError("...")
    
    # Проверка запасов
    for item in items:
        stock = get_stock(item['product_id'])
        if stock < item['quantity']:
            raise Exception("...")
    
    # Расчёт цены
    total = 0
    for item in items:
        price = get_price(item['product_id'])
        total += price * item['quantity']
    
    # Применение скидок
    user = get_user(user_id)
    if user.loyalty_level > 5:
        total *= 0.9
    
    # Создание заказа
    order = Order(...)
    # ... и т.д.

# ✅ Хорошо: разделение на методы
def create_order(user_id, items):
    validate_order(user_id, items)
    check_inventory(items)
    total_price = calculate_price(user_id, items)
    apply_discounts(user_id, total_price)
    return Order.create(user_id, items, total_price)

4. Duplicate Code (Дублирование кода)

Повторение одного и того же кода в разных местах:

# ❌ Плохо: дублирование
class UserRepository:
    def get_active_users(self):
        users = []
        for user in all_users:
            if user.is_active and user.verified:
                users.append(user)
        return users

class OrderRepository:
    def get_active_orders(self):
        orders = []
        for order in all_orders:
            if order.is_active and order.verified:
                orders.append(order)
        return orders

# ✅ Хорошо: используй функции высокого порядка
def filter_active_and_verified(items):
    return [item for item in items if item.is_active and item.verified]

class UserRepository:
    def get_active_users(self):
        return filter_active_and_verified(all_users)

class OrderRepository:
    def get_active_orders(self):
        return filter_active_and_verified(all_orders)

5. Shotgun Surgery (Дробовик-хирургия)

Одно изменение требует множества изменений в разных местах:

# ❌ Плохо: расположение сущностей рассеяно
# models.py
class Order:
    status: str

# views.py
if order.status == "pending":
    send_email()

# utils.py
if order.status == "processing":
    update_inventory()

# tasks.py
if order.status == "completed":
    send_notification()

# Изменить статусы → нужно трогать везде!

# ✅ Хорошо: централизованное управление состояниями
from enum import Enum

class OrderStatus(Enum):
    PENDING = "pending"
    PROCESSING = "processing"
    COMPLETED = "completed"

# Все статусы в одном месте!

class Order:
    def __init__(self):
        self.status = OrderStatus.PENDING
    
    def mark_processing(self):
        self.status = OrderStatus.PROCESSING
        self._on_status_changed()
    
    def _on_status_changed(self):
        # Все побочные эффекты в одном месте
        if self.status == OrderStatus.PROCESSING:
            update_inventory(self)
        elif self.status == OrderStatus.COMPLETED:
            send_notification(self)

6. Large Class (Большой класс)

Класс с сотнями строк:

# ❌ Плохо: 1000+ строк в одном файле
class Product:  # Огромный класс
    # Характеристики
    # Валидация
    # Сохранение в БД
    # Расчёты цены
    # Управление инвентарём
    # Генерация отчётов
    # ...

# ✅ Хорошо: разделение ответственности
class Product:
    # Только данные товара
    id: int
    name: str
    price: float

class ProductValidator:
    @staticmethod
    def validate(product): pass

class ProductRepository:
    @staticmethod
    def save(product): pass

class PricingEngine:
    @staticmethod
    def calculate(product): pass

7. Feature Envy (Зависть к функциям)

Метод больше интересуется другим классом:

# ❌ Плохо: интерес к чужим данным
class OrderService:
    def calculate_total(order):
        total = 0
        for item in order.items:
            price = item.product.price
            quantity = item.quantity
            tax = item.product.category.tax_rate
            total += price * quantity * (1 + tax)
        return total

# ✅ Хорошо: каждый класс обрабатывает свои данные
class OrderItem:
    def calculate_total(self):
        return self.product.price * self.quantity * (1 + self.product.category.tax_rate)

class Order:
    def calculate_total(self):
        return sum(item.calculate_total() for item in self.items)

# Теперь просто:
total = order.calculate_total()

8. Data Clumps (Клочки данных)

Повторяющиеся группы переменных:

# ❌ Плохо: повторяющиеся параметры везде
def create_order(user_name, user_email, user_phone, ...):
    pass

def update_user(user_name, user_email, user_phone):
    pass

def send_notification(user_name, user_email, user_phone):
    pass

# ✅ Хорошо: группировка в объект
@dataclass
class UserInfo:
    name: str
    email: str
    phone: str

def create_order(user_info: UserInfo):
    pass

def update_user(user_info: UserInfo):
    pass

def send_notification(user_info: UserInfo):
    pass

9. Switch Statements (Длинные switch'и)

Условная логика вместо полиморфизма:

# ❌ Плохо: большой if-else
def calculate_salary(employee_type, base_salary):
    if employee_type == "manager":
        return base_salary * 1.5 + bonus
    elif employee_type == "developer":
        return base_salary * 1.2 + bonus
    elif employee_type == "intern":
        return base_salary
    elif employee_type == "contractor":
        return base_salary * 0.8

# ✅ Хорошо: полиморфизм
class Employee:
    def calculate_salary(self): pass

class Manager(Employee):
    def calculate_salary(self):
        return self.base_salary * 1.5 + self.bonus

class Developer(Employee):
    def calculate_salary(self):
        return self.base_salary * 1.2 + self.bonus

class Intern(Employee):
    def calculate_salary(self):
        return self.base_salary

# Использование:
salary = employee.calculate_salary()  # Работает для любого типа!

10. Speculative Generality (Спекулятивная обобщённость)

Код для функциональности, которая может понадобиться:

# ❌ Плохо: оверинжиниринг "на будущее"
class ConfigManager:
    def __init__(self):
        self.configs = {}
    
    def get_config(self, key, parser=None, validator=None, 
                   cache=True, encrypt=False, ttl=None):
        # 10 параметров для функциональности, которая не нужна
        pass

# ✅ Хорошо: простое решение для текущей задачи
class ConfigManager:
    def __init__(self):
        self.configs = {}
    
    def get_config(self, key):
        return self.configs.get(key)
    
    def set_config(self, key, value):
        self.configs[key] = value
    
    # Добавь функции, когда они понадобятся!

11. Temporary Field (Временные поля)

Поля, которые используются только иногда:

# ❌ Плохо: поле используется редко
class Order:
    def __init__(self):
        self.items = []
        self.temp_calculation = None  # Используется только в одном методе!
    
    def apply_discount(self):
        self.temp_calculation = self.calculate_base_total()
        discount = self.temp_calculation * 0.1
        self.temp_calculation = None
        return discount

# ✅ Хорошо: используй локальные переменные
class Order:
    def apply_discount(self):
        base_total = self.calculate_base_total()  # Локальная переменная
        return base_total * 0.1

12. Message Chains (Цепочки вызовов)

Долгая цепь делегирования:

# ❌ Плохо: долгая цепь вызовов
company.department.manager.user.permissions.can_edit

# Если структура изменится, всё сломается!

# ✅ Хорошо: предоставь метод на более высоком уровне
class Company:
    def can_user_edit(self, user_id):
        return self.department.manager.can_user_edit(user_id)

# Теперь клиент вызывает просто:
company.can_user_edit(user_id)

13. Middle Man (Посредник)

Класс, который только делегирует другим:

# ❌ Плохо: класс только перенаправляет
class OrderManager:
    def __init__(self, repository):
        self.repository = repository
    
    def get_order(self, id):
        return self.repository.get_order(id)
    
    def save_order(self, order):
        return self.repository.save_order(order)
    
    # Просто перенаправление, никакой логики!

# ✅ Хорошо: убери посредника
repository.get_order(id)  # Используй напрямую

14. Lazy Class (Ленивый класс)

Класс, который не делает ничего полезного:

# ❌ Плохо: пустой класс
class UserValidator:
    @staticmethod
    def validate(user):
        return True

# ✅ Хорошо: объедини с другим классом или удали
# Если это просто валидация, используй Pydantic:
from pydantic import BaseModel, EmailStr

class UserModel(BaseModel):
    name: str
    email: EmailStr  # Автоматическая валидация!

Чеклист для обнаружения антипаттернов

  • Класс > 200 строк? (God Object, Large Class)
  • Метод > 20 строк? (Long Method)
  • Код повторяется > 2 раз? (Duplicate Code)
  • Много параметров функции? (Data Clumps)
  • Длинные цепи вызовов? (Message Chains)
  • Условная логика вместо полиморфизма? (Switch Statements)
  • Код для несуществующих требований? (Speculative Generality)

Решение: Refactoring

# 1. Запусти тесты: убедись, что всё работает
# 2. Малые шаги: один refactoring за раз
# 3. Снова тесты: проверь каждый шаг

# До (плохо)
def process(users):
    result = []
    for u in users:
        if u['active']:
            result.append({'id': u['id'], 'name': u['name']})
    return result

# Шаг 1: Используй список list comprehension
def process(users):
    return [{'id': u['id'], 'name': u['name']} for u in users if u['active']]

# Шаг 2: Используй объект
from dataclasses import dataclass

@dataclass
class User:
    id: int
    name: str
    active: bool

def process(users: list[User]) -> list[dict]:
    return [{'id': u.id, 'name': u.name} for u in users if u.active]

# Шаг 3: Используй метод класса
def process(users: list[User]) -> list['UserDTO']:
    return [UserDTO.from_user(u) for u in users if u.active]

Итоги

Антипаттерны — это признаки плохой архитектуры:

  • God Object: Разделяй ответственность
  • Long Methods: Выноси подлогику в методы
  • Duplicate Code: Используй DRY принцип
  • Data Clumps: Группируй данные в объекты
  • Switch Statements: Используй полиморфизм
  • Speculative Generality: YAGNI (You Aren't Gonna Need It)

Главное правило: Пиши простой, понятный код. Рефакторь постепенно.

Какие знаешь антипаттерны? | PrepBro