Связано ли DRY со связанностью
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
DRY и связанность кода
Да, принцип DRY (Don't Repeat Yourself) тесно связан с концепцией связанности или сцепления кода. Однако это отношение неоднозначное и требует аккуратного понимания.
Что такое DRY?
DRY — принцип разработки, который гласит: каждая часть функциональности должна быть реализована ровно один раз в коде. Идея состоит в том, что не должно быть дублирования логики.
Что такое связанность?
Связанность (coupling) — это степень, в которой один модуль зависит от другого. Высокая связанность означает, что изменение одного компонента требует изменения других.
Связь между ними
Перво-наперво: DRY НЕ всегда является причиной высокой связанности, но неправильное применение DRY может её увеличить.
Пример 1: DRY как причина связанности
# ❌ Плохо: извлекли повторяющийся код, но создали нежелательную зависимость
class UserService:
def get_user_email(self, user_id):
# Получение email из базы
return database.query(f"SELECT email FROM users WHERE id = {user_id}")
class OrderService:
def send_order_confirmation(self, order_id):
# Используем тот же запрос для получения email
email = UserService().get_user_email(self.get_user_id_for_order(order_id))
self.send_email(email)
class NotificationService:
def notify_user(self, user_id):
# И снова повторяем логику
email = UserService().get_user_email(user_id)
self.send_notification(email)
Видим повторение get_user_email(), извлекли в отдельный метод — кажется, DRY выполнили. Но теперь OrderService и NotificationService сильно связаны с UserService. Если изменить сигнатуру метода или его поведение, нужно обновлять обе служ.
Пример 2: DRY без излишней связанности
# ✅ Хорошо: извлекли логику, но разделили ответственность
class UserRepository:
"""Отвечает за получение данных пользователя"""
def get_email(self, user_id: int) -> str:
return database.query(f"SELECT email FROM users WHERE id = {user_id}")
class UserService:
"""Бизнес-логика работы с пользователями"""
def __init__(self, repository: UserRepository):
self.repository = repository
def get_user_email(self, user_id: int) -> str:
return self.repository.get_email(user_id)
class OrderService:
"""Работает только с абстракцией"""
def __init__(self, user_service: UserService):
self.user_service = user_service
def send_order_confirmation(self, order_id: int):
user_id = self.get_user_id_for_order(order_id)
email = self.user_service.get_user_email(user_id)
self.send_email(email)
class NotificationService:
"""Также использует абстракцию"""
def __init__(self, user_service: UserService):
self.user_service = user_service
def notify_user(self, user_id: int):
email = self.user_service.get_user_email(user_id)
self.send_notification(email)
Здесь мы:
- Исключили дублирование (DRY)
- Использовали Dependency Injection для слабой связанности (Low Coupling)
- Разделили ответственность (Single Responsibility)
Проблема с "неправильным" DRY
Основная ошибка: извлекать в отдельную функцию код, который совпадает синтаксически, но семантически различен.
# ❌ Плохо: синтаксическое сходство, но разные смыслы
def format_value(value):
"""Общая функция для всех форматирований"""
return f"{value:.2f}"
class PriceFormatter:
def format(self, price):
return format_value(price) # Используем общую функцию
class PercentageFormatter:
def format(self, percentage):
return format_value(percentage) # Используем ту же функцию
Проблема: если требования поменяются, цены должны округляться до 2 знаков, а проценты до 1, мы создадим излишнюю связанность.
# ✅ Хорошо: разделили по смыслу
class PriceFormatter:
@staticmethod
def format(price: float) -> str:
return f"${price:.2f}"
class PercentageFormatter:
@staticmethod
def format(percentage: float) -> str:
return f"{percentage:.1f}%"
Правильный баланс
- Исключай дублирование — когда логика действительно одна и та же и по смыслу, и по реализации
- Избегай излишней связанности — используй абстракции (interfaces, dependency injection)
- Разделяй по ответственности — один класс/модуль = одна задача
- Прежде всего подумай — прежде чем извлекать код, убедись, что он действительно должен быть общим
Вывод: DRY и слабая связанность идут рука об руку, если правильно применять оба принципа. DRY помогает уменьшить объём кода, а правильная архитектура помогает избежать излишней связанности при этом.