ru:https://highload.today/blogs/what-is-single-responsibility-principle/ ua:https://highload.today/uk/blogs/what-is-single-responsibility-principle/
logo
Основы      23/12/2021

Принцип SOLID, который все понимают неправильно: что такое единая ответственность в разработке

Николай Коваленко BLOG

Backend Developer в Ronis Business Tools

Если искать в интернете определение принципа единой ответственности SOLID (SPR: Single Responsibility Principle), можно наткнуться на множество статей, которые почему-то описывают принцип единой обязанности (на английском он тоже звучит как Single Responsibility Principle), называя его принципом SOLID, которым он не является.

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

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

Проблема терминологии принципа единой ответственности

В своей книге «Чистый код. Создание, анализ и рефакторинг» Роберт Мартин упоминает принцип единой ответственности (Single Responsibility Principle (SRP)).

Роберт Мартин «Чистый код. Создание, анализ и рефакторинг»

Роберт Мартин «Чистый код. Создание, анализ и рефакторинг»

В первой главе присутствуют слова создателя С++ Берна Страуступа по поводу того, что такое чистый код:

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

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

Более подробно Роберт Мартин останавливается на Single Responsibility Principle (в русском переводе почему-то «принципе единой обязанности») в своей книге «Принципы, паттерны и методики гибкой разработки на C#».

В книге этот принцип описан так:

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

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

Онлайн-курс "Проджект-менеджер в ІТ" від Laba.
Навчіться запускати, контролювати й успішно реалізовувати ІТ-проєкти. Пройти весь шлях проєктного управління на реальному кейсі вам допоможе PMD із 19-річним досвідом в ІТ.
Детальніше про курс

Роберт Мартин в русском переводе пишет, что в контексте принципа Single Responsibility Principle (SRP) мы будем называть обязанностью причину изменения.

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

Роберт Мартин «Чистая архитектура. Искусство разработки программного обеспечения»

Роберт Мартин «Чистая архитектура. Искусство разработки программного обеспечения»

В книге «Чистая архитектура. Искусство разработки программного обеспечения» Роберт Мартин в третьей главе, которая называется «Принципы дизайна», пишет следующее:

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

SRP: Single Responsibility Principle — принцип единой ответственности является следствием закона Конвея, который формулируется следующим образом: лучшей является такая структура программной системы, которая формируется в основном под влиянием социальной структуры организации, использующей эту систему, поэтому каждый программный модуль имеет одну и только одну причину для изменения (ответственность)».

Сам Роберт Мартин указывает на то, что из всех принципов SOLID принцип единой ответственности (Single Responsibility Principle) является наиболее трудно понимаемым. И допускает, что это, вероятнее всего, обусловлено выбором названия, недостаточно точно соответствующего сути принципа. Услышав это название, многие программисты решают, что каждый модуль должен отвечать за что-то одно.

Такой принцип действительно существует. Он гласит:

«Функция должна делать что-то одно и только одно». 

На русском этот принцип скорее всего правильно называть принципом единой обязанности, что на английском звучит как Single Responsibility Principle, и обычно вводит всех в заблуждение. Этот принцип используется для деления функций на более мелкие на более низком уровне. Но он не является одним из принципов SOLID, сформулированных Робертом Мартином, и тем более не является принципом единой ответственности SOLID.

Онлайн-курс "Створення електронної музики" від Skvot.
Практичний курс про те, як знайти власний стиль та написати й зарелізити свій перший трек.
Програма курсу і реєстрація

Традиционно принцип единой ответственности описывается так:

«Модуль должен иметь одну и только одну причину для изменения».

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

«Модуль должен отвечать за требования одного и только одного стейкхолдера бизнес-требований заказчика». 

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

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

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

Зачем нужен принцип единой ответственности

Зачем же придерживаться принципа единой ответственности и почему принцип единой обязанности и принцип единой ответственности — это все же разные принципы?

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

Воркшоп "PR + AI: Рисерч, Креатив, Контент" від Skvot.
Навчіться адаптувати потенціал АІ під задачі піарника. Корисні тулзи, яким можна делегувати рутину, генерувати свіжі ідеї для контенту і піар-стратегій.
Дізнатись більше

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

Рассмотрим пример, предлагаемый Робертом Мартином в книге «Чистая архитектура. Искусство разработки программного обеспечения», но в разрезе сбора бизнес-требований и более упрощенный, чем оригинал, приведенный в книге.

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

  • генеральный директор (ему нужно контролировать показатели продаж);
  • бухгалтер (ему нужно подавать отчет о продажах в налоговую);
  • отдел кадров (ему нужно контролировать выполнение плана сотрудниками).

После сбора требований со всех стейкхолдеров бизнеса оказалось, что всем троим подходит один вариант отчета. В итоге принимается решение сделать один компонент, реализующий один вариант отчета.

Кажется, всем троим подходит один вариант отчета. Что же делать?

Кажется, всем троим подходит один вариант отчета. Что же делать?

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

В чем же проблема с генератором отчета, который удовлетворяет требования сразу трех стейкхолжеров бизнеса? На начальных этапах разработки проблема может казаться неочевидной, поскольку кажется, что у такого решения есть ряд преимуществ. А именно: простая структура, отсутствие дублирования, простота внесения изменений.

Онлайн-курс "Маркетолог" від Laba.
Пройдіть повний шлях розробки маркетингових стратегій на практиці та з фідбеком від CEO бренд-маркетингової агенції.
Програма курсу і реєстрація

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

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

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

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

Итоги

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

Читайте также: Не будьте STUPID: разработчик назвал 10 принципов, которые отличают хорошего программиста от плохого

Это текст из личного блога, опубликованный с разрешения автора.

If you have found a spelling error, please, notify us by selecting that text and pressing Ctrl+Enter.

Онлайн-курс "Продуктова аналітика" від Laba.
Станьте універсальним аналітиком, опанувавши 20+ інструментів для роботи з будь-яким продуктом.
Дізнатись більше про курс

Этот материал – не редакционный, это – личное мнение его автора. Редакция может не разделять это мнение.

Ваша жалоба отправлена модератору

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: