Single responsibility principle, он же принцип единой ответственности,
он же принцип единой изменчивости — крайне скользкий для понимания парень и столь нервозный вопрос на собеседовании программиста.  Первое серьезное знакомство с этим принципом состоялось для меня в начале первого курса, когда молодых и зеленых нас вывезли в лес, чтобы сделать из личинок студентов — студентов настоящих. В лесу нас разделили на группы по 8-9 человек в каждой и устроили соревнование — какая группа быстрее выпьет бутылку водки при условии, что первый человек из группы наливает водку в стакан, второй выпивает, а третий закусывает. Выполнивший свою операцию юнит встает в конец очереди группы.  Случай, когда размер очереди был кратен трем, и являлся хорошей реализацией SRP. Официальное определение принципа единой ответственности (SRP) говорит о том, что у каждого объекта есть своя ответственность и причина существования и эта ответственность у него только одна. Рассмотрим объект "Выпивоха" (Tippler).
Для выполнения принципа SRP разделим обязанности на троих:  Каждый из участников процесса ответственен за одну компоненту процесса, то есть имеет одну атомарную ответственность — выпить, налить или закусить.  Выпивоха же, в свою очередь является фасадом для данных операций: Человек-программист пишет код для человека-обезьяны, а человек-обезьяна невнимателен, глуп и вечно куда-то спешит. Он может удержать и понять около 3 — 7 термов в один момент времени.
В случае выпивохи этих термов три. Однако если мы напишем код одной простыней, то в нем появятся руки, стаканы, мордобои и бесконечные споры о политике. И все это будет в теле одного метода. Уверен — вы видели такой код в своей практике. Не самое гуманное испытание для психики. С другой стороны, человек-обезьяна заточен на моделирование объектов реального мира в своей голове. В своем воображении он может их сталкивать, собирать из них новые объекты и точно так же разбирать. Представьте себе старую модель машины. Вы можете в воображении открыть дверь, открутить обшивку двери и увидеть там механизмы стеклоподъемников, внутри которых будут шестерни. Но вы не можете увидеть все компоненты машины одновременно, в одном "листинге". По крайней мере "человек-обезьяна" не может. Поэтому человеки-программисты декомпозируют сложные механизмы на набор менее сложных и работающих элементов. Однако, декомпозировать можно по-разному: во многих старых машинах — воздуховод выходит в дверь, а в современных — сбой электроники замка не дает запуститься двигателю, что доставляет при ремонте. Так вот, SRP — это принцип, объясняющий КАК декомпозировать, то есть где провести линию разделения.  Он говорит, что декомпозировать надо по принципу разделения "ответственности", то есть по задачам тех или иных объектов. Вернемся к выпивохе и плюсам, которые получает человек-обезьянка при декомпозировании:  И, конечно же, минусы:  Позвольте господа! Класс выпивохи же также выполняет единую ответственность — он выпивает! И вообще, слово "ответственность" — понятие крайне размытое. Кто-то ответственен за судьбу человечества, а кто-то ответственен за поднимание опрокинутых на полюсе пингвинов. Рассмотрим две реализации выпивохи. Первая, указанная выше, содержит в себе три класса — налить, выпить и закусить. Вторая, написана через методологию "Вперед и только вперед" и содержит всю логику в методе Act: Оба этих класса, с точки зрения стороннего наблюдателя, выглядят абсолютно одинаково и выполняют единую ответственность "выпить".  Конфуз! Тогда мы лезем в интернет и узнаем другое определение SRP — Принцип единой изменчивости. Это определение гласит, что "У модуля есть один и только один повод для изменения". То есть "Ответственность — это повод для изменения".  Теперь все встает на свои места. Отдельно можно изменять процедуры наливания, выпивания и закусывания, а в самом выпивохе мы можем поменять только последовательность и состав операций, например, переместив закуску перед выпиванием или добавив чтение тоста. В подходе "Вперед и только вперед", все что можно поменять — меняется только в методе Act. Это может быть читабельно и эффективно в случае, когда логики немного и она редко меняется, но зачастую это кончается ужасными методами по 500 строк в каждом, с количеством if -ов большим, чем требуется для вступления России в нато.  Выпивохи часто не понимают, почему они проснулись в чужой квартире, или где их мобильный. Пришло время добавить подробную логировку. Начнем логировку с процесса наливания: Инкапсулировав ее в PourOperation, мы поступили мудро с точки зрения ответственности и инкапсуляции, но вот с принципом изменчивости у нас теперь конфуз. Помимо самой операции, которая может меняться, изменчивой становится и сама логировка. Придется разделять и делать специальный логировщик для операции наливания: Дотошный читатель заметит, что LogAfter, LogBefore и OnError также могут меняться по отдельности, и по аналогии с предыдущими действиями создаст три класса: PourLoggerBefore, PourLoggerAfter и PourErrorLogger. А вспомнив, что операций для выпивохи три — получаем девять классов логирования. В итоге весь выпивоха состоит из 14 (!!!) классов. Гипербола? Едва ли! Человек-обезьянка с декомпозиционной гранатой раздробит “наливателя” на графин, стакан, операторы наливания, сервис подачи воды, физическую модель столкновения молекул и следующий квартал будет пытаться распутать зависимости без глобальных переменных. И поверьте — он не остановится. Именно на этом моменте многие приходят к выводу, что SRP — это сказки из розовых королевств, и уходят вить лапшу... … так и не узнав о существовании третьего определения Srp:  "Схожие для изменения вещи должны храниться в одном месте". или “То, что изменяется вместе, должно храниться в одном месте” То есть, если мы меняем логировку операции, то мы должны это менять в одном месте. Это очень важный момент — так как все объяснения SRP, которые были выше, говорили о том, что надо дробить типы, пока они дробятся, то есть накладывало "ограничение сверху" на размер объекта, а теперь мы говорим уже и об "ограничении снизу". Иными словами, SRP не только требует "дробить пока дробится", но и не перестараться — "не раздробить сцепленные вещи". Не усложнять без надобности. Это великая битва бритвы Оккама с человеком-обезьяной! Теперь выпивохе должно стать полегче. Помимо того, что не надо дробить логировщик IPourLogger на три класса, мы также можем объединить все логировщики в один тип: И если нам добавится четвертый тип операции, то для нее уже готова логировка. А код самих операций чист и избавлен от инфраструктурного шума. В результате у нас 5 классов для решения задачи выпивания: Каждый из них отвечает строго за одну функциональность, имеет одну причину для изменения. Все схожие для изменения правила лежат рядом.  В рамках разработки протокола передачи данных нужно сделать сериализацию и десериализацию некоторого типа "User" в строку. Можно подумать, что сериализацию и десериализацию нужно делать в отдельных классах: Так как у каждого из них есть своя ответственность и один повод для изменения. Но повод для изменения у них общий — "изменение формата сериализации данных".
И при изменение этого формата всегда будут меняться и сериализация и десериализация вместе. Согласно принципу локализации изменений мы должны объединить их в один класс: Это избавиляет нас от излишней сложности, и необходимости помнить, что при каждом изменении сериализатора, нужно помнить и о десериализаторе. Необходимо посчитать годовую выручку компании и сохранить ее в файл C:\results.txt. Быстро решаем это при помощи одного метода: Уже из определения задачи видно, что есть две подзадачи -"Посчитать выручку" и "Сохранить выручку". Каждая из них имеет по одному поводу для изменений — "изменене методики подсчета" и "изменение формата сохранения". Эти изменения никак не пересекаются. Так же, мы не можем односложно ответить на вопрос — "что делает метод SaveGain?". Этот метод И считает выручку И сохраняет результаты. Потому нужно разделить этот метод на два: Плюсы: Однажды мы писали сервис автоматической регистрации b2b клиента. И появился GOD -метод на 200 строк подобного содержимого: В этом списке было еще около 10-ти бизнес операций с жуткой связанностью. Объект счета нужен был почти всем. Идентификатор точки и имя клиента нужны были в половине вызовов. После часового рефакторинга, мы смогли отделить инфраструктурный код и некоторые нюансы работы с аккаунтом в отдельные методы/классы. God метод полегчал, но осталось 100 строк кода, которые распутываться никак не хотели.  Лишь через несколько дней пришло понимание, что суть этого "полегчавшего" метода — и есть бизнес алгоритм. И что изначальное описание ТЗ было довольно сложным. И именно попытка разбить на куски этот метод будет нарушением SRP, а не наоборот.  Пришло время оставить в покое нашего выпивоху. Вытрите слезы — мы обязательно вернемся к нему как-нибудь. А сейчас формализуем знания из этой статьи.  Мне не встречались достаточные критерии выполнения SRP. Но есть необходимые условия: 1) Задайте себе вопрос — что делает этот класс/метод/модуль/сервис. вы должны ответить на него простым определением. ( благодарю Brightori ) Впрочем иногда подобрать простое определение очень сложно  2) Фикс некоторого бага или добавление новой фичи затрагивает минимальное количество файлов/классов. В идеале — один.  Так как ответственность (за фичу или баг) инкапсулированна в одном файле/классе, то вы точно знаете где искать и что править. Например: фича изменения вывода логировки операций потребует изменить только логировщик. Бегать по всему остальному коду не требуется.  Другой пример — добавление нового UI-контрола, схожего с предыдущими. Если это заставляет вас добавить 10 разных сущностей и 15 разных конвертеров — кажется, вы “передробили”. 3)Если несколько разработчиков работают над разными фичами вашего проекта, то вероятность мердж -конфликта, то есть вероятность того, что один и тот же файл/класс будет изменен у нескольких разработчиков одновременно — минимальна. Если при добавлении новой операции "Вылить водку под стол" вам нужно затронуть логировщик, операцию выпивания и выливания — то похоже, что ответственности разделены криво. Безусловно, это не всегда возможно, но нужно стараться снизить этот показатель.  4) При уточняющем вопросе про бизнес логику (от разработчика или менеджера) вы лезете строго в один класс/файл и получаете информацию только от туда. Фичи, правила или алгоритмы компактно написаны каждая в одном месте, а не разбросаны флагами по всему пространству кода. 5) Нейминг понятен. Наш класс или метод ответственен за что-то одно, и ответственность отражена в его названии AllManagersManagerService — скорее всего, God-класс
LocalPayment — вероятно, нет  В начале проектирования, человек-обезьянка не знает и не чувствует всех тонкостей решаемой задачи и может дать маху. Ошибаться можно по разному: Важно запомнить правило: "ошибаться лучше в большую сторону", или "не уверены — не дробите". Если, например, ваш класс собирает в себе две ответственности — то он по прежнему понятен и его можно распилить на два с минимальным изменением клиентского кода. Собирать же из осколков стекла стакан, как правило, сложнее из-за размазанного по нескольким файлам контекста и отсутствия необходимых зависимостей в клиентском коде.  Сфера применения SRP не ограничивается ООП и SOLID. Он применим к методам, функциям, классам, модулям, микросервисам и сервисам. Он применим как к “фигакс-фигакс-и-в-прод”, так и к “рокет-сайнс” разработке, везде делая мир чуточку лучше. Если задуматься, то это едва ли не фундаментальный принцип всей инженерии. Машиностроение, системы управления, да и вообще все сложные системы — строятся из компонентов, и “недодробление” лишает конструкторов гибкости, “передробление” — эффективности, а неверные границы — разума и душевного спокойствия.  SRP не выдуман природой и не является частью точной науки. Он вылезает из наших с вами биологических и психологических ограничений.Это всего лишь способ контролировать и развивать сложные системы при помощи мозга человека-обезьяны. Он рассказывает нам, как декомпозировать систему. Изначальная формулировка требовала изрядного навыка телепатии, но надеюсь, эта статья слегка развеяла дымовую завесу.