Принципы проектирования SOLID за 7 минут.

ООП подход к написанию приложений сделал возможным написание хорошо масштабируемого и поддерживаемого кода, но как и в случае с любой хорошей вещью, попав в неопытные руки, проект чуть больше лендинг страницы, содержащий в себе более десяти взаимосвязанных классов, начинает стремительно становится громоздкой, сильно связанной мешаниной классов. И чтобы минимизировать вероятность плохих результатов, достаточно придерживаться 5 принципам абревиатуры SOLID.

Принципы SOLID были сформулированы Робертом Мартином (известен также как дядюшка Боб), человеком с огромным практическим опытом, автором книг, посвященных архитектуре приложений, которые сейчас считаются классикой в мире программирования.

SOLID — это аббревиатура по первым буквам 5 принципов, придерживаясь которых, ваш код станет более «чистым» и легче в поддержке и масштабировании.

  • Single Responsibility Principle (Принцип единственной ответственности).
  • Open-Closed Principle (Принцип открытости-закрытости).
  • Liskov Substitution Principle (Принцип подстановки Барбары Лисков).
  • Interface Segregation Principle (Принцип разделения интерфейса).
  • Dependency Inversion Principle (Принцип инверсии зависимостей).

Single Responsibility Principle.

Если кратко, то Принцип единственной ответсвенности, говорит: Каждый класс решает только одну задачу.

Более современным определением является: Каждый объект имеет одну ответсвенность только для одного actor.

Если подробнее то, принцип утверждает:

  • Каждый объект должен иметь одну обязанность, и эта обязанность должна быть полностью инкапсулирована в класс.
  • Объект не должен быть похож на «швейцарский нож».
  • Одна ответсвенность, она же причина для изменения, может быть только перед единственным actor (пользователем с одной ролью).

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

Для примера, есть интернет маназин, и разные пользователи с разными ролями могут просить функционал о статистики дневных продаж. Вот только Владелец бизнеса, Аналитик или условный специалист по контекстной рекламе будут желать в отчете о дневных продаж видеть разные параметры: для кого-то важны доход/расход, а кто-то в том числе видеть динамику к предыдущему дню, а кто-то желает видеть продажи новым пользователям, пришедшим по интернет-рекламе. Эти разные роли — могут просить периодически изменения в подобном отчете, а соответсвенно функционал отчета для этих ролей должны реализовывать разные классы (модули), чтобы не нарушался Принцип единственной отсвенности.

Open-closed Principle.

Если кратко, то принцип открытости/закрытости говорит: программные объекты (классы, модули, функции и т.д.) должны быть открыты для расширения, но закрыты для модификации/изменения.

Если развернуто, то принцип утверждает:

  • Программные объекты (классы, модули, функции и т.п.) объекты могут менять свое поведение без изменения их исходного кода
  • «Закрыт для модификации» означает, что мы уже разработали класс, и он прошел модульное тестирование. Мы не должны менять его, пока не найдем ошибки.
  • В терминах ООП означает, что для расширения функциональности вашего класса, хороший вариант, это наследование.
  • При наследовании и расширении поведения следует помнить о соблюдении 3-го принципе SOLID — принципе подстановке Лискова (о нем рассказано ниже).

Liskov Substitution Principle.

Если кратко, то Принцип подстановки Барбары Лисков утверждает: Необходимо, чтобы подклассы могли бы служить заменой для своих суперклассов.

В фор­му­ли­ровке Роберта Мар­ти­на: «функ­ции, кото­рые исполь­зуют базо­вый тип, должны иметь воз­мож­ность исполь­зо­вать под­типы базо­вого типа не зная об этом». Также можно сказать, что , то есть поведение наследуемых классов должно быть ожидаемым для кода, использующего переменную базового типа.

Если развернуто, то принци гласит:

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

Когда нарушается принцип подстановки Барбары Лисков? Например, если класс наследник расширяет метод из базового класса и в качестве функционала добавляет возврат из метода дополнительных типов. Для примера: если какой-либо метод в родительском классе предусматривает возврат массива array, то если класс-наследник к возврату массива добавит при некоторых обстоятельствах возврат, например NULL, то принцип нарушен, так как весь код приложения использующий этот метод НЕ ПРЕДУСМАТРИВАЕТ обработку значений для типов отличных от array, как это было реализовано в родительском супер-классе.

Interface Segregation Principle.

Если кратко, то Принцип Разделения Интерфейсов говорит: Создавайте узкоспециализированные «тонкие» интерфейсы.

Если развернуто, то принцип гласит:

  • Слишком «толстые» интерфейсы необходимо разделять на более узкоспециализированные, более «тонкие», более специфичные и конкретные.
  • Клиенты, реализующие интерфейсы, не должны зависеть от методов, которые они не будут использовать.
  • Клиенты, реализуют «тонкие» интерфейсы с методами, необходимыми в их работе. При выполнении этого принципа на клиентов не будет оказываться влияние как в случае, если бы интерфейс был «толстым», и произошло изменение методов, которые клиенты не используют.

Советом по соблюдению данного принципа является: не бойтесь и не ленитесь создавать тонкие Интерфейсы.

Dependency Inversion Principle.

Если кратко, то Принцип Инверсии Зависимостей гласит: Зависимости должны строиться относительно абстракций, а не деталей.

Если развернуто, то принцип означает:

  • Модули верхнего уровня не должны зависеть от модулей нижнего уровня.
  • Все зависимости внутри системы строятся на основе абстракций.
  • Все модули должны зависеть от абстракций.
  • Абстракции же не должны зависеть от деталей конкретных реализаций.
  • А вот детали должны зависеть от абстракций.

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

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

Здесь в качестве примеров можно рассмотреть:

  • Зависмость от конкретной БД и ее механизмов работы это несоблюдение принципа.
  • Есть механизм отправки уведомлений и он зависит от траснпорта Email это несоблюдение принципа, ведь транспортов может быть гораздо больше: slack, tg и т.д.

Резюмируем:

Конечная цель принципов SOLID : это проектирование модулей, как кирпичиков будущего каркаса программы, легко масштабируемых и поддерживаемых. И если вспомнить, что дядя Боб это большой специалист, почти с пятидесятилетним опытом, который застал развитие ИТ от перфокарт до микропроцессоров, то этот специалист плохого точно не посоветует.

Если Вы когда либо слышали, что в работе программиста только 50% времени уходит на непосредственное написание кода, то да, хорошая архитектура часто требует большого времени на обдумывание будущих сущностей, их функционали и ответсвенности.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *