Многие инженеры начинают своё архитектурное мышление с SOLID. Затем изучают GoF-паттерны. Но всё равно остаётся ощущение, что чего-то не хватает: распределения ответственности, логики построения модели, связи структуры и поведения. И вот тут GRASP — это как раз то недостающее звено.
Хочу начать с личной предыстории.
Давным-давно, как и многие из вас, я читал умные книжки: «Чистый код» и «Чистая архитектура» Роберта Мартина, «Совершенный код» Стива Макконнелла и другие.
Также не обошли меня и классические принципы проектирования — SOLID, KISS, DRY — и, думаю, каждый читатель добавит сюда свои.
Безусловно, это всё важные и фундаментальные вещи.
Но однажды на горизонте появилось DDD — предметно-ориентированное проектирование в изложении Эрика Эванса. Именно его «синяя книга» стала культовой и задала язык для архитектурного мышления.
Позже я открыл и «красную книгу» Вона Вернона, где DDD уже рассматривался с точки зрения практической имплементации: архитектура, код, реальные подходы в проектах.

Читая Эванса, рассматривая его диаграммы классов и примеры кода, я всё думал: как он это делает?
Самым большим открытием для меня стало то, что книга DDD хоть и показывает стратегические и тактические приёмы — агрегаты, объекты‑значения, спецификации, фабрики и т. д. — но не учит проектировать саму предметную область.
Складывалось ощущение, что мы это уже откуда‑то должны были знать.
А откуда — остаётся загадкой.
Эванс очень подробно рассказывает:
о принципах предметно‑ориентированного мышления,
о тактических паттернах — агрегатах, сущностях, объектах‑значениях, репозиториях,
о стратегических подходах — ограниченных контекстах, контекстных картах, ubiquitous language.
Но он почти не даёт методики: как из требований, сценариев, реальной жизни — прийти к модели. Он как бы подразумевает, что ты уже нащупал нужные сущности — и теперь просто нужно их правильно оформить.
А как ты их нащупал — остаётся за кадром.
При этом стоит отметить, что и SOLID‑принципы не дают внятных ответов на вопрос:
как именно проектировать предметную область? Как и многие другие — безусловно великие — практики и труды.
Со временем начинаешь приходить к одной странной мысли:
все говорят про ООП, все пишут на объектно‑ориентированных языках — но писать и понимать, что ты пишешь, оказывается не одно и то же.
И со временем приходит странное ощущение. Будто вся архитектурная зрелость современного инженера сводится к SOLID, Чистому коду, и, максимум, — паттернам GoF.
То есть — к правилам оформления, к «как писать»,
но не к «что моделировать» и «почему именно так».
SOLID, безусловно, важен. Он помогает писать поддерживаемый код, говорит о структуре классов, об устойчивости к изменениям. Но он почти не затрагивает смысловую часть архитектуры — то, как должна выглядеть модель предметной области, какие объекты мы проектируем, где границы, откуда берутся поведения и ответственности.
И в этом кроется одна из главных ловушек:
Но потом сталкиваешься с реальной сложной системой — и вдруг осознаешь: тех инструментов, которые ты знал, просто не хватает. Они говорят о коде — но не о модели. О принципах оформления — но не о сути конструкции.
Хочется привести аналогию. Из личного опыта — сноуборд.
Многие учатся кататься сами. Смотрят видео, повторяют за другими, вроде бы все получается. Но потом приходят к тренеру — и вдруг оказывается:
стойка неправильная
корпус работает против доски
закантовка срывается
вес распределяется хаотично
Вседержится «на чувстве» и годах практики, но нет системы, нет понимания, нет архитектуры движения. Можно ехать. Но ты не знаешь — почему именно так.
То же самое и с ООП.
Да, ты используешь классы и объекты.
Да, есть интерфейсы, инъекции, модули.
Но если ты просто создаешь Hibernate-сущности с геттерами и сеттерами и меняешь их состояние в сервисах — это еще не объектно-ориентированное проектирование.
Это код на ООП-языке. Но не ООП как мышление.
Когда все встало на места: Крэг Ларман и его «Применение UML и шаблонов проектирования»
Следующей важной вехой для меня стала книга, которая произвела неизгладимое впечатление — «Применение UML 2.0 и шаблонов проектирования» автора Крэга Лармана
(в оригинале — «Applying UML and Patterns: An Introduction to Object‑Oriented Analysis and Design and Iterative Development»).
После нее мне показалось, что я наконец нашел ответы почти на все вопросы, которые накопились за годы практики.

