Модульность — это мираж
Давайте я открою вам секрет: ваша кодовая база — не матрёшка. Те 47 уровней абстракции, которые вы создали, не делают вас умнее — они заставляют будущего-вас плакать над своим дорогущим кофе ручной работы. Модульность подобна острому соусу: немного улучшает вкус, но если утопить в нём свой буррито, то в три часа ночи вы будете молиться фарфоровым богам.
Иллюзия модульности
Мы все через это проходили. Вы начинаете с благих намерений:
def calculate_order_total(items):
return sum(item['price'] * item['quantity'] for item in items)
Затем демон лучших практик нашёптывает: «А что, если нам понадобятся разные стратегии ценообразования? Давайте сделаем так, чтобы это работало на будущее!» Внезапно вы смотрите на код:
class AbstractPricingStrategy(metaclass=ABCMeta):
@abstractmethod
def calculate(self, items: List[ItemProtocol]) -> Decimal:
pass
class DefaultPricingStrategy(AbstractPricingStrategy):
def __init__(self, tax_adapter: TaxServiceInterface):
self._tax_adapter = tax_adapter
def calculate(self, items) -> Decimal:
# 42 строки сопоставления шаблонов корпоративного уровня
Теперь для вашего простого расчёта требуется внедрение зависимостей, три интерфейса и ещё кое-что. Поздравляем — вы только что создали разработку, управляемую фреймворком!
Видите эту машину Рубе Голдберга? Именно в этот момент ваш генеральный директор спрашивает: «Почему изменение скидки в размере 5 долларов занимает 3 недели?»
Когда модульность столкнулась с реальностью
Давайте найдём проблему в этом фрагменте кода на Java:
public interface UserService {
User createUser(UserDTO userDTO);
}
public class UserServiceImpl implements UserService {
private final UserValidator validator;
private final UserRepository repo;
private final EmailService emailService;
// 15 параметров конструктора позже...
}
Вы создали:
- кошмар поддержки;
- парадокс тестируемости (нужно имитировать 10 зависимостей только для проверки одного метода);
- гарантии занятости (но только если вы планируете никогда не уходить). Горькая правда? Большинство проектов не живут достаточно долго, чтобы оправдать свою архитектуру. Я видел кодовые базы, которые были чрезмерно разработаны для масштаба, которого они никогда не достигали. Это всё равно что построить ускоритель частиц для колки орехов.
Практические контрмеры
Фильтр из трёх вопросов перед созданием нового модуля:
- Будет ли это изменяться независимо от других компонентов?
- Уменьшает ли эта абстракция когнитивную нагрузку?
- Я делаю это из-за реальных потребностей или фантазий архитектурных астронавтов? Попробуйте выполнить следующие действия по рефакторингу:
- Найдите класс «менеджер», координирующий 5+ зависимостей.
- Встройте методы, пока они не начнут вызывать сопротивление.
- Посмотрите, как скрытое дублирование появляется словно по волшебству.
# Перед: 8 файлов, 3 шаблона
result = PriceCalculatorFactory.get_instance().calculate(order)
# После: 1 файл, 0 паттернов фабрики
result = sum(item.price * item.quantity for item in order.items)
Когда модульность действительно работает
Есть золотая середина — как рецепт мясного рулета вашей бабушки. Это работает, когда:
- разные команды владеют компонентами;
- вы создаёте настоящие распределённые системы;
- вам нужно поддерживать несколько конкретных реализаций (реальных, а не тех, что «могут понадобиться когда-нибудь»). Но даже тогда помните закон Джеффа Этвуда: «Лучший код — это отсутствие кода». Иногда самое модульное решение — удалить функцию.
Набор инструментов для прагматиков
- Пишите код, который легко удалять.
- Можете ли вы удалять функции без кровопролития?
- Примите скромную функцию.
- Не каждому понятию нужно собственное пространство имён.
- Реализуйте разработку, основанную на принципе YAGNI (You Aren’t Gonna Need It — вам это не понадобится).
- Будущие требования — ужасные хрустальные шары.
- Оптимизируйте для чтения, а не для записи.
- Код читают в 10 раз чаще, чем пишут. Хватит хвастаться.
В следующий раз, когда вы возьмётесь за
AbstractFactoryProxyDecorator
, спросите себя: «Это упрощает задачу или просто делает мой код более „профессиональным“?». Ваши коллеги по команде (и серверы production) будут вам благодарны. Последняя мысль: если бы программирование было столярным делом, чрезмерная модульность заключалась бы в использовании 1000 зубочисток для изготовления стула. Это может выглядеть впечатляюще, но удачи вам в том, чтобы сидеть на нём.
- Код читают в 10 раз чаще, чем пишут. Хватит хвастаться.
В следующий раз, когда вы возьмётесь за