Глава 2

Одна функция заказа, на которой проявятся все шесть принципов

Возьмём небольшой интернет-магазин. Первая версия умеет посчитать сумму заказа, применить скидку и добавить стоимость доставки. Требование кажется простым, поэтому разработчик пишет всё в одной функции.

TypeScript
function calculateOrder(order) {
  let subtotal = 0;

  for (const item of order.items) {
    subtotal += item.price * item.quantity;
  }

  let discount = subtotal > 10000 ? subtotal * 0.1 : 0;
  let delivery = subtotal > 5000 ? 0 : 500;

  return subtotal - discount + delivery;
}

Код работает: тестовый заказ выдаёт правильную сумму. Именно в этот момент особенно легко начать "улучшать архитектуру" просто потому, что мы знаем красивые слова. Но сначала стоит увидеть реальные свойства решения. Что здесь уже нормально: формула читается сверху вниз, в ней нет фабрик, контейнеров и абстрактных провайдеров - для первой версии это достоинство, а не недостаток. Что настораживает: функция одновременно знает правила скидки, доставки и структуру заказа. Если эти части начнут меняться независимо, одна функция станет точкой постоянных конфликтов.

Причём проблема не в сегодняшнем коде, а в его траектории.

  1. Сегодня: одно правило скидки, один способ доставки
  2. Через месяц: промокоды, категории клиентов, два перевозчика
  3. Через полгода: маркетинг и логистика меняют правила независимо
Первый навык - не про паттерны. Не спрашивайте, какой паттерн сюда вставить. Спросите, какая часть кода уже создаёт измеримую проблему. Пока проблемы нет - её и не надо "решать" заранее.

Дальше мы будем возвращаться к этой функции в каждой практике и смотреть, какой принцип отвечает на очередное реальное изменение. Начнём с самого раннего вопроса: достаточно ли просто решение.

Ссылки