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

Твердые принципы

ТВЕРДЫЙ. представляет собой набор из 5 принципов, объединенных вместе и названных Робертом Мартином.

  • Принцип единой ответственности
  • Принцип открытости закрыт
  • Принцип замены Лискова
  • Принцип разделения интерфейса
  • Принцип инверсии зависимостей

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

На SOLID есть много статей и видео, но, на мой взгляд, наиболее эффективный способ обучения - это объединить их с оригинальными формулировками и примерами из книг «Чистый код» и «Чистая архитектура» »Р. Мартина.

Сначала попробуем лучше понять SRP!

SRP - Тайна «Ответственности» и разложение

"Одинокий! Обязанность! Принцип! »- звучит довольно декларативно, не правда ли?

Когда на собеседовании вас просят рассказать об этом принципе, первое, что, вероятно, приходит в голову, это что-то, прямо связанное с названием принципа:

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

Сам Р. Мартин пишет в «Чистом коде», что SRP - это наиболее часто неправильно понимаемый принцип. Для меня главным препятствием к пониманию этого принципа было абстрактное слово «Ответственность».

Действительно, что такое «ответственность»?

Если немного отклониться в сторону абсурдной логики, окажется, что, например, игра, написанная в одном классе, несет ровно одну ответственность - она ​​запускает игру!

Очевидно, что никому не пришло бы в голову применить такой пример на практике (хотя, конечно, бывают случаи), потому что SRP в первую очередь говорит о декомпозиции.

Но каков порог этого разложения?

Стоит ли при создании калькулятора описывать его 100 классами?

Или вот более конкретный, но не менее странный пример: следует ли мне создать отдельный класс для вывода на консоль, поскольку цель тега, с которым будет выводиться сообщение, и текст сообщения - разные «обязанности»?

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

В упрощенном виде это может даже звучать так:

«Разлагайтесь, пока не почувствуете, что это только усложняет ситуацию!»

К счастью, формулировка SRP Р. Мартина совершенно иная.
Более того, в нем вообще нет слова «ответственность»!

«У класса должна быть одна и только одна причина для изменения» © R. Мартин.

Вместо «ответственности» мы получаем «причины для перемен»!

А теперь давайте определим источники изменений.

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

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

Р. Мартин называет таких людей «актерами» и пишет, что SRP можно переформулировать так:

«Класс должен отвечать только за одного актера». © Р. Мартин.

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

Также обратите внимание на формулировку «одна и только одна причина».

SRP сообщает нам не только о том, что он намеревается сократить количество источников изменений, но и о том, что изменение логики по той же причине должно быть объединено.

Резюме

Таким образом, SRP не просто устанавливает «курс декомпозиции», но декларирует правило группировки сущностей в коде:

То, что меняется по обычным причинам, должно быть объединено, а то, что изменяется по разным причинам, должно быть разделено.

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