Принцип единственной ответственности (Single Responsibility Principle)
12503

Принцип единственной ответственности (Single Responsibility Principle)


Принцип единственной ответственности (SRP) - это первый из принципов проектирования SOLID, оказавших большое влияние на разработку программного обеспечения с тех пор, как они были представлены Робертом Мартином ("Дядя Боб") в 2000 году. К сожалению, этот принцип часто понимают неправильно. В сочетании со слепой верой это может привести к чрезмерному упрощению мышления и ошибкам в проектировании.

Принцип часто формулируется как "каждый программный модуль должен иметь одну и только одну причину для изменения". И тогда название, кажется, предполагает, что у модуля должна быть "единственная ответственность". Это кажется довольно простым для понимания. Значит, модуль должен делать только одну вещь, верно? Нет. Здесь действует другое правило: функция должна делать только одну вещь. Вы когда-нибудь зажимали нос, называя функцию как-нибудь вроде "ImportDataAndLoadIntoDatabase". Мы знаем следующее: функция должна выполнять только одну функцию.

SRP - это разрешение иногда прощать себя за то, что кажется нарушением связности. На самом деле этот принцип означает, что код в данном модуле должен принадлежать одному и только одному конечному владельцу (или функциональной единице). Если это не так, вы должны разбить его на части. Дядя Боб использует пример (в письменном виде и в разговорах), когда финансовый директор и главный операционный директор зависят от кода, который рассчитывает часы работы сотрудников. Расчет часов - это простая математика, с которой все должны согласиться, верно? Один из руководителей просит внести изменения в этот код, и это нарушает бизнес-правила другого. Расчет часов не может быть общим: этот кусок кода должен иметь финансовую версию и операционную версию, несмотря на то, что это нарушает наши чувства DRY и связности(cohesion: связность характеризует то, насколько хорошо все методы класса или все фрагменты метода соответствуют главной цели, — иначе говоря, насколько сфокусирован класс). Это сильно отличается от того, как большинство людей применяют SRP.

Хотя мне не нужно применять его каждый день, SRP соответствует моему опыту. Я работал в системе управления транспортом, и у нас был объект, который представлял движение грузовиков. Он был оперативным по своей природе - вы назначали водителя, время прибытия и отправления в места доставки и т.д. Была и другая версия этого объекта, которая использовалась для оплаты труда водителей. Объекты были один к одному с большим количеством явных дубликатов. Это действительно сводило меня с ума! Несколько раз я пытался обработать их одинаковым кодом, но неизбежно терпел неудачу. И знаете что? Один объект принадлежал Операциям, а другой - (вы угадали) Финансам. Это была именно та вещь, о которой говорил дядя Боб. Хотя SRP верен, его иногда трудно применять на практике, поскольку кто (или какая группа) является "конечным владельцем" чего-либо, может быть неясным и потребовать времени для прояснения, особенно если вы строите систему с нуля с большим количеством заинтересованных сторон. С другой стороны, я рассматриваю SRP как естественное следствие принципов DDD: небезопасно иметь модель, которая совместно используется в ограниченных контекстах.

К сожалению, я видел, как многие люди слепо следуют неправильному пониманию SRP. Часто люди, которым нравятся маленькие классы, используют его, чтобы оправдать создание еще большего количества еще более маленьких классов. То, что начинается как простой, легкий для понимания класс, в итоге разбивается на множество абстракций, которые теперь труднее понять в совокупности. Независимо от того, нравится ли вам такой стиль, SRP сама по себе не приведет вас к этому. Недавно я прочитал книгу Adaptive Code (2-е издание, Microsoft Press), которая на сегодняшний день имеет рейтинг 4,7/5 на Amazon при 123 оценках. Там есть целая глава, посвященная SRP. И на протяжении всей главы она неверно объясняет SRP как относящуюся к классам, делающим слишком много вещей, и обосновывает проектные решения только на этом основании. По соображениям связности (cohesion) классы не должны делать слишком много вещей; поэтому дизайнерские решения не всегда плохи. Но, как пример, класс с 2 страницами кода разбит на ~12 классов и интерфейсов, и все это во имя неправильно понятой SRP. И это уважаемая книга опытного автора, а не случайный пост в блоге.

Мы должны поощрять начинающих инженеров понимать обоснование этих принципов, бороться с ними, применять их, когда они имеют смысл, и отвергать их, когда они не имеют смысла. Возвращение к первоисточникам также поучительно и увлекательно. Принципы SOLID уходят корнями в основные принципы проектирования, которые были заложены еще до нашего поколения - например, в работе Дэвида Парнаса (Parnas Paper), в которой представлена идея сокрытия информации, и в книге Ларри Константина "Метод анализа и проектирования структурированных систем", где представлены идеи сцепления и связности (coupling and cohesion). Дядя Боб считает, что эти работы повлияли на его мышление. В своих беседах, обычно после обязательных случайных рассуждений о физике, он всегда старается связать настоящее с прошлым. Это замечательная вещь. Но дядюшек Бобов вокруг не так много. Как отрасль, мы не очень хорошо передаем опыт от поколения к поколению. Что мы можем сделать для этого? Хотя преувеличением будет сказать, что "нет ничего нового под солнцем", удивительно, как часто мы боремся со старыми проблемами и не знаем, что можем встать на плечи тех, кто пришел до нас.

Почему нам, инженерам, нравятся эти принципы проектирования? (Помимо их эвристической пользы, я думаю, что это потому, что они дают ощущение ограничений для того, что в противном случае было бы беспредельным пространством решений. Они уменьшают беспокойство и вносят некое подобие детерминизма там, где его нет. Обычно мы бунтари и ненавидим ограничения (скажите кому-нибудь, что он должен использовать vim или emacs). Но ограничения - наш друг, когда мы сталкиваемся с бездной открытой проблемы, поэтому мы тянемся к ним. Но иногда мы заходим слишком далеко. Основанные на опыте наблюдения превращаются в принципы, которые становятся правилами, которые становятся собственно правилами, которые, в конце концов, превращаются в закон. Но давайте будем осторожны. Если отбросить физику, единственный абсолютный закон, который я нашел в программной инженерии, заключается в том, что нет никаких законов, которые можно было бы найти. В конце концов, мы строим замки из битов.

Получать оповещения о новых статьях:


Не нашли нужную статью? Предложите свою тему