Принципы проектирования

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

Карта раздела

  1. Разделение ответственности — как выделять независимые причины изменения.
  2. Связность и зацепление — как оценивать границы модуля и стоимость зависимостей.
  3. Композиция вместо наследования — как собирать поведение из небольших компонентов в Go.
  4. SOLID на практике — как применять принципы без догматизма.
  5. DRY, KISS и YAGNI — как не дублировать знание и не строить преждевременную сложность.
  6. Инверсия и внедрение зависимостей — как направлять зависимости к стабильным контрактам.
  7. Инженерные trade-offs — как обосновывать выбор через требования и измерения.

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

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

Минимум для E4

  • Находить в задаче независимые причины изменения и отделять transport, прикладную логику и инфраструктуру.
  • Объяснять разницу между высокой связностью модуля и сильным зацеплением модулей.
  • Предпочитать явную композицию и маленькие интерфейсы реализации, когда это упрощает замену или тест.
  • Не вводить общий слой до появления реального общего изменяемого знания.

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

  • Проектировать границы по владению данными, консистентности, отказам и темпу изменений команд.
  • Оценивать стоимость абстракции: API, миграции, наблюдаемость, обратная совместимость и когнитивная нагрузка.
  • Подтверждать решение тестами, метриками и историей изменений, а не только чистотой диаграммы.

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

  • Ответственность — причина, по которой компонент должен измениться.
  • Связность (cohesion) — насколько элементы модуля работают ради одной задачи.
  • Зацепление (coupling) — насколько изменение одного модуля требует знания или изменения другого.
  • Композиция — сборка поведения через поля, интерфейсы и делегирование.
  • Абстракция — контракт, скрывающий вариативную деталь; она оправдана наличием вариативности.

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

  1. Как понять, что класс или пакет делает слишком много?
    • У него появляются независимые причины изменения, несвязанные зависимости и тесты, которые требуют множества разных сценариев настройки.
  2. Почему нельзя просто применить все SOLID-принципы?
    • Каждый дополнительный слой имеет цену. Принцип направляет выбор при реальном изменении, но не заменяет требования.
  3. Что важнее: отсутствие дублирования или простота?
    • Нужно устранять дублирование знания с общей причиной изменения; похожий код в разных доменах часто безопаснее преждевременной общей абстракции.
  4. Почему в Go интерфейс обычно объявляет потребитель?
    • Потребитель формулирует минимальные нужные ему операции, поэтому контракт не превращается в широкий интерфейс поставщика.
  5. Как доказать, что новая граница лучше старой?
    • Показать сценарий изменения, уменьшение затронутых модулей, изолированный тест и отсутствие лишней эксплуатационной сложности.

Практика

  • Возьмите HTTP-handler с SQL и бизнес-правилами. Разделите parsing/validation, use case и repository; критерий: use case тестируется без httptest и реальной БД.
  • Для двух похожих интеграций выпишите, что совпадает по смыслу, а что меняется независимо; критерий: решение об общем контракте содержит минимум два подтверждённых сценария вариации.
  • Проведите review небольшого PR: назовите одну границу, одну лишнюю абстракцию и проверяемый критерий улучшения.

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

  • Делить код только по техническим слоям, не замечая границ домена и владения данными.
  • Выносить общий helper для похожего синтаксиса, хотя правила и будущие изменения различаются.
  • Создавать интерфейс на каждую структуру и получать косвенность без альтернативной реализации.
  • Оценивать дизайн по числу паттернов вместо стоимости следующего изменения.

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

База разработки и Computer Science · Разделение ответственности · Go · Проектирование Go-приложений · System Design · Тестирование

Источники

  • Robert C. Martin, Clean Architecture и Agile Software Development: Principles, Patterns, and Practices.
  • John Ousterhout, A Philosophy of Software Design.
  • Документация Go: Effective Go и Code Review Comments.
  • Eric Evans, Domain-Driven Design, главы о границах модели и модулей.