#exp #arch #gex
Слой доменов
❓Из чего состоит слой доменов?
Как я писал ранее, слой состоит из бизнес сущностей и бизнес логики. Бизнес сущность - это ограниченный контекст вашего бизнеса, который подчиняется некоторому набору бизнес правил (бизнес логике).
Предположим, вы делаете сайт знакомств.
❓Какие можно выделить сущности?
1️⃣ Пользователь - информация о пользователе (ФИО, текст "о себе");
2️⃣ Лайк - запись о том, кто кого лайкнул;
❓Какие модули с бизнес логикой можно выделить?
1️⃣ Действие "Поставить лайк";
2️⃣ Действие "Отменить лайк".
А вот, например, действие "Загрузка фото пользователя" не будет являться доменной бизнес логикой - его следует выносить в слой приложения. И отслеживать эту операцию нужно через EventBus (о нем я обязательно напишу, когда буду рассказывать о слое приложения).
Слой доменов
❓Из чего состоит слой доменов?
Как я писал ранее, слой состоит из бизнес сущностей и бизнес логики. Бизнес сущность - это ограниченный контекст вашего бизнеса, который подчиняется некоторому набору бизнес правил (бизнес логике).
Предположим, вы делаете сайт знакомств.
❓Какие можно выделить сущности?
1️⃣ Пользователь - информация о пользователе (ФИО, текст "о себе");
2️⃣ Лайк - запись о том, кто кого лайкнул;
❓Какие модули с бизнес логикой можно выделить?
1️⃣ Действие "Поставить лайк";
2️⃣ Действие "Отменить лайк".
А вот, например, действие "Загрузка фото пользователя" не будет являться доменной бизнес логикой - его следует выносить в слой приложения. И отслеживать эту операцию нужно через EventBus (о нем я обязательно напишу, когда буду рассказывать о слое приложения).
👍5🤔4🔥2
#exp #gex #arch
Кстати, на практике я заметил, что в доменном слое можно "обойтись" без реализации бизнес логики. И оставить в нем только интерфейсы, которые декларируют контракты модулей этого слоя.
Приведу пример:
Вы хотите сделать функцию "Поставить лайк" на вашем сайте знакомств. Вы делаете в доменном слое модуль, например,
❓Где же тогда разместить саму бизнес логику?
Все просто. Для интерфейса
Кстати, на практике я заметил, что в доменном слое можно "обойтись" без реализации бизнес логики. И оставить в нем только интерфейсы, которые декларируют контракты модулей этого слоя.
Приведу пример:
Вы хотите сделать функцию "Поставить лайк" на вашем сайте знакомств. Вы делаете в доменном слое модуль, например,
ApplyLike и пишите в нем свою логику. Вот тут и кроется подвох. В какой-то момент вы хотите использовать другую логику, но ваши Use Cases уже связаны с модулем ApplyLike. Решить эту проблему можно с помощью интерфейса ApplyLikeInterface. Такая реализация сделает ваш доменный слой более гибким и позволит легче масштабироваться.❓Где же тогда разместить саму бизнес логику?
Все просто. Для интерфейса
ApplyLikeInterface вы делаете слой DomainCore, для модуля ApplyLike с вашей бизнес логикой вы должны сделать Domain слой.👍6🔥2
#exp #arch #gex
Порты и Адаптеры
Альтернативное название Гексагональной архитектуры - “Порты и адаптеры”. Это название лучше отражает принцип работы этого паттерна, так как шестиугольник (гексагон) не является строгим требованием паттерна, а вот наличие портов и адаптеров является одним из ключевых факторов.
❓Что такое порты?
Определение портов довольно простое. По сути это любая точка входа в вашем приложении. Это может быть графический интерфейс, командная строка, даже публичный метод класса - все это является портами.
❓Что такое адаптеры?
Точки входа (порты) мы определили. Теперь наша задача - передать данные через порты так, чтобы сохранился приемлемый уровень изоляции одного слоя от другого. В этом нам помогают адаптеры. Они позвляют транспортировать данные в другой слой, ничего не зная о деталях реализации модулей, которые мы хотим использовать. Максимум, который нам известен при использовании адаптеров, - это некий контракт взаимодействия.
Используя порты в качестве точек входа, а адаптеры в качестве транспортировщиков данных, система обретает гибкость, которая позволит в будущем легче масштабироваться. Например, использовать другой бизнес-логический модуль, фреймворк, базу данных и так далее.
Теперь, зная о том, что такое порты и адаптеры, стоит запомнить ключевое правило: любое перемещение между слоями системы должно сопровождаться входом на порт слоя и передачей данных его адаптеру.
Ниже я расскажу, какие ограничения накладываются на подобные перемещения.
Порты и Адаптеры
Альтернативное название Гексагональной архитектуры - “Порты и адаптеры”. Это название лучше отражает принцип работы этого паттерна, так как шестиугольник (гексагон) не является строгим требованием паттерна, а вот наличие портов и адаптеров является одним из ключевых факторов.
❓Что такое порты?
Определение портов довольно простое. По сути это любая точка входа в вашем приложении. Это может быть графический интерфейс, командная строка, даже публичный метод класса - все это является портами.
❓Что такое адаптеры?
Точки входа (порты) мы определили. Теперь наша задача - передать данные через порты так, чтобы сохранился приемлемый уровень изоляции одного слоя от другого. В этом нам помогают адаптеры. Они позвляют транспортировать данные в другой слой, ничего не зная о деталях реализации модулей, которые мы хотим использовать. Максимум, который нам известен при использовании адаптеров, - это некий контракт взаимодействия.
Используя порты в качестве точек входа, а адаптеры в качестве транспортировщиков данных, система обретает гибкость, которая позволит в будущем легче масштабироваться. Например, использовать другой бизнес-логический модуль, фреймворк, базу данных и так далее.
Теперь, зная о том, что такое порты и адаптеры, стоит запомнить ключевое правило: любое перемещение между слоями системы должно сопровождаться входом на порт слоя и передачей данных его адаптеру.
Ниже я расскажу, какие ограничения накладываются на подобные перемещения.
👍5🔥2
#exp #arch #gex
Принцип инверсии зависимостей отчетливо прослеживается, когда мы используем слой представления, слой приложения, доменный слой и слой инфраструктуры. Стоит заметить, что при правильном использовании DIP все зависимости направлены внутрь системы. От конкретных деталей ко все более и более абстрактным модулям на других слоях.
Благодаря этому принципу вы сможете проектировать модули так, чтобы они не зависели от представлений или от конкретных внешних систем. Именно это помогает достичь необходимого уровня изоляции каждой отдельно взятой системы или модуля и создать "идеальную" среду для тестирования.
Принцип инверсии зависимостей отчетливо прослеживается, когда мы используем слой представления, слой приложения, доменный слой и слой инфраструктуры. Стоит заметить, что при правильном использовании DIP все зависимости направлены внутрь системы. От конкретных деталей ко все более и более абстрактным модулям на других слоях.
Благодаря этому принципу вы сможете проектировать модули так, чтобы они не зависели от представлений или от конкретных внешних систем. Именно это помогает достичь необходимого уровня изоляции каждой отдельно взятой системы или модуля и создать "идеальную" среду для тестирования.
🔥5👍3🤔2
#exp #gex #arch
Слой приложения
#️⃣ Давайте вспомним, за что отвечает слой приложения. В данном слое расположены ваши Use Cases. Это некие агрегаторы, которые вызывают несколько разных логических модулей.
Помните про действия “Поставить лайк” (
В гексагональной архитектуре действует постулат: все Use Cases должны храниться в слое приложения и только там. Также не забываем о том, что данный слой должен иметь порты и адаптеры для того, чтобы его можно было вызвать из других слоев, например, из слоя представления (API, GUI, etc.).
На самом деле, это практически все, что необходимо знать об этом слое - его не стоит сильно усложнять. Единственное, что мы позже в него добавим, - взаимодействие со слоем инфраструктуры через EventBus.
Слой приложения
#️⃣ Давайте вспомним, за что отвечает слой приложения. В данном слое расположены ваши Use Cases. Это некие агрегаторы, которые вызывают несколько разных логических модулей.
Помните про действия “Поставить лайк” (
ApplyLike) и “Отменить лайк” (CancelLike) из поста про слой доменов? В слое приложения мы можем сделать use case “toggleLike” - это будет переключатель лайка. Если пользователь кликает на фото другого пользователя и у него еще нет лайка, то лайк ставится (ApplyLike), в противном случае лайк отменяется (CancelLike). В данном примере toggleLike - это Use Case двух бизнес логик.В гексагональной архитектуре действует постулат: все Use Cases должны храниться в слое приложения и только там. Также не забываем о том, что данный слой должен иметь порты и адаптеры для того, чтобы его можно было вызвать из других слоев, например, из слоя представления (API, GUI, etc.).
На самом деле, это практически все, что необходимо знать об этом слое - его не стоит сильно усложнять. Единственное, что мы позже в него добавим, - взаимодействие со слоем инфраструктуры через EventBus.
Telegram
Башня Байткода: заметки об архитектуре ПО
#exp #arch #gex
Слой доменов
❓Из чего состоит слой доменов?
Как я писал ранее, слой состоит из бизнес сущностей и бизнес логики. Бизнес сущность - это ограниченный контекст вашего бизнеса, который подчиняется некоторому набору бизнес правил (бизнес логике).…
Слой доменов
❓Из чего состоит слой доменов?
Как я писал ранее, слой состоит из бизнес сущностей и бизнес логики. Бизнес сущность - это ограниченный контекст вашего бизнеса, который подчиняется некоторому набору бизнес правил (бизнес логике).…
👍6🔥4
#exp #gex #arch
Инфраструктурный слой (ИС)
❓ Что такое инфраструктурный слой?
Инфраструктурный слой - это слой для связи приложения с внешним миром. Однако, стоит ограничивать общение этого слоя, так как в противном случае он может очень сильно разрастись. Обычно в этот слой относят взаимодействия с:
1️⃣ Базой данных;
2️⃣ Системами индексации контента;
3️⃣ Кэшем;
4️⃣ Файловой системой или файловым хранилищем;
5️⃣ ORM;
6️⃣ Фреймворками;
7️⃣ Сторонними библиотеками;
8️⃣ Брокерами очередей
... и многими другими инструментами.
Некоторые разработчики ошибочно включают в этот слой такие модули как GUI, API и т.п., то есть те модули, с которыми непосредственно работает конечный пользователь системы. Это большая ошибка, потому что они перегружают слой, и постепенно он становиться трудно изменяемым. Чтобы избавиться от этой проблемы, данный слой разделяют на подмножества: слой доступа к данным (Data Access Layer) и слой представления данных (Data Presentation Layer).
Хочу отметить, что ИС - один из самых эффективных слоев, который позволяет сделать ваше ПО чрезвычайно устойчивым к изменениям требований (любых требований). Фактор устойчивости крайне важен - он помогает вашей системе деградировать медленнее.
Формируя инфраструктурный слой своего приложения, старайтесь делать адаптеры более абстрактными. Адаптеры с более абстрактными методами легче заменить, чем адаптеры, которые сильно связаны с деталями реализации.
Инфраструктурный слой (ИС)
❓ Что такое инфраструктурный слой?
Инфраструктурный слой - это слой для связи приложения с внешним миром. Однако, стоит ограничивать общение этого слоя, так как в противном случае он может очень сильно разрастись. Обычно в этот слой относят взаимодействия с:
1️⃣ Базой данных;
2️⃣ Системами индексации контента;
3️⃣ Кэшем;
4️⃣ Файловой системой или файловым хранилищем;
5️⃣ ORM;
6️⃣ Фреймворками;
7️⃣ Сторонними библиотеками;
8️⃣ Брокерами очередей
... и многими другими инструментами.
Некоторые разработчики ошибочно включают в этот слой такие модули как GUI, API и т.п., то есть те модули, с которыми непосредственно работает конечный пользователь системы. Это большая ошибка, потому что они перегружают слой, и постепенно он становиться трудно изменяемым. Чтобы избавиться от этой проблемы, данный слой разделяют на подмножества: слой доступа к данным (Data Access Layer) и слой представления данных (Data Presentation Layer).
Хочу отметить, что ИС - один из самых эффективных слоев, который позволяет сделать ваше ПО чрезвычайно устойчивым к изменениям требований (любых требований). Фактор устойчивости крайне важен - он помогает вашей системе деградировать медленнее.
Формируя инфраструктурный слой своего приложения, старайтесь делать адаптеры более абстрактными. Адаптеры с более абстрактными методами легче заменить, чем адаптеры, которые сильно связаны с деталями реализации.
👍6🔥4
#arch #gex #exp
Инфраструктурный слой. Что в него выделять?
Все. Все, что сможете (любые внешние модули).
Библиотеки. Я стараюсь не использовать зависимости проекта напрямую. Лучше сделать адаптер в инфраструктурном слое, чтобы библиотеку можно было легко заменить. Ведь завтра релизнется новая более удобная и производительная либа, которую я захочу подключить в свой проект.
Хранилища данных. Тут частота изменений не такая большая. По моему опыту, вопрос о смене БД возникает, когда проект достигает "подросткового возраста" и старше. Смена СУБД или драйвера БД - это довольно трудоемкая задача. Если вы правильно организуете код, то вы сможете избежать основную массу проблем при миграции.
Прикрываем тыл. Бывает так, что на старте нового проекта вы приняли решение использовать Инструмент А, потому что вы с ним лучше знакомы, но в какой-то момент вы поняли, что это была плохая идея, и вам нужен Инструмент Б. Если вы не сможете быстро и бесшовно внедрить Инструмент Б, то цена такой ошибки может оказаться очень большой (деньги компании, ваше время, время коллег и нервы).
Инфраструктурный слой. Что в него выделять?
Библиотеки. Я стараюсь не использовать зависимости проекта напрямую. Лучше сделать адаптер в инфраструктурном слое, чтобы библиотеку можно было легко заменить. Ведь завтра релизнется новая более удобная и производительная либа, которую я захочу подключить в свой проект.
Хранилища данных. Тут частота изменений не такая большая. По моему опыту, вопрос о смене БД возникает, когда проект достигает "подросткового возраста" и старше. Смена СУБД или драйвера БД - это довольно трудоемкая задача. Если вы правильно организуете код, то вы сможете избежать основную массу проблем при миграции.
Прикрываем тыл. Бывает так, что на старте нового проекта вы приняли решение использовать Инструмент А, потому что вы с ним лучше знакомы, но в какой-то момент вы поняли, что это была плохая идея, и вам нужен Инструмент Б. Если вы не сможете быстро и бесшовно внедрить Инструмент Б, то цена такой ошибки может оказаться очень большой (деньги компании, ваше время, время коллег и нервы).
👍6🔥4
#exp #arch #gex
Слой представления
❓Что такое слой представления?
Данный слой - это подмножество инфраструктурного слоя. В инфраструктуру обычно выделяют минимум две задачи: доступ к данным (Data Access Layer) и представление данных (Data Presentation Layer). В слой представления обычно выносят все, с чем взаимодействуют конечные пользователи. Это может быть графический интерфейс, командная оболочка, HTTP API и т.п.
#️⃣ Немного о факторе устойчивости
Ранее я писал о слое инфраструктуры и его подмножестве - слое доступа к данным (Data Access Layer). Упоминался такой фактор как устойчивость к изменениям. Данный фактор/критерий является частью общей теории о Функциональной устойчивости информационных систем. По сути он означает то, что ваша система должна уметь быстро изменяться. Например, пользователи вашего приложения начнут уходить в сервис, который визуально удобнее вашего. Вы должны иметь возможность без лишних замедлений обновить свою систему, чтобы пользователям стало комфортнее. И такие банальные проблемы как неразделенные слои не должны вам мешать.
Также под устойчивостью подразумевается исправление ошибок. Плохо спроектированная архитектура может заметно увеличить время исправления бага. Если возникает подобная проблема, значит, ваша система в некоторой степени не устойчива к изменениям. Решить это можно регулярным проведением качественного рефакторинга архитектуры вашей системы.
Слой представления
❓Что такое слой представления?
Данный слой - это подмножество инфраструктурного слоя. В инфраструктуру обычно выделяют минимум две задачи: доступ к данным (Data Access Layer) и представление данных (Data Presentation Layer). В слой представления обычно выносят все, с чем взаимодействуют конечные пользователи. Это может быть графический интерфейс, командная оболочка, HTTP API и т.п.
#️⃣ Немного о факторе устойчивости
Ранее я писал о слое инфраструктуры и его подмножестве - слое доступа к данным (Data Access Layer). Упоминался такой фактор как устойчивость к изменениям. Данный фактор/критерий является частью общей теории о Функциональной устойчивости информационных систем. По сути он означает то, что ваша система должна уметь быстро изменяться. Например, пользователи вашего приложения начнут уходить в сервис, который визуально удобнее вашего. Вы должны иметь возможность без лишних замедлений обновить свою систему, чтобы пользователям стало комфортнее. И такие банальные проблемы как неразделенные слои не должны вам мешать.
Также под устойчивостью подразумевается исправление ошибок. Плохо спроектированная архитектура может заметно увеличить время исправления бага. Если возникает подобная проблема, значит, ваша система в некоторой степени не устойчива к изменениям. Решить это можно регулярным проведением качественного рефакторинга архитектуры вашей системы.
👍4🔥3🤯3
#exp #arch #gex
Разделение на компоненты и слайсы (Feature slicing)
Компонентно-ориентированную разработку можно использовать где угодно. Эта парадигма не связана с гексагональной архитектурой напрямую. Однако, паттерн гексагона описывает некий Component (закрашенная синяя область на схеме), в котором стоит разобраться.
❓ Что такое компонент с точки зрения гексагональной архитектуры?
В гексагональной архитектуре под компонентом понимается набор модулей, который относится к одной конкретной сущности вашего приложения. Это может быть бизнес-сущность Пользователь, Товар или что-то еще. Самое главное, что модули этого компонента могут находиться на разных слоях и объединяться в CBSE компоненты.
На практике не очень удобно, что приходится оперировать одним и тем же термином (компонент) в разных контекстах. Я предлагаю выделять следующие правила для гексагоналки:
1️⃣ Термин компонент подразумевается только в конексте CBSE;
2️⃣ Набор компонентов, которые можно сгруппировать на нескольких слоях, будет называться слайс (slice или feature slice);
3️⃣ Составление компонентов происходит по правилам CBSE. За одним исключением: компоненты на внутреннем уровне не должны зависеть от компонентов на внешнем уровне. Соблюдаем принцип инверсии зависимостей.
❓ Чем полезен feature slice?
Слайсы привносят в паттерн гексагональной архитектуры не только понятие CBSE, но и способ организации кода. Когда вы думаете не только о том, как организовать компонент, но и о том, как организовать слайс, то проект становится более структурированным. Это позволяет не только быстро и удобно разрабатывать фичи, но и делать это максимально изолированно от других слайсов и их компонентов.
Разделение на компоненты и слайсы (Feature slicing)
Компонентно-ориентированную разработку можно использовать где угодно. Эта парадигма не связана с гексагональной архитектурой напрямую. Однако, паттерн гексагона описывает некий Component (закрашенная синяя область на схеме), в котором стоит разобраться.
В гексагональной архитектуре под компонентом понимается набор модулей, который относится к одной конкретной сущности вашего приложения. Это может быть бизнес-сущность Пользователь, Товар или что-то еще. Самое главное, что модули этого компонента могут находиться на разных слоях и объединяться в CBSE компоненты.
На практике не очень удобно, что приходится оперировать одним и тем же термином (компонент) в разных контекстах. Я предлагаю выделять следующие правила для гексагоналки:
Слайсы привносят в паттерн гексагональной архитектуры не только понятие CBSE, но и способ организации кода. Когда вы думаете не только о том, как организовать компонент, но и о том, как организовать слайс, то проект становится более структурированным. Это позволяет не только быстро и удобно разрабатывать фичи, но и делать это максимально изолированно от других слайсов и их компонентов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🤯3🔥2
#exp #gex #arch
Command/Query bus на практике
Когда мы принимаем на вход какие-либо данные от пользователей, мы обязательно валидируем входящие данные и формируем ответ в нужном формате. Обычная схема в таком случае это Controller => Use Case => Domain Logic => Responder.
Controller - принимает и валидирует данные;
Use Case - агрегирует и использует доменную логику (Domain Logic);
Responder - формирует ответ в нужном формате.
Обычно этого хватает на старте, но с развитием системы могут появиться проблемы: разработчик забыл написать валидацию, нарушение конвенций или их отсутствие, некачественная валидация и т.д.
Решением подобных проблем являются внедрение правил CQRS и организация слоя Command/Query bus.
❓ Что такое Command/Query bus?
CQB - это изолированный слой системы, который несет ответственность за все входящие данные и формирует выходящие данные.
Для CQB можно выделить следующие задачи:
1️⃣ формирует команду/запрос;
2️⃣ валидирует команду/запрос;
3️⃣ передает её в обработчик команды/запроса;
4️⃣ обработчик команды/запроса формирует ответ*.
* В случае команд (запись данных) можно отдать стандартный ответ из контролера
CQB унифицирует работу с входными/выходными данными и предотвращает передачу некорректных данных в слой бизнес логики.
Command/Query bus на практике
Когда мы принимаем на вход какие-либо данные от пользователей, мы обязательно валидируем входящие данные и формируем ответ в нужном формате. Обычная схема в таком случае это Controller => Use Case => Domain Logic => Responder.
Controller - принимает и валидирует данные;
Use Case - агрегирует и использует доменную логику (Domain Logic);
Responder - формирует ответ в нужном формате.
Обычно этого хватает на старте, но с развитием системы могут появиться проблемы: разработчик забыл написать валидацию, нарушение конвенций или их отсутствие, некачественная валидация и т.д.
Решением подобных проблем являются внедрение правил CQRS и организация слоя Command/Query bus.
CQB - это изолированный слой системы, который несет ответственность за все входящие данные и формирует выходящие данные.
Для CQB можно выделить следующие задачи:
* В случае команд (запись данных) можно отдать стандартный ответ из контролера
CQB унифицирует работу с входными/выходными данными и предотвращает передачу некорректных данных в слой бизнес логики.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍4
#exp #arch #gex
Выводы о Гексагональной архитектуре
✅ Преимущества
1. Строго декларируются зоны ответственности, которые инкапсулируются в слоях приложения;
2. Бизнес-логика отделяется от логики системы, что упрощает миграцию кода;
3. Строго определяется направление зависимостей в соответствии с DIP;
4. Исчезает проблема зависимости от конкретных технических и технологических решений;
5. Бизнес-логика и системная логика отделяются от модулей представления;
6. Появляются правила объединения модулей в компоненты, которые можно переиспользовать в других системах;
7. Появляются правила CQRS, позволяющие увеличить производительность системы.
🚫 Недостатки
1. Очень высокий порог входа в концепции паттерна;
2. Увеличение количества слоев может затруднить понимание работы системы;
3. Большое количество кодовой базы.
Выводы о Гексагональной архитектуре
1. Строго декларируются зоны ответственности, которые инкапсулируются в слоях приложения;
2. Бизнес-логика отделяется от логики системы, что упрощает миграцию кода;
3. Строго определяется направление зависимостей в соответствии с DIP;
4. Исчезает проблема зависимости от конкретных технических и технологических решений;
5. Бизнес-логика и системная логика отделяются от модулей представления;
6. Появляются правила объединения модулей в компоненты, которые можно переиспользовать в других системах;
7. Появляются правила CQRS, позволяющие увеличить производительность системы.
1. Очень высокий порог входа в концепции паттерна;
2. Увеличение количества слоев может затруднить понимание работы системы;
3. Большое количество кодовой базы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥3
#gex #navi
Первая цепочка постов о Гексагональной архитектуре подошла к концу. Надеюсь, вы получили много полезой информации о том, как работать с рассмотренным паттерном. Чтобы глубже понять Гексагоналку, нам потребуется больше времени, а пока продолжим погружаться в другие интересные темы проектирования архитектуры.
Навигация по постам
1. Что такое Гексагональная архитектура?
2. Что такое слои приложения, и зачем они нужны?
3. Слой доменов Часть 1, Часть 2
4. Порты и Адаптеры
5. Принцип инверсии зависимостей в Гексагональной архитектуре
6. Слой приложения
7. Инфраструктурный слой
8. Инфраструктурный слой. Что в него выделять?
9. Слой представления
10. Разделение на компоненты и слайсы (Feature slicing)
11. Command/Query bus на практике
Первая цепочка постов о Гексагональной архитектуре подошла к концу. Надеюсь, вы получили много полезой информации о том, как работать с рассмотренным паттерном. Чтобы глубже понять Гексагоналку, нам потребуется больше времени, а пока продолжим погружаться в другие интересные темы проектирования архитектуры.
Навигация по постам
1. Что такое Гексагональная архитектура?
2. Что такое слои приложения, и зачем они нужны?
3. Слой доменов Часть 1, Часть 2
4. Порты и Адаптеры
5. Принцип инверсии зависимостей в Гексагональной архитектуре
6. Слой приложения
7. Инфраструктурный слой
8. Инфраструктурный слой. Что в него выделять?
9. Слой представления
10. Разделение на компоненты и слайсы (Feature slicing)
11. Command/Query bus на практике
Telegram
Башня Байткода: заметки об архитектуре ПО
#exp #gex #arch
Я столкнулся с Гексагональной архитектурой не так давно. Однако, этот паттерн проектирования архитектуры приложений настолько сильно захватил мои мысли, что теперь, работая над чужим ПО, я думаю "Какого 🤬🤬🤬 тут нет гексагоналки?!" 😅
❓Что…
Я столкнулся с Гексагональной архитектурой не так давно. Однако, этот паттерн проектирования архитектуры приложений настолько сильно захватил мои мысли, что теперь, работая над чужим ПО, я думаю "Какого 🤬🤬🤬 тут нет гексагоналки?!" 😅
❓Что…
👍5🔥4
#exp #arch #grasp
Проектирование пакетов/компонентов системы
На ряду с принципами SOLID, Роберт Мартин описал также 6 других:
1️⃣ Принцип эквивалентности повторного использования и выпуска (Reuse-Release Equivalency Principle или REP);
2️⃣ Общий принцип закрытия (Common Closure Principle или CCP);
3️⃣ Общий принцип повторного использования (Common Reuse Principle или CRP);
4️⃣ Принцип ациклических зависимостей (Acyclic Dependencies Principle или ADP);
5️⃣ Принцип стабильных зависимостей (Stable Dependencies Principle или SDP);
6️⃣ Принцип стабильной абстракции (Stable Abstraction Principle или SAP).
Возможно, вы уже слышали рекомендацию, в которой говорится, что мы должны стремиться к достижению low coupling (низкой связанности) и high cohesion (высокого сцепления) при работе над кодовой базой.
Мне не нравится термин "сцепление", поэтому я буду использовать слово "сплоченность".
❗️ Coupling (связанность) представляет собой степень взаимосвязи между блоками. Другими словами, это количество соединений между двумя или более блоками. Чем меньше число, тем ниже coupling. Блок (юнит) здесь необязательно является классом. Это может быть метод, класс, группа классов или даже модуль.
Понятие Cohesion (сплоченность) мы разберем чуть позже, когда узнаем о принципах REP, CCP, CRP. Для удобства эти принципы разделяют на следующие группы:
1️⃣ Принципы связности пакетов/компонентов - REP, CCP, CRP - снижают степень связности (coupling) пакетов и компонентов;
2️⃣ Принципы сплоченности пакетов/компонентов - SAP, SDP, ADP - увеличивают степень сплоченности (cohesion).
* На постере идеальный пример сплоченности модулей и сцепления компонентов.
Проектирование пакетов/компонентов системы
На ряду с принципами SOLID, Роберт Мартин описал также 6 других:
Возможно, вы уже слышали рекомендацию, в которой говорится, что мы должны стремиться к достижению low coupling (низкой связанности) и high cohesion (высокого сцепления) при работе над кодовой базой.
Мне не нравится термин "сцепление", поэтому я буду использовать слово "сплоченность".
Понятие Cohesion (сплоченность) мы разберем чуть позже, когда узнаем о принципах REP, CCP, CRP. Для удобства эти принципы разделяют на следующие группы:
* На постере идеальный пример сплоченности модулей и сцепления компонентов.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍3
#exp #arch #case
Хочу поделиться кейсом задачи, которую недавно решил в Github Booster. Цель - продемонстрировать, как можно развивать отдельные модули, как можно мыслить, чтобы дать импульс такому развитию.
📌 Задача
1️⃣ Использовать два кейса - syncSubscribers и syncSubscriptions для подписки на пользователей, которые подписались на целевого пользователя в Github, но на которых я не подписался в ответ.
2️⃣ Использовать два кейса - syncSubscribers и syncSubscriptions для отписки от пользователей, на которых подписался целевой пользователь, но которые не подписались на меня в ответ.
Процесс развития модулей
▶️ Уровень 1
Нарушен принцип SRP - класс SyncManager может изменяться более чем по одной причине. Декомпозируем.
▶️ Уровень 2
Можно так и оставить, но мне бы хотелось абстрагироваться от каждого кейса, поэтому через Manager классы я буду вызывать Handler классы. Это поможет мне в будущем заменить один Handler на другой так, чтобы те, кто использует Manager класс, не знали об этом измении и продолжали свою работу.
▶️ Уровень 3
Все, что хотели, разделили и абстрагировали. И тут возникла циклическая зависимость, которая порождается методами subscribersBalancing и subscriptionsBalancing. SubscribersManager класс зависит от SubscriptionsManager и наоборот.
▶️ Уровень 4
Для решения проблемы циклических зависимостей делаю следующее:
Cоздаю интерфейсы SubscribersSyncManagerInterface и SubscriptionsSyncManagerInterface, чтобы Manager классы завязывались на них (выделены зеленым).
Эти интерфейсы в моем случае ведут к еще одним Manager классам, которые нужны для отдельной логики.
Если не нужно делать дополнительные действия, можно привязать эти интерфейсы к Handler классам, и проблема циклических зависимостей будет решена.
Плюсы и минусы
➕ Соблюдается принцп SRP;
➕ Есть Handler классы, которые удобно покрывать тестами;
➕ Через Dependency Injection можно переопределять детали реализации интерфейсов.
❌ Много классов;
❌ Структура проекта без конкретных правил может стать чрезмерно запутанной.
Хочу поделиться кейсом задачи, которую недавно решил в Github Booster. Цель - продемонстрировать, как можно развивать отдельные модули, как можно мыслить, чтобы дать импульс такому развитию.
Процесс развития модулей
Нарушен принцип SRP - класс SyncManager может изменяться более чем по одной причине. Декомпозируем.
Можно так и оставить, но мне бы хотелось абстрагироваться от каждого кейса, поэтому через Manager классы я буду вызывать Handler классы. Это поможет мне в будущем заменить один Handler на другой так, чтобы те, кто использует Manager класс, не знали об этом измении и продолжали свою работу.
Все, что хотели, разделили и абстрагировали. И тут возникла циклическая зависимость, которая порождается методами subscribersBalancing и subscriptionsBalancing. SubscribersManager класс зависит от SubscriptionsManager и наоборот.
Для решения проблемы циклических зависимостей делаю следующее:
Cоздаю интерфейсы SubscribersSyncManagerInterface и SubscriptionsSyncManagerInterface, чтобы Manager классы завязывались на них (выделены зеленым).
Эти интерфейсы в моем случае ведут к еще одним Manager классам, которые нужны для отдельной логики.
Если не нужно делать дополнительные действия, можно привязать эти интерфейсы к Handler классам, и проблема циклических зависимостей будет решена.
Плюсы и минусы
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥4🤔1
#arch #ddd
Проектирование по модели предметной области становится возможным только в том случае, если четко отделен уровень предметной области. В многоуровневой архитектуре таким уровнем является Доменный слой (Domain Layer), который мы ранее рассматривали в Гексагональной архитектуре.
Уровень предметной области отвечает за описание бизнес-логики, рабочие состояния, бизнес-правила.
Именно здесь контролируется и используется текущее состояние прикладной модели, пусть даже технические подробности манипуляций данными делегируются инфраструктуре. Этот уровень является главной, алгоритмической частью программы.
Изолирование доменного слоя от кода интерфейса пользователя, прикладных операций и инфраструктуры позволяет модели развиться до достаточно сложной и в то же время достаточно понятной, чтобы заключить в себе существенные знания о предмете и эффективно их применить.
Проектирование по модели предметной области становится возможным только в том случае, если четко отделен уровень предметной области. В многоуровневой архитектуре таким уровнем является Доменный слой (Domain Layer), который мы ранее рассматривали в Гексагональной архитектуре.
Уровень предметной области отвечает за описание бизнес-логики, рабочие состояния, бизнес-правила.
Именно здесь контролируется и используется текущее состояние прикладной модели, пусть даже технические подробности манипуляций данными делегируются инфраструктуре. Этот уровень является главной, алгоритмической частью программы.
Изолирование доменного слоя от кода интерфейса пользователя, прикладных операций и инфраструктуры позволяет модели развиться до достаточно сложной и в то же время достаточно понятной, чтобы заключить в себе существенные знания о предмете и эффективно их применить.
Telegram
Башня Байткода: заметки об архитектуре ПО
#exp #arch #gex
Слой доменов
❓Из чего состоит слой доменов?
Как я писал ранее, слой состоит из бизнес сущностей и бизнес логики. Бизнес сущность - это ограниченный контекст вашего бизнеса, который подчиняется некоторому набору бизнес правил (бизнес логике).…
Слой доменов
❓Из чего состоит слой доменов?
Как я писал ранее, слой состоит из бизнес сущностей и бизнес логики. Бизнес сущность - это ограниченный контекст вашего бизнеса, который подчиняется некоторому набору бизнес правил (бизнес логике).…
👍4🔥3
#arch #ddd
Модель, выраженная в программе
Чтобы суметь найти компромиссы в программной реализации и при этом не потерять преимуществ проектирования по модели, связь между моделью и реализацией необходимо прорабатывать на уровне деталей.
В эти детали входят: ассоциации, сущности, объекты значений, службы, модули.
Когда требуется соблюсти однозначное соответствие между моделью и программной реализацией, труднее всего приходится при создании ассоциаций между объектами.
Ассоциации
❗️ Ассоциации - способ связать объекты, отношения БД и компоненты. Для всякой прослеживаемой в модели ассоциации должен существовать механизм в программе. Например, внешние ключи БД, агрегаты и тд.
Существует как минимум три способа сделать ассоциации более удобными и управляемыми:
1️⃣ Свести отношения к однонаправленным, прослеживаемым в одном направлении.
2️⃣ Добавить квалификаторы, тем самым явно ограничивая ассоциацию. Например, от "один ко многим" до "один к одному"
3️⃣ Устранить несущественные ассоциации. Например, избавиться от транзитивных зависимостей.
❗️ Важно ограничить взаимосвязи до минимума. Двунаправленные ассоциации означают, что два объекта можно понять только совместно, как одно целое. Если техническое задание непосредственно не требует двунаправленных отношений, то сведение их к однонаправленным снижает взаимозависимость и упрощает структуру программы (соблюдается принцип low coupling).
Модель, выраженная в программе
Чтобы суметь найти компромиссы в программной реализации и при этом не потерять преимуществ проектирования по модели, связь между моделью и реализацией необходимо прорабатывать на уровне деталей.
В эти детали входят: ассоциации, сущности, объекты значений, службы, модули.
Когда требуется соблюсти однозначное соответствие между моделью и программной реализацией, труднее всего приходится при создании ассоциаций между объектами.
Ассоциации
Существует как минимум три способа сделать ассоциации более удобными и управляемыми:
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
Башня Байткода: заметки об архитектуре ПО
#exp #arch #grasp
Проектирование пакетов/компонентов системы
На ряду с принципами SOLID, Роберт Мартин описал также 6 других:
1️⃣ Принцип эквивалентности повторного использования и выпуска (Reuse-Release Equivalency Principle или REP);
2️⃣ Общий принцип…
Проектирование пакетов/компонентов системы
На ряду с принципами SOLID, Роберт Мартин описал также 6 других:
1️⃣ Принцип эквивалентности повторного использования и выпуска (Reuse-Release Equivalency Principle или REP);
2️⃣ Общий принцип…
👍4🔥3🤯1
#arch #ddd #exp
Объект-значение (Value Object)
Объект-значение - это объект, которыи представляет описательныи аспект предметнои области и не имеет индивидуального существования, собственной идентичности. Такие объекты создаются в программе для представления тех элементов проекта, о которых достаточно знать только, что они собои представляют, но не кем именно они являются.
Правила проектирования объектов-значений:
❗️ Нужно различать, когда и что использовать (сущность, объект-значения), чтобы специальные приемы работы с объектами использовались только тогда, когда нужно.
❗️ Если элемент модели полностью определяется своими атрибутами, то его следует считать объектом-значением.
❗️ Сделаите так, чтобы он отражал смысл заложенных в него атрибутов и придаите ему соответствующую функциональность.
❗️ Считаите такои объект неизменяющимся. Изменение значения (value) может привести к повреждению объекта-владельца путем искажения его инвариантов.
❗️ Не даваите ему индивидуальности, вообще избегаите любых сложностеи, неизбежных при программном управлении сущностями.
* В своей практике я сталкивался с объектами-значениями в системе. Но лично мне кажется, что это бомба замедленного действия🤌
Объект-значение (Value Object)
Объект-значение - это объект, которыи представляет описательныи аспект предметнои области и не имеет индивидуального существования, собственной идентичности. Такие объекты создаются в программе для представления тех элементов проекта, о которых достаточно знать только, что они собои представляют, но не кем именно они являются.
Правила проектирования объектов-значений:
* В своей практике я сталкивался с объектами-значениями в системе. Но лично мне кажется, что это бомба замедленного действия
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥3🤔1
#arch #ddd
Модули (Module)
Модули используют все, но мало кто воспринимает их как полноценные структурные составляющие модели. Код подразделяют по разным критериям на всевозможные виды структурных элементов: от отдельных аспектов технической архитектуры до рабочих заданий конкретных разработчиков.
На уровне предметной области Модули должны соответствовать смысловым частям модели, выражая суть и структуру модели в крупном масштабе.
При проектировании Модулей придерживайтесь следующих правил:
❗️ Добивайтесь низкой зависимости модулей друг от друга, чтобы понятия в разных модулях можно было анализировать и воспринимать независимо друг от друга.
❗️ Дорабатывайте модель до тех пор, пока в ней не возникнут естественные границы в соответствии с высокоуровневыми концепциями предметной области, а соответствующий код не разделится соответствующим образом.
❗️ Дайте модулям такие имена, которые войдут в Единый язык. Как сами Модули, так и их имена должны отражать знание и понимание предметной области.
Модули (Module)
Модули используют все, но мало кто воспринимает их как полноценные структурные составляющие модели. Код подразделяют по разным критериям на всевозможные виды структурных элементов: от отдельных аспектов технической архитектуры до рабочих заданий конкретных разработчиков.
На уровне предметной области Модули должны соответствовать смысловым частям модели, выражая суть и структуру модели в крупном масштабе.
Как и все остальное в искусстве DDD, Модули являются механизмом коммуникации. <...> Если вы помещаете несколько классов в один Модуль, вы тем самым говорите вашему преемнику, которому предстоит изучать эту архитектуру: думай о них вместе, как о целом. Если ваша модель рассказывает историю, то Модули - это ее главы.
Эрик Эванс
При проектировании Модулей придерживайтесь следующих правил:
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
Башня Байткода: заметки об архитектуре ПО
#exp #arch #grasp
Проектирование пакетов/компонентов системы
На ряду с принципами SOLID, Роберт Мартин описал также 6 других:
1️⃣ Принцип эквивалентности повторного использования и выпуска (Reuse-Release Equivalency Principle или REP);
2️⃣ Общий принцип…
Проектирование пакетов/компонентов системы
На ряду с принципами SOLID, Роберт Мартин описал также 6 других:
1️⃣ Принцип эквивалентности повторного использования и выпуска (Reuse-Release Equivalency Principle или REP);
2️⃣ Общий принцип…
👍3🔥2
#arch #ddd #exp
Ловушки инфраструктуры
😡 Архитектуру диктует фреймворк
Сильное влияние на проектные решения по организации пакетов оказывают технические среды программирования. В некоторых случаях структуру архитектуры диктует используемый в команде фреймворк, размягчая мозг разработчика так, что он уже не заботится об отражении модели в программе.
😐 Разработчики переборщили
В другом случае, команда разработки создает такую архитектуру (например, многоуровневую), что обязанности одного объекта-модели размазываются между несколькими модулями (или слоями) программы. На этом этапе мысленно собрать все части объекта модели в одну концептуальную единицу становится почти невозможным, вследствие чего отраженная модель в программе либо понимается частично, либо не понимается совсем.
🫰 Вылезаем из болота
Если вы испытываете сложности с отражением модели предметной области в вашей программе, убедитесь в том, что правила построения архитектуры не слишком жесткие, а также что ваша программа не содержит чрезмерное количество обязательных пакетов.
😒 И снова low coupling + high cohesion
Иногда для формирования пакетов, способных отразить модель, достаточно соблюдать правила высокой внутренней связности и низкой внешней зависимости пакетов (low coupling and high cohesion).
Ловушки инфраструктуры
Сильное влияние на проектные решения по организации пакетов оказывают технические среды программирования. В некоторых случаях структуру архитектуры диктует используемый в команде фреймворк, размягчая мозг разработчика так, что он уже не заботится об отражении модели в программе.
В другом случае, команда разработки создает такую архитектуру (например, многоуровневую), что обязанности одного объекта-модели размазываются между несколькими модулями (или слоями) программы. На этом этапе мысленно собрать все части объекта модели в одну концептуальную единицу становится почти невозможным, вследствие чего отраженная модель в программе либо понимается частично, либо не понимается совсем.
Если вы испытываете сложности с отражением модели предметной области в вашей программе, убедитесь в том, что правила построения архитектуры не слишком жесткие, а также что ваша программа не содержит чрезмерное количество обязательных пакетов.
Иногда для формирования пакетов, способных отразить модель, достаточно соблюдать правила высокой внутренней связности и низкой внешней зависимости пакетов (low coupling and high cohesion).
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥4🤔1
#exp #ddd #arch
Агрегаты на практике
Агрегаты очень интересная часть DDD, поэтому хочется дополнить теоретический пост примером и своим опытом работы с ними.
Приведу пример из финансовой области. Итак, предположим наша команда занимается выдачей займов. К нам приходит Иван Иваныч, просит 100 тысяч русских долларов. Указывает все свои данные в форме на сайте, отправляет заявку на выдачу займа. Мы показываем ему несколько документов на подпись, Иваныч как-то все подписывает, переводим заявку в статус "Ожидает аудит". Проводим проверку его заявки, если все ок, то Иваныч получает деньги и начинает "жить" у нас в системе.
Пример инвариантов Агрегатов
Инвариант первый. Оформление заявки на займ.
Продолжим пример. Иваныч заполнил форму и отправил ее. В этот момент мы получили из БД инфу о пользователе (
Инвариант второй. Подписание документов.
Когда документы сгенерированы и мы получили коллекцию документов в коде, привязываем их к агрегату. Для сборки агрегата в актуальном инварианте используем новый метод
Чтобы изменить инвариант агрегата на второй, в сам агрегат добавляем новый метод
Инвариант третий. Ожидание аудита.
Когда
Надеюсь, логика изменения инвариантов агрегата стала более понятной. Количество инвариантов агрегата может быть разным, но очень важно помнить о соблюдении границ агрегата. Из опыта могу посоветовать не делать большие агрегаты и не использовать агрегаты более чем в 1-2 бизнес-процессах. В идеале использовать один агрегат для одного сложного бизнес-процесса, т.к. частные случаи в процессе могут зааффектить производительность. Даже если вам кажется, что можно переиспользовать агрегат в другом бизнес-процессе, - вам кажется😏
Агрегаты на практике
Агрегаты очень интересная часть DDD, поэтому хочется дополнить теоретический пост примером и своим опытом работы с ними.
Приведу пример из финансовой области. Итак, предположим наша команда занимается выдачей займов. К нам приходит Иван Иваныч, просит 100 тысяч русских долларов. Указывает все свои данные в форме на сайте, отправляет заявку на выдачу займа. Мы показываем ему несколько документов на подпись, Иваныч как-то все подписывает, переводим заявку в статус "Ожидает аудит". Проводим проверку его заявки, если все ок, то Иваныч получает деньги и начинает "жить" у нас в системе.
Пример инвариантов Агрегатов
Инвариант первый. Оформление заявки на займ.
Продолжим пример. Иваныч заполнил форму и отправил ее. В этот момент мы получили из БД инфу о пользователе (
User) и создали запись о новой заявке на займ (Order) в статусе "оформление заявки" + отправили задачу на формирование документов для подписания. Чтобы не создавать все объекты по отдельности, можно реализовать агрегат (LoanAggregate) и службу для него (LoanService). В LoanService добавим метод createNewOrder(array attributes): LoanAggrate, в аргументе которого будет минимальный набор данных для создания агрегата. Сам агрегат будет обычным объектом и будет содержать инфу о User-сущности и корневой сущности Order. Чтобы сохранить агрегат в первом инварианте сделаем метод LoanService::toAwaitingDocuments, который проверит корректность данных и зафиксирует данные в БД.Инвариант второй. Подписание документов.
Когда документы сгенерированы и мы получили коллекцию документов в коде, привязываем их к агрегату. Для сборки агрегата в актуальном инварианте используем новый метод
LoanService::getLoan(userId): LoanAggregate.Чтобы изменить инвариант агрегата на второй, в сам агрегат добавляем новый метод
addDocument(Document document), а в LoanService добавляем метод toDocumentsSigning, который проверит агрегат и зафиксирует новый инвариант (подписание документов).Инвариант третий. Ожидание аудита.
Когда
LoanAggregate будет переведен во второй инвариант и Иваныч как-то подпишет документы, мы переведем агрегат в следующий инвариант с помощью нового метода LoanService::toAwaitingAudit(). Кстати, если вы храните подписи документов в объектах-сущностях, то для агрегата можно сделать новый метод addSignature(Signature signature) и дополнить сборку агрегата в Фабрике (о фабриках позже).Надеюсь, логика изменения инвариантов агрегата стала более понятной. Количество инвариантов агрегата может быть разным, но очень важно помнить о соблюдении границ агрегата. Из опыта могу посоветовать не делать большие агрегаты и не использовать агрегаты более чем в 1-2 бизнес-процессах. В идеале использовать один агрегат для одного сложного бизнес-процесса, т.к. частные случаи в процессе могут зааффектить производительность. Даже если вам кажется, что можно переиспользовать агрегат в другом бизнес-процессе, - вам кажется
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥2🤯1