Srp что это такое
Srp что это такое
Secure Remote Password Protocol (SRPP) — протокол парольной аутентификации, устойчивый к прослушиванию и MITM-атаке и не требующий третьей доверенной стороны. SRP содержит некоторые элементы из других протоколов обмена ключами и идентификации, при этом вносит небольшие усовершенствования и уточнения. Протокол сохраняет стойкость и эффективность протоколов класса Encrypted key exchange, при этом избавляясь от некоторых их недостатков.
Содержание
Обзор
Протокол SRP позволяет пользователю идентифицировать себя на сервере, при этом не передавая своего пароля, то есть подтвердить тот факт, что он знает свой пароль, и только этот факт. Он имеет ряд полезных качеств:
SRP эффективно реализует Доказательство с нулевым разглашением между пользователем и сервером, хранящим информацию о его пароле. При прослушивании за один раз злоумышленником может быть проверена только одна версия пароля, начиная с версии 6 данного протокола. Данный протокол имеет много ревизий, на данный момент последняя ревизия — 6a.
В результате работы данного протокола обе стороны получают длинный секретный ключ, проверяемый на соответствие между сторонами после получения. В случаях, когда помимо аутентификации необходимо шифрование данных, SRP предоставляет более надёжные, чем SSH, и более быстрые, чем Deffie-Hellman, средства для достижения этой цели. Протокол SRP версии 3 описывается в RFC 2945. SRP версии 6 также используется для аутентификации в SSL/TLS и других стандартах, таких как EAP и SAML, и в данный момент стандартизуется IEEE P1363 и ISO/IEC 11770-4.
Принцип работы
Введем обозначения, необходимые для рассуждения:
Понятия пароля и верификатора соответствуют общепринятым понятиям секретного и открытого ключей, с двумя оговорками: пароль, как правило, меньше секретного ключа, так как его помнит пользователь, а память у него небольшого размера; в свою очередь, верификатор по математическим свойствам схож с открытым ключом, так как он легко получается из пароля, а обратная операция является вычислительно неразрешимой. Однако вместо того, чтобы быть общеизвестным, верификатор хранится сервером в тайне. Способ аутентификации, который предполагает хранение сервером верификатора, но не пароля, называется основанным на верификации(verifier-based).
Из исходных параметров вычисляются A,B (см. ниже). Сервер хранит пароли, используя следующую формулу:
После этого сервер хранит пару (I, s, v) в своей базе данных. Аутентификация происходит по следующей схеме:
На стороне клиента:
На стороне сервера:
Теперь обе стороны имеют общий секретный ключ K. Для завершения аутентификации, им необходимо свериться, что их ключи совпадают. Один из возможных способов:
Сравнение с некоторыми типами алгоритмов
Речь пойдет о простых типах алгоритмов аутентификации и их уязвимостях в сравнении с данным, что покажет преимущества SRP.
Самый простой способ аутентификации — передача незашифрованного пароля от клиента к серверу, после чего сервер сравнивает полученный пароль или его хеш с элементом базы данных. Очевидный недостаток — уязвимость к прослушиванию.
Модифицируя первый алгоритм, получаем аутентификацию с запросом и подтверждением (challenge-responce), где обмен происходит так:
после этого клиент вычисляет хеш от трех величин: r, c, password, и посылает его обратно. Данный метод уязвим к перебору, так как злоумышленник, имея r, c, hash, может подобрать пароль клиента.
Анализируя первые два алгоритма, можно прийти к третьему, который защищен и от перебора по словарю. Семейство таких протоколов называется Encrypted key exchange (EKE). Суть этого алгоритма в том, что обе стороны генерируют свои открытые ключи для асимметричного шифрования, и обмениваются или с помощью симметричного алгоритма, используя известный обоим пароль пользователя как ключ. Данное семейство протоколов имеет широкое распространение, с разными реализованными модификациями, добавляющими некоторые свойства:
Для того, чтобы избежать всех указанных уязвимостей и получить алгоритм с хорошей скоростью работы, была разработана концепция AKE (Asymmetric key exchange), отличающаяся от предыдущих прежде всего тем, что при передаче данных отсутствует всякое шифрование, которое избавляет систему от ненужных затрат вычислительной мощности и возможных уязвимостей определенных алгоритмов шифрования. Одной из реализаций AKE и является SRP.
Software Restriction Policies
Технический справочник по политикам ограниченного использования программ (Windows Server 2003)
Справка по политикам ограниченного использования программ (Windows Server 2003)
Диагностика политик ограниченного использования программ (Windows Server 2003)
Угрозы и противодействия для политик ограниченного использования программ (Windows Server 2008 R2)
Область применения: Windows Server 2022, Windows Server 2019, Windows Server 2016, Windows Server 2012 R2, Windows Server 2012
в этой статье для ит-специалистов описываются политики ограниченного использования программ (srp) в Windows Server 2012 и Windows 8, а также ссылки на технические сведения о наборе исправлений безопасности, начиная с Windows Server 2003.
Описание политик ограниченного использования программ
Политики ограниченного использования программ — это основанная на групповых политиках функция, которая выявляет программы, работающие на компьютерах в домене, и управляет возможностью выполнения этих программ. Политики ограниченного использования программ являются частью стратегии управления и безопасности Майкрософт, позволяющей предприятиям повышать надежность, целостность и управляемость их компьютеров.
Кроме того, данные политики помогают создать конфигурацию с расширенными ограничениями для компьютеров, на которых разрешается запуск только определенных приложений. Политики ограниченного использования программ интегрируются со службой Microsoft Active Directory и групповой политикой. Политики можно создавать на изолированных компьютерах. Они являются политиками доверия, то есть представляют собой правила, устанавливаемые администратором, чтобы ограничить выполнение сценариев и другого кода, не имеющего полного доверия.
Данные политики ограниченного использования программ определяются как расширение редактора локальных групповых политик или оснастки Microsoft Management Console (MMC) «Локальные политики безопасности».
Более подробные сведения о политике ограниченного использования программ см. в разделе Технический обзор политик ограниченного использования программ.
Практическое применение
Администраторы могут использовать политики ограниченного использования программ для решения следующих задач:
определить доверенный код;
разработать гибкую групповую политику для регулирования работы сценариев, исполняемых файлов и элементов ActiveX.
Политики ограниченного использования программ применяются операционной системой и приложениями (например, для создания сценариев), которые им соответствуют.
В частности, администраторы могут использовать политики ограниченного использования программ в следующих целях:
определить программное обеспечение (исполняемые файлы), которое может выполняться на клиентах;
запретить пользователям выполнять определенные программы на компьютерах с общим доступом;
определить, кто может добавлять доверенных издателей на клиентах;
установить область действия политик ограниченного использования программ (указать, будут ли политики применяться для всех пользователей или только для группы пользователей на клиентах);
запретить работу исполняемых файлов на локальном компьютере, сайте, в подразделении или домене. Это уместно в тех случаях, когда политики ограниченного использования программ не применяются для решения потенциальных проблем со злоумышленниками.
Новые и измененные функции
Функциональные изменения в политиках ограниченного использования программ отсутствуют.
Удаленные или устаревшие функциональные возможности
Удаленные или устаревшие функции в политиках ограниченного использования программ отсутствуют.
Требования к программному обеспечению
Расширение редактора локальных групповых политик для политик ограниченного использования программ доступно через консоль управления (MMC).
Для создания и поддержки политик ограниченного использования программ на локальном компьютере требуются следующие компоненты:
Редактор локальных групповых политик
Authenticode и WinVerifyTrust
Если планируются вызовы для развертывания этих политик в домене, к вышеупомянутому списку потребуется добавить следующие компоненты:
Доменные службы Active Directory
Сведения о диспетчере сервера
Политики ограниченного использования программ представляют собой расширение редактора локальных групповых политик и не устанавливаются с помощью пункта «Добавить роли и компоненты» диспетчера серверов.
См. также
В следующей таблице содержатся ссылки на соответствующие ресурсы, необходимые для понимания и применения политик ограниченного использования программ.
Многоликий принцип единственности ответственности
Кажется, любой «солидный» программист знает что такое SOLID вообще и принцип единственности ответственности (SRP) в частности.
Спойлер, если вдруг не знаете
Single Responsibility Principle: A module should have one, and only one, reason to change.
Open/Closed Principle:: A software artifact should be open for extension but closed for modification.
Liskov Substitution Principle:: What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T
Interface Segregation Principle:: Clients should not be forced to depend upon interfaces that they do not use.
Dependency Inversion Principle::
High level modules should not depend upon low level modules. both should depend upon abstractions.
Abstractions should not depend upon details. details should depend upon abstractions.
Когда речь заходит об SRP, я всегда уточняю, что именно имеет ввиду мой собеседник. Потому что у SRP существует как минимум пять разных формулировок и три интерпретации. И я не думаю, что подобная эмм… штуковина является хорошим руководством по разработке ПО.
Формулировки SRP
Для начала приведу неверную, но самую популярную формулировку:
Класс должен делать одну вещь
Которой вторит и русская википедия:
Для каждого класса должно быть определено единственное назначение. Все ресурсы, необходимые для его осуществления, должны быть инкапсулированы в этот класс и подчинены только этой задаче.
Хотя английская версия той же статьи приводит одну из формулировок Мартина.
It is too easy for programmers to hear the name and then assume that it means that every module should do just one thing.
Make no mistake, there is a principle like that. […] But it is not one of the SOLID principles — it is not the SRP.
— Robert C. Martin, Clean Architecture
Сам Мартин формулирует SRP тремя разными способами:
Формулировка 2003 года
The Single Responsibility Principle (SRP) states that a class or module should have one, and only one, reason to change
— Robert C. Martin, Agile software development Principles Patterns and Practices
Формулировка 2014 года
Gather together the things that change for the same reasons. Separate those things that change for different reasons.
— Robert C. Martin, The Single Responsibility Principle
Формулировка 2018 года
A module should be responsible to one, and only one, actor
— Robert C. Martin, Clean Architecture
Чтобы понять, что у них общего, мне потребовалось по три прочтения всех публикаций Мартина об SRP. Вы же сэкономите день-два жизни и получите ответ за пятнадцать минут, если дочитаете пост до конца.
Для начала рассмотрим как анкл Боб объясняет SRP последние двадцать лет.
Объяснения SRP
Agile software development Principles Patterns and Practices, 2003
Впервые SRP появился в Agile software development Principles Patterns and Practices. В этой книге Мартин пояснял его на примере разделения кода различных функций программы:
Consider the bowling game from Chapter 6. For most of its development the Game class was handling two separate responsibilities. It was keeping track of the current frame, and it was calculating the score. In the end, RCM and RSK separated these two responsibilities into two classes. The Game kept the responsibility to keep track of frames, and the Scorer got the responsibility to calculate the score. (see page 85.)
— Robert C. Martin, Agile software development Principles Patterns and Practices
Clean Code, 2008
Пояснять SRP на примере разделения кода по функциям программы Мартин продолжает и в Clean Code:
The seemingly small SuperDashboard class in Listing 10-2 has two reasons to change. First, it tracks version information that would seemingly need to be updated every time the software gets shipped. Second, it manages Java Swing components (it is a derivative of JFrame, the Swing representation of a top-level GUI window)
— Robert C. Martin, Clean Code
The Clean Coder, 2011
Затем в The Clean Coder анкл Боб иллюстрирует SRP уже примером разделения аспектов реализации (пользовательского интерфейса и бизнес-правил):
There is a design principle called the Single Responsibility Principle (SRP). This principle states that you should separate those things that change for different reasons, and group together those things that change for the same reasons. GUIs are no exception.
The layout, format, and workflow of the GUI will change for aesthetic and efficiency reasons, but the underlying capability of the GUI will remain the same.
Design experts have been telling us for decades to separate our GUIs from our business rules.
— Robert C. Martin, The Clean Coder
The Single Responsibility Principle, 2014
В следующей публикации о SRP анкл Боб уже напрямую использует термин «разделение аспектов [реализации]» (separation of concerns):
Two years later, Edsger Dijkstra wrote another classic paper entitled On the role of scientific thought. in which he introduced the term: The Separation of Concerns. [. ] This is the reason we do not put SQL in JSPs. This is the reason we do not generate HTML in the modules that compute results. This is the reason that business rules should not know the database schema. This is the reason we separate concerns.
— Robert C. Martin, https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html
Но здесь же, Мартин впервые объясняет SRP совсем в другом ключе:
And this gets to the crux of the Single Responsibility Principle. This principle is about people.
When you write a software module, you want to make sure that when changes are requested, those changes can only originate from a single person, or rather, a single tightly coupled group of people representing a single narrowly defined business function.
— Robert C. Martin, https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html
Здесь уже речь идёт о разделении кода по людям.
Clean Architecture, 2018
В окончательной же форме это объяснение появляется ещё через четыре года в Clean Architecture:
A module should be responsible to one, and only one, actor
— Robert C. Martin, Clean Architecture
Действующим лицом (actor) в этом случае является группа стейкходеров (людей так или иначе причастных к программе и её созданию) с одинаковыми потребностями.
Шестая формулировка SRP
Мне кажется более понятной шестая (уже моя) формулировка SRP:
Модуль должен отвечать за реализацию требований одного стейкхолдера.
— Алексей Жидков, Многоликий принцип единственности ответсвенности
Ни эта, ни любая другая формулировка SRP не даёт программистам практического руководства к действию в каждодневной работе. Может быть, будет полезнее разбить SRP на несколько практических рекомендаций? Например:
формируйте направленный ациклический граф зависимостей между модулями;
разделяйте ввод-вывод (в том числе GUI) и бизнес-правила;
разделяйте код реализующий разные функции системы;
пишите тесты. В тестах мокайте только внешние системы, а system under test создавайте «руками» (а не с помощью DI-контейнера).
Эти рекомендации не нуждаются большом предварительном проектировании с определением стейкхолдеров и требований. И следование им можно контролировать механически.
Применение таких рекомендаций в каждодневной работе доступно намного более широкому кругу программистов и также даст поддерживаемую и стабильную систему на выходе.
На суку висит мочало, начинаем всё сначала
SOLID relevance, 2020
Постоянное изменение формулировок и интерпретаций SRP можно было бы объяснить эволюцией понимания SRP самим Мартином. Сначала для него SRP был о разделении по функциям программы. Потом он понял, что по аспектам реализации код тоже необходимо разделять. Наконец, анкл Боб обобщил их через разделение по требованиям различных действующих лиц.
Это было отличное объяснение развития событий. Пока Мартин не написал свой последний пост на тему SRP. В нём он снова откатился к разделению только по аспектам:
It is hard to imagine that this principle is not relevant in software. We do not mix business rules with GUI code. We do not mix SQL queries with communications protocols.
— Robert C. Martin, https://blog.cleancoder.com/uncle-bob/2020/10/18/Solid-Relevance.html
Если посмотреть на историю объяснений SRP с высоты «птичьего полёта», то становится видно что анкл Боб постоянно скачет между этими критериями декомпозиции кода:
История интерпретаций SRP
Agile software development Principles Patterns and Practices
Функциональность и намёк на действующее лицо*
The Single Responsibility Principle
Функциональность, аспект реализации и действующее лицо
Функциональность и действующее лицо, в меньшей степени аспект реализации**
* В Agile software development Principles Patterns and Practices был и другой пример в главе про SRP.
Two different applications use the Rectangle class. One application does computational geometry. It uses Rectangle to help it with the mathematics of geometric shapes. It never draws the rectangle on the screen. The other application is graphical in nature. It may also do some computational geometry, but it definitely draws the rectangle on the screen.
— Robert C. Martin, Agile software development Principles Patterns and Practices
Глядя на этот пример (из 2021 года) можно прийти к выводу, что у разных приложений будут разные пользователи (один из видов действующих лиц) и методы draw и area реализуют требования разных действующих лиц.
** В Clean Architecture разделение по аспекту реализации тоже присутствует (метод save, определяемый CTO). Но в этой книге Мартин уже явно не проговаривает необходимость разделения по аспектам. В сочетании с нетипичным значением слова actor, это приводит к тому, что такое объяснение можно проинтерпретировать как декомпозицию только на основе пользователей программы. Это может стать четвёртой интерпретацией SRP, но в жизни я её пока не встречал.
Можно разделять SQL и JSP и всё ещё использовать один и тот же код в разных функциях и ломать функции одних пользователей при модификации функций других пользователей.
И наоборот, можно завести по микросервису для каждого пользователя или функции системы и собрать в один метод и парсинг json-а, и бизнес-правила, и выполнение SQL-запросов. В итоге получить хрупкий код, который трудно поддерживать.
Можем ли мы полагаться на принцип, формулировка и интерпретация которого меняется каждые три года? Я думаю нет.
Нам нужны новые принципы
В итоге мы приходим к тому, что:
вообще, не очень понятно, что такое SRP. Разные разработчики понимают под этой аббревиатурой разные принципы дизайна. Даже сам Мартин постоянно по-разному формулирует и иллюстрирует SRP;
то, что мне кажется Единственно Верной Версией SRP, невозможно использовать на практике. Потому что в реальной жизни необходимую для этой версии аналитику никто не делает.
И хотя SRP является самым неоднозначным принципом SOLID-а, остальные четыре принципа тоже имеют разночтения и проблемы с применением на практике. Поэтому я не думаю, что SOLID в своём текущем виде является хорошим руководством по дизайну систем.
Single Responsibility Principle. Не такой простой, как кажется
Single responsibility principle, он же принцип единой ответственности,
он же принцип единой изменчивости — крайне скользкий для понимания парень и столь нервозный вопрос на собеседовании программиста.
Первое серьезное знакомство с этим принципом состоялось для меня в начале первого курса, когда молодых и зеленых нас вывезли в лес, чтобы сделать из личинок студентов — студентов настоящих.
В лесу нас разделили на группы по 8-9 человек в каждой и устроили соревнование — какая группа быстрее выпьет бутылку водки при условии, что первый человек из группы наливает водку в стакан, второй выпивает, а третий закусывает. Выполнивший свою операцию юнит встает в конец очереди группы.
Случай, когда размер очереди был кратен трем, и являлся хорошей реализацией SRP.
Определение 1. Единая ответственность.
Официальное определение принципа единой ответственности (SRP) говорит о том, что у каждого объекта есть своя ответственность и причина существования и эта ответственность у него только одна.
Рассмотрим объект «Выпивоха» (Tippler).
Для выполнения принципа SRP разделим обязанности на троих:
Каждый из участников процесса ответственен за одну компоненту процесса, то есть имеет одну атомарную ответственность — выпить, налить или закусить.
Выпивоха же, в свою очередь является фасадом для данных операций:
Зачем?
Человек-программист пишет код для человека-обезьяны, а человек-обезьяна невнимателен, глуп и вечно куда-то спешит. Он может удержать и понять около 3 — 7 термов в один момент времени.
В случае выпивохи этих термов три. Однако если мы напишем код одной простыней, то в нем появятся руки, стаканы, мордобои и бесконечные споры о политике. И все это будет в теле одного метода. Уверен — вы видели такой код в своей практике. Не самое гуманное испытание для психики.
С другой стороны, человек-обезьяна заточен на моделирование объектов реального мира в своей голове. В своем воображении он может их сталкивать, собирать из них новые объекты и точно так же разбирать. Представьте себе старую модель машины. Вы можете в воображении открыть дверь, открутить обшивку двери и увидеть там механизмы стеклоподъемников, внутри которых будут шестерни. Но вы не можете увидеть все компоненты машины одновременно, в одном «листинге». По крайней мере «человек-обезьяна» не может.
Поэтому человеки-программисты декомпозируют сложные механизмы на набор менее сложных и работающих элементов. Однако, декомпозировать можно по-разному: во многих старых машинах — воздуховод выходит в дверь, а в современных — сбой электроники замка не дает запуститься двигателю, что доставляет при ремонте.
Так вот, SRP — это принцип, объясняющий КАК декомпозировать, то есть где провести линию разделения.
Он говорит, что декомпозировать надо по принципу разделения «ответственности», то есть по задачам тех или иных объектов.
Вернемся к выпивохе и плюсам, которые получает человек-обезьянка при декомпозировании:
И, конечно же, минусы:
Определение 2. Единая изменчивость.
Позвольте господа! Класс выпивохи же также выполняет единую ответственность — он выпивает! И вообще, слово «ответственность» — понятие крайне размытое. Кто-то ответственен за судьбу человечества, а кто-то ответственен за поднимание опрокинутых на полюсе пингвинов.
Рассмотрим две реализации выпивохи. Первая, указанная выше, содержит в себе три класса — налить, выпить и закусить.
Вторая, написана через методологию «Вперед и только вперед» и содержит всю логику в методе Act:
Оба этих класса, с точки зрения стороннего наблюдателя, выглядят абсолютно одинаково и выполняют единую ответственность «выпить».
Тогда мы лезем в интернет и узнаем другое определение SRP — Принцип единой изменчивости.
Это определение гласит, что «У модуля есть один и только один повод для изменения«. То есть «Ответственность — это повод для изменения».
Теперь все встает на свои места. Отдельно можно изменять процедуры наливания, выпивания и закусывания, а в самом выпивохе мы можем поменять только последовательность и состав операций, например, переместив закуску перед выпиванием или добавив чтение тоста.
Определение 3. Локализация изменений.
Выпивохи часто не понимают, почему они проснулись в чужой квартире, или где их мобильный. Пришло время добавить подробную логировку.
Начнем логировку с процесса наливания:
Инкапсулировав ее в PourOperation, мы поступили мудро с точки зрения ответственности и инкапсуляции, но вот с принципом изменчивости у нас теперь конфуз. Помимо самой операции, которая может меняться, изменчивой становится и сама логировка. Придется разделять и делать специальный логировщик для операции наливания:
Дотошный читатель заметит, что LogAfter, LogBefore и OnError также могут меняться по отдельности, и по аналогии с предыдущими действиями создаст три класса: PourLoggerBefore, PourLoggerAfter и PourErrorLogger.
А вспомнив, что операций для выпивохи три — получаем девять классов логирования. В итоге весь выпивоха состоит из 14 (. ) классов.
Гипербола? Едва ли! Человек-обезьянка с декомпозиционной гранатой раздробит “наливателя” на графин, стакан, операторы наливания, сервис подачи воды, физическую модель столкновения молекул и следующий квартал будет пытаться распутать зависимости без глобальных переменных. И поверьте — он не остановится.
Именно на этом моменте многие приходят к выводу, что SRP — это сказки из розовых королевств, и уходят вить лапшу.
… так и не узнав о существовании третьего определения Srp:
«Схожие для изменения вещи должны храниться в одном месте«. или “То, что изменяется вместе, должно храниться в одном месте”
То есть, если мы меняем логировку операции, то мы должны это менять в одном месте.
Это очень важный момент — так как все объяснения SRP, которые были выше, говорили о том, что надо дробить типы, пока они дробятся, то есть накладывало «ограничение сверху» на размер объекта, а теперь мы говорим уже и об «ограничении снизу». Иными словами, SRP не только требует «дробить пока дробится», но и не перестараться — «не раздробить сцепленные вещи». Не усложнять без надобности. Это великая битва бритвы Оккама с человеком-обезьяной!
Теперь выпивохе должно стать полегче. Помимо того, что не надо дробить логировщик IPourLogger на три класса, мы также можем объединить все логировщики в один тип:
И если нам добавится четвертый тип операции, то для нее уже готова логировка. А код самих операций чист и избавлен от инфраструктурного шума.
В результате у нас 5 классов для решения задачи выпивания:
Каждый из них отвечает строго за одну функциональность, имеет одну причину для изменения. Все схожие для изменения правила лежат рядом.
Примеры из реальной жизни
В рамках разработки протокола передачи данных нужно сделать сериализацию и десериализацию некоторого типа «User» в строку.
Можно подумать, что сериализацию и десериализацию нужно делать в отдельных классах:
Так как у каждого из них есть своя ответственность и один повод для изменения.
Но повод для изменения у них общий — «изменение формата сериализации данных».
И при изменение этого формата всегда будут меняться и сериализация и десериализация вместе.
Согласно принципу локализации изменений мы должны объединить их в один класс:
Это избавиляет нас от излишней сложности, и необходимости помнить, что при каждом изменении сериализатора, нужно помнить и о десериализаторе.
Необходимо посчитать годовую выручку компании и сохранить ее в файл C:\results.txt.
Быстро решаем это при помощи одного метода:
Потому нужно разделить этот метод на два:
В этом списке было еще около 10-ти бизнес операций с жуткой связанностью. Объект счета нужен был почти всем. Идентификатор точки и имя клиента нужны были в половине вызовов.
После часового рефакторинга, мы смогли отделить инфраструктурный код и некоторые нюансы работы с аккаунтом в отдельные методы/классы. God метод полегчал, но осталось 100 строк кода, которые распутываться никак не хотели.
Лишь через несколько дней пришло понимание, что суть этого «полегчавшего» метода — и есть бизнес алгоритм. И что изначальное описание ТЗ было довольно сложным. И именно попытка разбить на куски этот метод будет нарушением SRP, а не наоборот.
Формализм.
Пришло время оставить в покое нашего выпивоху. Вытрите слезы — мы обязательно вернемся к нему как-нибудь. А сейчас формализуем знания из этой статьи.
Формализм 1. Определение SRP
Формализм 2. Необходимые критерии самопроверки.
Мне не встречались достаточные критерии выполнения SRP. Но есть необходимые условия:
1) Задайте себе вопрос — что делает этот класс/метод/модуль/сервис. вы должны ответить на него простым определением. ( благодарю Brightori )
Впрочем иногда подобрать простое определение очень сложно
2) Фикс некоторого бага или добавление новой фичи затрагивает минимальное количество файлов/классов. В идеале — один.
Так как ответственность (за фичу или баг) инкапсулированна в одном файле/классе, то вы точно знаете где искать и что править. Например: фича изменения вывода логировки операций потребует изменить только логировщик. Бегать по всему остальному коду не требуется.
Другой пример — добавление нового UI-контрола, схожего с предыдущими. Если это заставляет вас добавить 10 разных сущностей и 15 разных конвертеров — кажется, вы “передробили”.
Если при добавлении новой операции «Вылить водку под стол» вам нужно затронуть логировщик, операцию выпивания и выливания — то похоже, что ответственности разделены криво. Безусловно, это не всегда возможно, но нужно стараться снизить этот показатель.
4) При уточняющем вопросе про бизнес логику (от разработчика или менеджера) вы лезете строго в один класс/файл и получаете информацию только от туда.
Фичи, правила или алгоритмы компактно написаны каждая в одном месте, а не разбросаны флагами по всему пространству кода.
Наш класс или метод ответственен за что-то одно, и ответственность отражена в его названии
AllManagersManagerService — скорее всего, God-класс
LocalPayment — вероятно, нет
Формализм 3. Методика разработки «Оккама-first».
В начале проектирования, человек-обезьянка не знает и не чувствует всех тонкостей решаемой задачи и может дать маху. Ошибаться можно по разному:
Важно запомнить правило: «ошибаться лучше в большую сторону», или «не уверены — не дробите». Если, например, ваш класс собирает в себе две ответственности — то он по прежнему понятен и его можно распилить на два с минимальным изменением клиентского кода. Собирать же из осколков стекла стакан, как правило, сложнее из-за размазанного по нескольким файлам контекста и отсутствия необходимых зависимостей в клиентском коде.
Пора закругляться
Сфера применения SRP не ограничивается ООП и SOLID. Он применим к методам, функциям, классам, модулям, микросервисам и сервисам. Он применим как к “фигакс-фигакс-и-в-прод”, так и к “рокет-сайнс” разработке, везде делая мир чуточку лучше. Если задуматься, то это едва ли не фундаментальный принцип всей инженерии. Машиностроение, системы управления, да и вообще все сложные системы — строятся из компонентов, и “недодробление” лишает конструкторов гибкости, “передробление” — эффективности, а неверные границы — разума и душевного спокойствия.
SRP не выдуман природой и не является частью точной науки. Он вылезает из наших с вами биологических и психологических ограничений.Это всего лишь способ контролировать и развивать сложные системы при помощи мозга человека-обезьяны. Он рассказывает нам, как декомпозировать систему. Изначальная формулировка требовала изрядного навыка телепатии, но надеюсь, эта статья слегка развеяла дымовую завесу.