Ларман рассматривает весь процесс проектирования ПО:
от анализа требований — до проектирования, программной реализации и даже тестирования.
В книге — четкая методика, живая логика и настоящий процесс мышления архитектора.
В какой-то момент мне даже показалось, что Ларман говорит о DDD больше, чем сам Эванс.
Он начинает с текста требований и use-case'ов,
анализирует сценарии — и на их основе формирует концептуальную модель.
Но концептуальная модель — это еще не классы и не код.
Это — модель предметной области, построенная на уровне бизнес-понятий.
Тем не менее, уже на этом этапе выявлены:
ключевые бизнес-сущности,
связи между ними,
важные атрибуты и поведения.
Цельэтого этапа — понять, какие концепции вообще существуют в системе —
еще до написания первой строчки кода.
Интересно, что книга Лармана вышла еще в 1997 году — то есть до появления DDD Эрика Эванса (первая публикация — 2003).
И здесь важный момент: эти книги не конкурируют между собой, а дополняют друг друга.
Ларман дает процесс — от анализа требований до концептуального проектирования.
Он показывает, как из пользовательских сценариев прийти к модели, выявить сущности, роли и поведение.Эванс, в свою очередь, формализует язык и паттерны для работы с предметной областью.
Он показывает тактические конструкции (агрегаты, фабрики, спецификации)
и стратегические приёмы — ограниченные контексты, контекстные карты, Ubiquitous Language.
DDD не столько про «как найти модель», сколько про то, как с ней обращаться,
и какие принципы соблюдать, когда модель уже начала формироваться.
Поэтому Лармана вполне можно воспринимать как учебник архитектурного анализа,
а DDD — как специализированное продолжение, фокусирующееся на глубине домена и границах модели.
«Люди часто спрашивают меня о том, с какой книги лучше всего начать знакомство с объектно‑ориентированным проектированием. С тех пор, как я увидел книгу „Применение UML и шаблонов проектирования“, я рекомендую именно её.»
— Мартин Фаулер
Когда концептуальная модель уже сформирована — наступает следующий шаг:
выделение ролей объектов, ответственности и поведения.
И вот тут в игру вступает GRASP.
Всего представлено девять шаблонов:
Information Expert
Creator
Controller
Low Coupling
High Cohesion
Polymorphism
Pure Fabrication
Indirection
Protected Variations
Группа 1. Фундаментальные принципы модели
(Cohesion, Coupling, Information Expert, Creator)

