Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Антипаттерны и Code Smells
antipatterns

Антипаттерны и Code Smells

Распространённые ошибки: God Object, Singleton-глобал, Premature Optimization, Leaky Abstractions. Рефакторинг к чистому коду.

Антипаттерны и Code Smells

Антипаттерн — это решение, которое кажется правильным, но приводит к плохим последствиям.


#God Object: божественный объект

Проблема: Класс, который знает и делает слишком много.

# ❌ ПЛОХО: God Object class Application: def __init__(self): self.db = Database() self.cache = Cache() self.logger = Logger() self.config = Config() self.auth = AuthService() self.email = EmailService() # ... ещё 20 зависимостей ... def process_order(self, order_id: int): # 200 строк кода с бизнес-логикой, SQL, отправкой email... pass def generate_report(self, start, end): # 150 строк отчётности pass def send_notifications(self): # 100 строк уведомлений pass # ... ещё 50 методов ... # Проблемы: # 1. Невозможно тестировать # 2. Любое изменение ломает что-то другое # 3. Непонятно, за что отвечает класс
# ✅ ХОРОШО: Разделение ответственности class OrderService: def __init__(self, db, email_service): self._db = db self._email = email_service def process_order(self, order_id: int): # Только бизнес-логика заказа order = self._db.get_order(order_id) # ... логика ... self._email.send_confirmation(order) class ReportService: def __init__(self, db, cache): self._db = db self._cache = cache def generate_report(self, start, end): # Только отчётность pass class NotificationService: def __init__(self, db, email_service, sms_service): self._db = db self._email = email_service self._sms = sms_service def send_notifications(self): # Только уведомления pass

#Singleton как глобальная переменная

Проблема: Singleton используется как глобальное состояние, что затрудняет тестирование.

# ❌ ПЛОХО: Singleton-глобал class Config(Singleton): def __init__(self): self.debug = False self.database_url = "prod://db" # Везде в коде: def get_user(user_id: int): config = Config() # Скрытая зависимость! db = Database(config.database_url) return db.get(user_id) # В тестах нельзя подменить конфигурацию!
# ✅ ХОРОШО: Dependency Injection class Config: def __init__(self, debug: bool = False, database_url: str = ""): self.debug = debug self.database_url = database_url def get_user(user_id: int, config: Config): # Явная зависимость db = Database(config.database_url) return db.get(user_id) # В production: config = Config(debug=False, database_url="prod://db") user = get_user(1, config) # В тестах: test_config = Config(debug=True, database_url="test://db") user = get_user(1, test_config)

#Premature Optimization: преждевременная оптимизация

Проблема: Оптимизация до понимания реальных узких мест.

# ❌ ПЛОХО: Преждевременная оптимизация class OptimizedCache: """Сложный кэш с LRU, lock-free алгоритмами...""" # 500 строк сложного кода # Используется для кэширования 10 запросов в день
# ✅ ХОРОШО: Сначала простой код from functools import lru_cache @lru_cache(maxsize=128) def get_user(user_id: int): return db.get_user(user_id) # Профилируем, находим реальные узкие места # Оптимизируем только если нужно

Правило: Make it work, make it right, make it fast.


#Leaky Abstraction: протекающая абстракция

Проблема: Абстракция раскрывает детали реализации.

# ❌ ПЛОХО: ORM с протекающей абстракцией class UserQuery: def __init__(self, session): self.session = session def get_active_users(self): # Клиент должен знать SQL для оптимизации! return self.session.execute(""" SELECT * FROM users WHERE is_active = true AND last_login > NOW() - INTERVAL '30 days' """) # Абстракция "протекает" — нужно знать SQL
# ✅ ХОРОШО: Чистая абстракция class UserRepository: def get_active_users(self) -> List[User]: """Возвращает активных пользователей за 30 дней""" # Детали реализации скрыты return self._db.query(User).filter( User.is_active == True, User.last_login > datetime.now() - timedelta(days=30) ).all()

#Spaghetti Code: спагетти-код

Проблема: Отсутствие структуры, перемешанная логика.

