DRY, KISS и YAGNI

Зачем это на интервью

Эти принципы помогают обсуждать качество решения после того, как оно работает. Интервьюер ожидает, что E4 отличит дублирование знания от похожего кода, выберет простой путь и объяснит, почему не добавляет гипотетическую расширяемость. Это особенно важно в задаче, где «красивый» паттерн делает изменение менее прозрачным.

Минимум для E4

  • Отличать DRY про единый источник знания от механического удаления одинаковых строк.
  • Выбирать KISS: решение с наименьшей случайной сложностью, понятное следующему читателю.
  • Применять YAGNI: не реализовывать возможность без текущего проверяемого требования.
  • Рефакторить повтор только после понимания, что части меняются вместе.

DRY (Don’t Repeat Yourself) запрещает несколько независимых представлений одного правила. Например, лимит кредита, зашитый и в валидаторе, и в SQL-предикате, расходится при изменении политики. Два похожих HTTP-обработчика не обязательно нарушают DRY: их сходство может быть случайным, а будущие изменения — разными.

KISS (Keep It Simple, Stupid) призывает минимизировать случайную сложность: уровни косвенности, состояния, неявные соглашения и магию конфигурации. Простота не означает примитивность; корректный алгоритм с явными инвариантами лучше короткого, но хрупкого кода.

YAGNI (You Aren’t Gonna Need It) требует реализовывать подтверждённую потребность, а не прогноз. Он не запрещает оставлять точку расширения, если она уже нужна текущему сценарию, например передать Clock для детерминированного теста.

Углубление для E5/Senior

E5 рассматривает эти правила вместе. Раннее объединение дублирующегося кода может нарушить KISS, а отказ от абстракции может создать дорогую повторяемую работу. Решение принимают по траектории изменений: есть ли одинаковая бизнес-инварианта, кто владеет ей, как часто она меняется и насколько опасно расхождение.

Полезна «правила трёх» как сигнал к исследованию, а не закон: после третьего похожего случая собрать факты, выделить общую семантику и сохранить различия явными. Для публичных API YAGNI особенно ценен: каждое поле и флаг становятся обязательством совместимости. Удалить неиспользованную возможность после релиза часто дороже, чем добавить её позже.

Ключевые понятия

ПринципЗащищает отВопрос перед изменением
DRYРасхождения бизнес-правилЭто одно и то же знание или только похожая форма?
KISSСлучайной сложностиМожно ли объяснить поток выполнения без скрытой магии?
YAGNIПлаты за неиспользуемую возможностьКакое текущее требование оправдывает этот код?

Пример DRY — один конструктор доменного правила, используемый на границе ввода и в прикладном сервисе:

func ValidateQuantity(qty int) error {
    if qty < 1 || qty > 100 {
        return fmt.Errorf("quantity must be in [1, 100]")
    }
    return nil
}

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

Типовые вопросы

  1. Почему два одинаковых фрагмента не всегда нужно объединять?
    • Они могут выражать разные доменные причины и должны иметь возможность изменяться независимо.
  2. Что считать «простым» решением?
    • То, у которого понятны данные, порядок выполнения, ошибки и границы; число строк вторично.
  3. Когда YAGNI не применяют буквально?
    • Когда требование уже включает надёжность, безопасность или тестируемость, например таймауты для внешнего вызова.
  4. Как понять, что абстракция преждевременна?
    • У неё нет второго реального клиента, контракт описывает догадки, а изменение одного случая требует объяснять общий механизм.
  5. Как связаны DRY и copy-paste?
    • Copy-paste — лишь возможный симптом; нарушением становится дублирование одного изменяемого знания.
  6. Допустимы ли feature flags с точки зрения YAGNI?
    • Да, если они нужны для безопасного rollout сейчас и имеют владельца, срок удаления и наблюдаемость.

Практика

  • Найдите два похожих обработчика создания сущности и выпишите, какие правила у них общие, а какие разные.
    • Критерии готовности: общее правило имеет один владелец и тест; различия остались в вызывающих сценариях; нет абстракции с параметрами, описывающими все будущие варианты.
  • Спроектируйте API экспорта отчёта только для CSV, хотя в бэклоге есть PDF.
    • Критерии готовности: контракт не содержит неиспользуемого format; добавление PDF позже локализуется в одном месте; решение и ограничение задокументированы в тесте или ADR.

Частые ошибки и ловушки

  • Объединять одинаковые строки, игнорируя разные инварианты и владельцев.
  • Оправдывать сложную архитектуру словом «масштабирование» без измеримого сценария роста.
  • Использовать YAGNI, чтобы не добавить обязательную валидацию, метрики или обработку ошибок.
  • Создавать универсальный helper с десятком булевых параметров вместо двух ясных функций.
  • Не удалять временную универсальность после изменения требований.

Связанные темы

Источники

  • Andy Hunt, Dave Thomas. The Pragmatic Programmer, 20th Anniversary Edition, 2019.
  • Kent Beck. Extreme Programming Explained, 2nd ed., 2004.
  • Martin Fowler. Rule of Three.