Эти паттерны задают самую суть: структуру, связанность и здравый смысл проектирования. Они применимы и к отдельным классам, и к модулям, и к сервисам — формируя основу, на которую опираются остальные архитектурные решения.
Cohesion и Coupling — “первое дыхание архитектуры”
High Cohesion — высокая связанность обязанностей внутри компонента.
Когда поведение логически объединено и сфокусировано, система становится:проще в поддержке,
легче для понимания,
надёжнее при изменениях.
Low Coupling — низкая связанность между компонентами.
Чем меньше зависимостей между модулями, тем:выше модульность,
меньше каскадных изменений,
легче тестировать и заменять части системы.
Эти два принципа работают не только на уровне классов, но и на уровне архитектурных границ.
Например, в DDD Bounded Context — это своего рода макро-Cohesion:
внутри контекста — единая, связанная модель,
снаружи — слабосвязанные интерфейсы между контекстами.
Information Expert — поведение рядом с данными
Если объект обладает всей или большей частью информации, необходимой для выполнения задачи — именно ему и следует эту задачу поручить.
Это позволяет повысить Cohesion,
снизить дублирование,
избавиться от анемичных моделей,
и перейти к rich-домену, где данные и поведение неразделимы.
Information Expert — один из самых сильных паттернов GRASP, потому что он помогает не «придумывать архитектуру», а выводить ее из самой модели.
Creator — тот, кто ближе к объекту, и должен его создавать
Если некий объект B:
содержит объект A,
записывает его,
активно использует,
или обладает нужными данными для инициализации A —
то именно B должен быть ответственен за создание A.
В каком-то смысле, можно упрощённо сказать, что Creator — это частный случай Information Expert, применимый именно к созданию объектов. Он следует той же логике: «у кого есть данные — тот и действует», но сфокусирован на одном конкретном аспекте — моменте рождения.
Такой подход помогает:
снизить Coupling,
локализовать ответственность,
и не выносить создание объектов в искусственные фабрики, если это не нужно.
Группа 2. Инженерные надстройки
(Pure Fabrication, Indirection, Controller)
Эта группа шаблонов не стремится моделировать предметный мир.
Наоборот — она предлагает синтетические, искусственные конструкции,
которые нужны не бизнесу, а архитектуре. Они помогают соблюсти принципы, повысить гибкость и упростить сопровождение.
Pure Fabrication — свобода инженерного мышления
Иногда, следуя паттернам вроде Information Expert, можно слишком буквально перенести ответственность в бизнес-объект. Например, в Active Record бизнес-сущность знает, как себя сохранить в базу данных.
Но это нарушает SRP и приводит к сильной связанности с инфраструктурой.
В рамках чистой архитектуры и DDD такой подход считается антипаттерном.
Pure Fabrication предлагает другой путь: создавать искусственные абстракции, которые:
не отражают предметную область,
но нужны для архитектурной чистоты,
и соблюдают принципы Low Coupling и High Cohesion.
Классический пример — репозиторий. Это не бизнес-сущность, а прослойка между логикой и базой данных.
На практике любой класс, созданный ради читаемости, структурности, тестируемости — это проявление Pure Fabrication.
Еще один пример из книги Лармана — объект Cup, который отвечает за выбрасывание кубиков и подсчет суммы.
Такой сущности нет в бизнесе, но она помогает изолировать поведение и улучшить структуру.
Indirection — управляй зависимостями через прослойки
Indirection (перенаправление) — это паттерн, снижающий жесткую связанность компонентов. Он создаёт контролируемую прослойку между объектами и дает системе:
управляемость,
гибкость,
возможность замены компонентов без каскадных правок.
По сути, Indirection — это идея, лежащая в основе множества архитектурных решений.
В DDD это может быть сервис, координирующий бизнес-логику.
В гексагональной архитектуре — адаптер, получающий данные извне.
В UI — контроллер, принимающий пользовательский запрос и передающий дальше.
Indirection — это не просто «прокинуть вызов». Это может быть и обогащение данных, и трансформация интерфейса, и дополнительная логика, в зависимости от нужд системы.
Поэтому такие паттерны, как Adapter, Decorator, Proxy, Facade — можно рассматривать как частные реализации идеи Indirection:
Паттерн | Что делает | Как проявляется Indirection |
---|---|---|
Proxy | Перехватывает вызовы | Промежуточный объект между клиентом и реализацией |
Decorator | Расширяет поведение без изменения кода | Оборачивает объект с дополнительной логикой |
Adapter | Преобразует интерфейс под ожидаемый формат | Посредник между несовместимыми интерфейсами |
Facade | Упрощает доступ к сложной подсистеме | Интермедиар между клиентом и множеством компонентов |
Repository | Абстрагирует доступ к данным | Посредник между бизнес-логикой и инфраструктурой |
Ключевая сила Indirection — в гибкости. Ты не просто разделяешь зоны ответственности — ты создаёшь точку управления потоком данных, трансформаций, вызовов.
Indirection + Pure Fabrication: пересечение смыслов
Интересно, что некоторые архитектурные элементы — например, репозиторий — могут одновременно быть проявлением нескольких GRASP-паттернов.
С одной стороны, репозиторий — это Pure Fabrication, потому что в предметной области нет такого понятия. Это искусственная абстракция, созданная ради структурной чистоты и соблюдения принципов модульности.
С другой — репозиторий реализует принцип Indirection, так как служит прослойкой между бизнес-логикой и слоем хранения, снижая связанность и повышая гибкость.
Это отличный пример того, как GRASP-паттерны не исключают, а дополняют друг друга, проявляясь на разных уровнях архитектуры. Именно в этом — сила зрелого объектного проектирования.
Controller — паттерн первого звена координации
GRASP-паттерн Controller отвечает на вопрос:
Кто первым получает внешние события и координирует поведение системы?
Это может быть любой компонент, стоящий на границе системы: HTTP-контроллер, gRPC endpoint, CLI-команда, Kafka-консьюмер. Он принимает входные данные, определяет сценарий и делегирует выполнение вглубь архитектуры. Именно поэтому Controller называют паттерном первого звена координации.
В книге Лармана Controller может представлять либо всю систему, либо один конкретный сценарий — use case. Во втором случае он сближается с идеей use-case-класса или application-сервиса, который инкапсулирует логику одного бизнес-процесса.
Важно понимать: Controller — это не конкретный слой и не конкретный фреймворк-специфичный компонент. Это архитектурная роль, задача которой — грамотно разрулить вход и передать его туда, где будет происходить настоящее действие.
Где проявляется Controller на практике
RestController
,CommandHandler
gRPC endpoint или API gateway
Kafka-консьюмер, listener RabbitMQ
CLI-команда
Scheduler, запускающий периодическую логику
UseCase/Service-класс, реализующий сценарий
Контроллеры на разных уровнях
Controller может жить на разных слоях:
UI-контроллер — принимает вход пользователя, парсит, валидирует
Use-case-контроллер — координирует сценарий, вызывает нужные сервисы
Один может вызывать другой, создавая каскад управляющих компонентов. Это нормально — особенно в системах с выделенным слоем Application, как в DDD или в гексагональной архитектуре.
Почему это важно
Controller — точка входа в систему. Именно здесь можно:
обернуть выполнение в транзакцию,
проверить права доступа,
залогировать сценарий или метрики,
адаптировать входные данные к внутреннему API.
Хорошо спроектированный Controller делает систему прозрачной и предсказуемой.
Плохо спроектированный — превращает вход в кашу из проверок, вызовов и бизнес-логики.
Группа 3: Polymorphism и Protected Variations — про гибкость, устойчивость и защиту от изменений
Polymorphism (Полиморфизм)
Полиморфизм — одна из базовых концепций ООП. Согласно определению, это способность функции работать с объектами разных типов.
Различают несколько форм:
Параметрический полиморфизм
В Java — это дженерики:List<T>
,Optional<T>
. Код обобщён, и не зависит от конкретного типа.Ad-hoc полиморфизм (перегрузка)
Одинаковое имя метода с разными параметрами:void print(String s) { ... } void print(int i) { ... }
Subtype Polymorphism (подстановочный полиморфизм)
Классический пример: наследование, интерфейсы, переопределение методов.Shape shape = new Circle(); shape.draw(); // Вызовется реализация из Circle