# ❌ ПЛОХО: Спагетти-код def process_data(data): result = [] for item in data: if item > 0: if item % 2 == 0: x = item * 2 if x > 10: x = x - 5 if x > 20: x = x + 10 result.append(x) else: result.append(x) else: result.append(item) else: if item < -10: result.append(item * -1) elif item < -5: result.append(item + 10) # ... ещё 5 уровней вложенности ... return result
# ✅ ХОРОШО: Рефакторинг def process_data(data: List[int]) -> List[int]: result = [] for item in data: if item <= 0: processed = handle_negative(item) if processed is not None: result.append(processed) continue if item % 2 == 0: processed = handle_even_positive(item) if processed is not None: result.append(processed) else: result.append(item) return result def handle_negative(item: int) -> Optional[int]: if item < -10: return item * -1 elif item < -5: return item + 10 return None def handle_even_positive(item: int) -> Optional[int]: x = item * 2 if x > 20: return x + 10 elif x > 10: return x - 5 return x

#Magic Numbers: магические числа

Проблема: Числа без объяснения смысла.

# ❌ ПЛОХО: Магические числа def calculate_price(price: float) -> float: if price > 1000: return price * 0.9 elif price > 500: return price * 0.95 return price def is_valid_timeout(timeout: int) -> bool: return 0 < timeout < 86400
# ✅ ХОРОШО: Именованные константы BULK_DISCOUNT_THRESHOLD = 1000 BULK_DISCOUNT_RATE = 0.9 SMALL_DISCOUNT_THRESHOLD = 500 SMALL_DISCOUNT_RATE = 0.95 SECONDS_PER_DAY = 86400 def calculate_price(price: float) -> float: if price > BULK_DISCOUNT_THRESHOLD: return price * BULK_DISCOUNT_RATE elif price > SMALL_DISCOUNT_THRESHOLD: return price * SMALL_DISCOUNT_RATE return price def is_valid_timeout(timeout: int) -> bool: return 0 < timeout < SECONDS_PER_DAY

#Feature Envy: зависть к данным

Проблема: Метод использует данные другого класса больше, чем своего.

# ❌ ПЛОХО: Feature Envy class Report: def __init__(self, data: list): self.data = data class ReportGenerator: def generate_html(self, report: Report) -> str: # Использует report.data больше, чем свои данные html = "<html>" for item in report.data: html += f"<div>{item.name}: {item.value}</div>" html += "</html>" return html
# ✅ ХОРОШО: Переместить метод class Report: def __init__(self, data: list): self.data = data def to_html(self) -> str: html = "<html>" for item in self.data: html += f"<div>{item.name}: {item.value}</div>" html += "</html>" return html

#Long Method: длинный метод

Проблема: Метод длиннее 20-30 строк.

# ❌ ПЛОХО: Длинный метод def process_order(order): # Валидация (15 строк) if not order.items: raise ValueError("Empty order") if not order.customer: raise ValueError("No customer") # ... # Расчёт стоимости (20 строк) subtotal = 0 for item in order.items: # ... # Применение скидок (15 строк) # ... # Сохранение (10 строк) # ... # Отправка уведомлений (15 строк) # ...
# ✅ ХОРОШО: Выделение методов def process_order(order): validate_order(order) total = calculate_total(order) total = apply_discounts(order, total) save_order(order, total) send_notifications(order)

#Python-specific антипаттерны

#Mutable Default Arguments

# ❌ ПЛОХО: Изменяемый аргумент по умолчанию def add_item(item, items=[]): # Один список на все вызовы! items.append(item) return items add_item(1) # [1] add_item(2) # [1, 2] — а не [2]!
# ✅ ХОРОШО: None как значение по умолчанию def add_item(item, items=None): if items is None: items = [] items.append(item) return items

#Bare except

# ❌ ПЛОХО: Ловит всё, включая KeyboardInterrupt try: process() except: pass # Скрывает все ошибки!
# ✅ ХОРОШО: Конкретные исключения try: process() except ValueError as e: log_error(e) except ConnectionError as e: retry()

#EAFP vs LBYL

# ❌ ПЛОХО: LBYL (Look Before You Leap) — не Pythonic if key in my_dict and isinstance(my_dict[key], int): value = my_dict[key] else: value = 0
# ✅ ХОРОШО: EAFP (Easier to Ask Forgiveness than Permission) try: value = my_dict[key] if not isinstance(value, int): raise TypeError() except (KeyError, TypeError): value = 0

#Конец курса

Поздравляем! Вы изучили все 23 классических паттерна GoF, архитектурные паттерны и asyncio-паттерны с упором на Pythonic-реализации.

Что дальше:

  1. Практикуйтесь — применяйте паттерны в реальных проектах
  2. Изучайте исходники популярных библиотек — там много паттернов
  3. Читайте "Clean Code" и "Refactoring" для углубления
  4. Помните: паттерн — инструмент, а не цель!