Давным-давно, когда деревья были большими, а я еще только начинала свой путь в программировании, я конечно читала про SOLID, и тогда это было свежо. С тех пор прошло миллион лет много времени. Я уходила в долгий декрет, выходила обратно, меняла специализацию. И вот внезапно на работе разговор зашел о SOLID. И каково же было мое удивление, что ничего лучше пока не придумали. Эта статья планировалась, как обзорная, в которую можно взглянуть и вспомнить — о чем эти принципы и зачем они нужны.


image


Итак, рано или поздно любой человек, пишущий код, сталкивается с тем, что после него совсем не потоп, а кто-кто, кто будет этот код обслуживать. Отсюда возникает необходимость писать не просто код, который работает, а код, который легко расширять, модифицировать, в общем с которым приятно иметь дело. И причина нестареющей популярности SOLID, возможно, в том, что зная эти принципы писать хороший код легко. А вот без них легко наколхозить. Независимо от языка, на котором пишем (хотя, возможно, есть нюансы, просто для меня они пока неочевидны).


Даже если вы слышите эту аббревитуру первый раз, но вы разработчик и пишете годный год, а не плодите баги пачками (хотя как без них)… то скорее всего в свой работе вы уже используете SOLID. Просто не знаете об этом.


Теперь по порядку.


Когда и кем сформулированы


Принципы SOLID были сформулированы 2011 году, в книге “Принципы, паттерны и методики гибкой разработки на языке C#” Роберт Мартина. Воббще говоря первое издание книги вышло гораздо раньше, в 2005 году.


image
"Принципы, паттерны и методики гибкой разработки на языке C#”, Роберт Мартин"


В этой книге для удобства начинающих и не очень девелоперов были сформулированы правила хорошего кода. И часть из них (первые пять) и составляют те самые SOLID принципы.


Кратко


Лучшее краткое описание по-моему на википедии.
S Single responsibility principle Единая отвественность
O Open/closed principle Открытость/закрытость
L Liskov substitution principle Подстановка Лисков
I Interface segregation principle Разделение интерфейса
D Dependency inversion Инверсия зависимостей


Теперь чуть подробнее о каждом принципе.


S Single responsibility


За модуль должен быть ответственен один и только один специалист.

где “специалист”?—?это роль в компании, например, разработчик баз данных или аналитик и т.д.
Или то же самое на языке оригинала:


A module should be responsible to one, and only one, actor.

image
"Боливар не выдержит двоих."


На мой взгляд это самый простой и логичный принцип из всех. Смысл в том, что каждый должен заниматься своим делом и не важно, дворник ты или метод класса.


Хотя кто из нас не начинал с кода, который и в базу лезет и в лог пишет и еще что-нить посчитает и в глобальный объект сохранит? Только вот обслуживать подобный код?—?так себе удовольствие. Поэтому одна сущность?—?одна ответственность.


O Open/closed principle


Программные сущности … должны быть открыты для расширения, но закрыты для модификации.
A software artifact should be open for extension but closed for modification.

Другими словами, новую функциональность получаем добавлением нового, а не изменением существующего кода.


На мой взгляд этот принцип тесно связан с применением шаблонов проектирования. На эту тему принято упоминать классический труд так называемой “банд четырех” «Приёмы объектно-ориентированного проектирования. Паттерны проектирования».


image
«Приёмы объектно-ориентированного проектирования. Паттерны проектирования» Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес


Но опять же на вкус и цвет фломастеры разные. Мне больше нравится “Паттерны проектирования” Элизабет и Эрика Фримен, где то же самое, только поживее. Серию Head First можно считать слишком простой, кому-то не нравится подача в виде комиксов, но зато дойдет даже до ёжика.


image
"Паттерны проектирования" Фримен Эрик, Фримен Элизабет


Для себя я кратко сформулировала этот принцип как "добавляй, а не меняй".


L Liskov substitution principle


Функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа, не зная об этом.

Functions that use pointers to base classes must be able to use objects of derived classes without knowing it.


Если честно из этой формулировки ничего непонятно. Поэтому я нашла другую, гораздо гуманнее:
Наследующий класс должен дополнять, а не замещать поведение базового класса.
Уже лучше, согласитесь?


А теперь вопрос на засыпку?—?чем это отличается от предыдущего принципа? Дополняем новым, а не изменяем старое. Хм. В общем начинает складываться впечатление, что эти принципы?—?какие-то частные формулировки какого-то общего правила. Только вот какого, пока неясно.


I Interface segregation principle


Много интерфейсов, специально предназначенных для клиентов, лучше, чем один интерфейс общего назначения.
Make fine grained interfaces that are client specific.

Сразу вспоминается


image


Где-то я уже это слышала… Что-то про ответственность… Да это уже было в первом принципе!


D Dependency inversion.


Зависимость на Абстракциях. Нет зависимости на что-то конкретное.
Depend on abstractions, not on concretions.

Для меня этот принцип про активное использование интерфейсов вместо конкретных реализаций везде, где это возможно. И почему-то сразу в голову приходит паттерн Service locator. Наверное, потому что он реализует данный принцип “в лоб”.


Если совсем коротко, то ?— ?резолвим интерфейсы как можно ближе к точке входа в программу. То есть не в недрах тундры, а где-то наверху, ближе к пользователю.


Итого


Сдается мне, что Роберту Мартину очень нужно было написать толстую книжку. И чем объемнее, тем лучше. Потому что эти принципы… очень напоминают одно и тоже разными словами. Ну вы знаете, повторение мать учения и все такое.


Ну и наподследок для тех, кто дочитал? —? веселые картиночки по теме.