handbookНаписать

SOLID ​

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

Что это ​

SOLID - аббревиатура из первых букв пяти принципов, которые собрал Роберт Мартин в начале 2000-х. По отдельности они старше: открытость/закрытость сформулировал Бертран Мейер в 1988 году, подстановку - Барбара Лисков в 1987-м. Вместе они описывают, как разложить код по модулям так, чтобы изменение требований затрагивало как можно меньше мест.

Это не правила, которые проверяет компилятор, а вопросы к коду. Почему этот класс меняется? Что сломается, если добавить ещё один вариант? Можно ли подставить другую реализацию? Сколько методов на самом деле нужно клиенту? Кто от кого зависит? Каждый принцип - один такой вопрос. Многие паттерны из каталога - готовые ответы на них.

Пять принципов ​

S - единственная ответственность. У модуля одна причина для изменения. Если класс меняется и когда бухгалтерия просит другой формат отчёта, и когда меняется правило подсчёта, - в нём две ответственности, и правка одной рискует сломать другую. Пример: подсчёт продаж и форматирование отчёта живут порознь, а между ними - неизменяемая сводка. Подробнее.

O - открытость/закрытость. Модуль открыт для расширения и закрыт для изменения. Новое поведение добавляется новым кодом, а не правкой проверенного. Пример: новый способ оплаты подключается к кассе отдельным классом и одной строкой при сборке, а сама касса не меняется. Подробнее.

L - подстановка Лисков. Подтип должен работать везде, где ждут базовый тип, без сюрпризов: не бросать новых исключений, не требовать большего, не обещать меньшего. Пример: хранилище только для чтения не наследует запись с "заглушкой", которая падает, а реализует только контракт чтения. Подробнее.

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

D - инверсия зависимостей. Модули верхнего уровня зависят от абстракций, а детали реализуют эти абстракции. Бизнес-логика объявляет, что ей нужно, а инфраструктура подстраивается. Пример: сервис уведомлений знает порт Mailer, а SMTP подключается снаружи и подменяется в тестах. Подробнее.

Как они связаны ​

Принципы поддерживают друг друга. Разделённые ответственности (S) проще закрыть для изменений (O). Расширение через абстракцию (O) работает, только если реализации честно подставимы (L). Узкие интерфейсы (I) делают подстановку честной: реализовать два метода без заглушек проще, чем десять. А зависимость от абстракций (D) - механизм, на котором держатся и O, и тестируемость: если модуль сам создаёт свои зависимости, подставить другую нельзя.

Когда принципы вредят ​

  • Абстракция без второго варианта. Интерфейс под единственную реализацию "на будущее" почти всегда оказывается не той формы, когда будущее наступает. Сначала два конкретных случая, потом обобщение.
  • Дробление ради дробления. Единственная ответственность, понятая как "один метод на класс", даёт десятки файлов по пять строк, и чтобы понять одну операцию, нужно открыть их все. Ответственность - это причина изменения, а не размер.
  • Расширяемость там, где её не просят. Закрытый для изменений модуль, который всё равно правят раз в неделю, - лишняя косвенность без выгоды. Иногда match на три ветки честнее и дешевле.
  • Инверсия без границы. Порт оправдан на границе с инфраструктурой (сеть, база, время) или там, где нужны тестовые двойники. Оборачивать в свой интерфейс стандартную библиотеку или собственный соседний класс - церемония.
  • Принципы вместо языка. В Go, Python и TypeScript функция, протокол или структурный тип часто решают задачу без иерархии классов. Приём из Java, перенесённый буквально, в этих языках выглядит чужим.

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

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

  • Стратегия - открытость/закрытость и инверсия зависимостей на одном паттерне
  • Адаптер - как подключить внешнюю библиотеку к своему порту
  • Репозиторий - инверсия зависимостей для хранения данных
© 2014-2026 Тимур ТурдыевСайт и справочник работают на VPS от AdminVPS