Глава 5

KISS и YAGNI на практике

Допустим, разработчик заранее предполагает, что скидки когда-нибудь будут загружаться из базы, файла, внешнего API и панели администратора. Он создаёт общий движок правил, хотя сейчас существует только одно условие.

TypeScript
interface DiscountProvider {
  getRules(context): Rule[];
}

class DiscountProviderFactory {
  create(source) {
    if (source === "database") { /* ... */ }
    if (source === "remote") { /* ... */ }
    if (source === "config") { /* ... */ }
  }
}

// All three variants are still imaginary

Формально архитектура выглядит гибкой. Фактически в проекте появились интерфейс, реестр, фабрика и формат конфигурации. Каждый новый участник команды сначала изучает механизм, а уже потом - простое правило скидки. Что предлагает KISS: оставить правило явной функцией с понятным именем, входом и результатом. Чтобы проверить скидку, достаточно открыть один файл.

TypeScript
function calculateDiscount(subtotal) {
  if (subtotal <= 10000) {
    return 0;
  }

  return subtotal * 0.1;
}

Что добавляет YAGNI: не создавать несколько источников правил до появления хотя бы второго реального источника. При этом решение не должно мешать будущему изменению - и простая функция подходит под оба условия сразу.

Разницу удобно держать как таблицу сигналов: одно и то же будущее изменение можно готовить нормально или преждевременно.

Сигнал · Нормальная подготовка · Преждевременная архитектура

  • Будущее изменение - Изолировать формулу в именованной функции; Создать платформу для неизвестных вариантов
  • Тестирование - Проверить функцию несколькими значениями; Подменять четыре слоя ради одной формулы
  • Расширение - Менять структуру после второго реального сценария; Проектировать все возможные сценарии заранее
KISS и YAGNI считают решения, а не строки. Простая функция и гибкий движок могут быть одинаковой длины. Разница в том, сколько решений и слоёв придётся удерживать в голове, чтобы изменить одну формулу.

Пока правил мало, дублирование не проблема. Но как только похожий код появляется во втором месте, вступает DRY - и тут важно понять его правильно.

Ссылки