Паттерн Polymorphism из GRASP отвечает на вопрос:
Как проектировать поведение, которое должно различаться в зависимости от типа объекта?
Решение: Вынеси поведение в абстракцию — и пусть каждый тип реализует свое.
Пример без полиморфизма:
if (shape instanceof Circle) {
((Circle) shape).draw();
} else if (shape instanceof Rectangle) {
((Rectangle) shape).draw();
}
Пример с полиморфизмом:
interface Shape { void draw(); }
class Circle implements Shape {
public void draw() { ... }
}
Преимущества:
убираешь условную логику (
if
,switch
);код становится расширяемым без изменений в старом;
достигаешь принципа OCP — open for extension, closed for modification.
Protected Variations (Защита от изменений)
Если Polymorphism — это механизм, то Protected Variations — архитектурная цель.
Как защитить компоненты системы от изменений в других частях?
Суть:
Изолируй потенциально изменяемые участки стабильными абстракциями.
Предусмотри вариативность заранее — как архитектурную страховку.
Область | Пример |
---|---|
DDD | Репозиторий защищает доменную модель от изменений в БД |
Hexagonal Architecture | Адаптеры защищают ядро от API, UI, брокеров |
Чистая архитектура | Внешние слои зависят от внутренних через интерфейсы |
Protected Variations не про классы — а про архитектурное мышление:
— Где система нестабильна?
— Где точка потенциальной замены?
— Как изолировать важное от хрупкого?
Связь с принципами SOLID
Также необходимо упомянуть и принцип подстановки Барбары Лисков (LSP):
«Функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа, не зная об этом».
Абсолютно верно, Википедия дает здесь отсылку к контрактному программированию.
Своего рода LSP вводит поведенческую гарантию: если вы проектируете абстракцию — реализуйте ее корректно. Иначе подстановка просто ломает систему.
Многие интуитивно связывают LSP с полиморфизмом: раз уж подставляем типы — нужно делать это правильно.
Но если смотреть глубже, принцип Лисков ближе по духу к GRASP: Protected Variations.
Это про то, как гарантировать стабильность и безопасность при замене компонентов через абстракции. LSP отвечает за то, чтобы вариативные точки действительно были защищены — поведенчески, а не только структурно.
В свою очередь, принцип инверсии зависимостей (DIP) говорит:
«Высокоуровневый код не должен зависеть от деталей.»
То есть — абстрагируйся от нестабильного. Ровно то, о чём говорит Protected Variations в GRASP.
OCP (Open/Closed Principle) — еще один ключевой элемент, логически продолжающий связку. Он как раз перекликается с Polymorphism и Protected Variations, но с акцентом на изменяемость через расширение.
Это тот принцип, который начинающие разработчики часто не понимают:
“Программные сущности должны быть открыты для расширения, но закрыты для модификации.”
Как так?
Вся суть — в выделении правильных абстракций.
Это напрямую связано с:
Polymorphism — расширяемость через подстановку реализаций;
DIP — изоляция через абстракции, чтобы расширения не трогали клиентов;
LSP — поведенческая гарантия, что новые реализации не ломают старое;
Protected Variations — архитектурные буферы, чтобы изменения не «пробивали» клиентов.
OCP — это не средство, а цель.
Все остальные — это способы еt достичь.
Как GRASP-паттерны влияют на Cohesion и Coupling
Паттерн | Влияние на Cohesion и Coupling |
---|---|
Information Expert | Повышает Cohesion — поведение рядом с данными |
Creator | Снижает Coupling — создание у ближайшего соседа |
Pure Fabrication | Повышает Cohesion — выделение искусственного, но логичного объекта |
Indirection | Снижает Coupling — прослойка между компонентами |
Controller | Снижает Coupling UI и бизнес-логика, повышает Cohesion на входе |
Polymorphism | Снижает Coupling, повышает расширяемость и заменяемость |
Protected Variations | Локализует Coupling, создает буферы для изменений |
Вместо вывода
Многие инженеры начинают с практик, паттернов, фреймворков. Но по-настоящему зрелый подход начинается с понимания принципов. Не с SOLID, не с GoF, не с модных архитектурных терминов — а с глубинной логики распределения ответственности, устойчивости и смысла конструкции.
Именно это дает GRASP.
“A man who grasps principles can successfully select his own methods.
A man who tries methods, ignoring principles, is sure to have trouble.”
— Ralph Waldo Emerson«Тот, кто понимает принципы, сам найдет нужные методы. А тот, кто пробует методы, игнорируя принципы, неминуемо столкнется с проблемами.»
GRASP — это не просто девять паттернов. Это попытка выразить то, как мы должны думать о системе — на уровне архитектурной интуиции. Чтобы потом уже выбирать подходящие инструменты, архитектурные формы и даже стили программирования.
Зная принцип — ты всегда сможешь вывести практику. Но зная только практику — легко потеряться, когда реальность выходит за рамки учебника.
Если вам близко такое архитектурное мышление — буду рад обсудить сотрудничество.
Открыт к проектам, где важны не только фреймворки, но и смысл.
CTO / архитектор для старта или перезапуска проекта — пишите: @korobovn, мой канал t.me/cto_way, korobovn@gmail.com