diff --git a/ru-RU/Chapter1/Getting-Started-with-Domain-Driven-Design.md b/ru-RU/Chapter1/Getting-Started-with-Domain-Driven-Design.md
index 0cc1659..1e83906 100644
--- a/ru-RU/Chapter1/Getting-Started-with-Domain-Driven-Design.md
+++ b/ru-RU/Chapter1/Getting-Started-with-Domain-Driven-Design.md
@@ -188,4 +188,4 @@ DDD это не серебрянная пуля; как и все в прогр
Реализация DDD требует усилий. Если бы это было легко, все писали бы качественный код.
Будьте готовы, потому что вы скоро узнаете, как писать код, который при прочтении отлично описывает бизнес вашей компании.
- Наслаждайтесь этим приключением!
\ No newline at end of file
+ Наслаждайтесь этим приключением!
diff --git a/ru-RU/Chapter2/Architectural-Styles.md b/ru-RU/Chapter2/Architectural-Styles.md
index 9e167f7..d957fa5 100644
--- a/ru-RU/Chapter2/Architectural-Styles.md
+++ b/ru-RU/Chapter2/Architectural-Styles.md
@@ -1,28 +1,26 @@
Глава 2. Архитектурные стили
==
-Чтобы иметь возможность создавать сложные приложения, одним из ключевых требований является наличие архитектурного дизайна,
-который соответствует потребностям приложения. Одно из преимущества DDD заключается в том, что он не привязан к какому-либо
-конкретному стилю архитектуры. Вместо этого мы можем свободно выбирать архитектуру, которая наилучшим образом соответствует
-потребностям каждого Ограниченного Контекста внутри основного Домена, который предлагает разнообразный набор архитектурных
-решений для каждого конкретной проблемы Домена.
+Чтобы иметь возможность создавать сложные приложения, одним из ключевых требований является наличие архитектурного дизайна, который соответствует потребностям приложения. Одно из преимущества DDD заключается в том, что он не привязан к какому-либо конкретному стилю архитектуры. Вместо этого мы можем свободно выбирать архитектуру, которая наилучшим образом соответствует потребностям каждого Ограниченного Контекста внутри основного Домена, который предлагает разнообразный набор архитектурных решений для каждого конкретной проблемы Домена.
-Например, Система Обработки Заказов может использовать подход Event Sourcing для отслеживания всех различных операций с заказом;
-Каталог продуктов может использовать CQRS для предоставления информации о продуктах различным клиентам; Система Управления Контентом
-может использовать Гексогональную Архитектуру (Hexagonal Architecture) для представления требований, таких как блоги, статичные страницы и т.д.
+Например:
+- Система Обработки Заказов может использовать подход **Event Sourcing** для отслеживания всех различных операций с заказом.
-В этой главе представленно введение во все соответствующие архитектурные стили в контексте PHP, следуя эволюции от традиционного
-(старого) PHP-кода к более сложной архитектуре. Обратите внимание, что, хотя существует много дургих существующих архитектурных стилей,
-таких как Data Fabric или SOA, некоторые из них оказались слишком сложными для представления средствами PHP.
+- Каталог продуктов может использовать **CQRS** для предоставления информации о продуктах различным клиентам.
+
+- Система Управления Контентом может использовать **Гексогональную Архитектуру** (Hexagonal Architecture) для представления требований, таких как блоги, статичные страницы и т.д.
+
+В этой главе представлено введение во все соответствующие архитектурные стили в контексте PHP, следуя эволюции от традиционного (старого) PHP-кода к более сложной архитектуре. Обратите внимание, что, хотя существует много других существующих архитектурных стилей, таких как Data Fabric или SOA, некоторые из них оказались слишком сложными для представления средствами PHP.
+
+
## Старые, добрые времена
-До релиза PHP версии 4, язык не охватывал Объектно-Ориентированную Парадигму. В то время обычным способом написания приложения
-было использвоание процедур и глобального состояния. Такие понятия, как Разделение Ответственности (Separation of Concerns (SoC)) и
-Модель-Представление-Контролер (Model-View-Controller (MVC)) были широко распространены среди сообщества PHP.
+До релиза PHP версии 4, язык не охватывал Объектно-Ориентированную Парадигму. В то время обычным способом написания приложения было использование процедур и глобального состояния. Такие понятия, как **Разделение Ответственности** (Separation of Concerns (SoC)) и **Модель-Представление-Контролер** (Model-View-Controller (MVC)) были широко распространены среди сообщества PHP.
-Пример ниже представляет собой приложение, написанное традиционным способом, где приложение состоят из множества фронтальных контроллеров, смешанных
-с кодом HTML. В те времена слой Инфраструктуры, Представления, UI, и Доменные слои были перемешаны.
+Пример ниже представляет собой приложение, написанное традиционным способом, где приложение состоят из множества фронтальных контроллеров, смешанных с кодом HTML. В те времена слой Инфраструктуры, Представления, UI, и Доменные слои были перемешаны.
+
+
```php
```

-Этот стиль кода часто называют Большой Ком Грязи (Big Ball of Mud).
-Однако в этом стиле улучшение стало то, что заголовок и нижний колонтитул веб-страницы были заключены в отдельные файлы.
-Это позвонило избежать дублирования и способствовало повторному использованию:
+
+
+Этот стиль кода часто называют **Большой Ком Грязи** (Big Ball of Mud).
+Однако в этом стиле улучшение стало то, что заголовок и нижний колонтитул веб-страницы были заключены в отдельные файлы. Это позвонило избежать дублирования и способствовало повторному использованию:
+
+
```php
```
-В настоящее время, хотя это крайн нежелательно, все еще встречаются приложение которые используют подобный процедурный подход. (скорре всего legacy код)
-Основным недостатком этого стиля архитектуры является то, что нет реального Разделения Ответственности (Separation of Concerns). Обслуживание и
-стоимость разработки приложения, разработанного таким образом, резко возрастает по сравнению с другими известными и проверенными архитектурами.
+
+
+В настоящее время, хотя это крайне нежелательно, все еще встречаются приложения которые используют подобный процедурный подход (скорее всего legacy код). Основным недостатком этого стиля архитектуры является то, что нет реального **Разделения Ответственности** (Separation of Concerns). Обслуживание и стоимость разработки приложения, разработанного таким образом, резко возрастает по сравнению с другими известными и проверенными архитектурами.
+
+
## Многоуровневая архитектура (Layered Architecture)
-С точки зрения удобства поддержки и повторого использования кода, наилучший способ сделать код более простым в обслуживании - это разделить концепции, то есть создать слои для каждой
-отдельной задачи. В нашем предыдущем примере легко сформировать разные уровни: первй для икапсуляции доступа и манипулирования данными, второй для решения проблем
-инфраструктуры и третий для оркестрирования двух предыдущих.
-Основное правило многоуровневой архитектуры - это то, что каждый слой должен иметь связь (возможно исопльзовать) с нижестоящими слоями,
-как показано на рисунке ниже
+
+С точки зрения удобства поддержки и повторного использования кода, наилучший способ сделать код более простым в обслуживании - это разделить концепции, то есть создать слои для каждой отдельной задачи.
+В нашем предыдущем примере легко сформировать разные уровни:
+- первый для инкапсуляции доступа и манипулирования данными.
+- второй для решения проблем инфраструктуры.
+- третий для оркестрирования двух предыдущих.
+
+Основное правило многоуровневой архитектуры - это то, что каждый слой должен иметь связь (возможность использовать) с нижестоящими слоями, как показано на рисунке ниже:

-Многоуровневая архитектура стремится к разделению различных компонентов приложения. Например, с точки зрения
-предыдущего примера, Представление сообщения в блоге должно быть полностью незаисимым от сообщения в блоге как
-концептуальной сущности. Сообщение в блоге как концептуальная сущность может может быть связано с одним или несколькими
-представлениями, вместо того чтобы быть тесно связанным с каким либо определенным представлением. Это принято называть
-Разделением Ответственности (Separation of Concerns).
+**Многоуровневая Архитектура** стремится к разделению различных компонентов приложения. Например, с точки зрения предыдущего примера, **Представление** сообщения в блоге должно быть полностью независимым от сообщения в блоге как концептуальной сущности.
+Сообщение в блоге как концептуальная сущность может быть отображено одним или несколькими **Представлениями**, вместо того чтобы быть тесно связанным с каким либо конкретным **Представлением**. Это принято называть **Разделением Ответственности** (Separation of Concerns).
+
+Другой парадигмой и шаблоном архитектуры, преследующей ту же цель, является шаблон **Model-View-Controller**. Изначально он задумывался и широко использовался для создания настольных приложений с графическим интерфейсом, а теперь он в основном использвуется в веб-приложениях благодаря популяризации веб-фреймворков, таких как Symfony, Zend, CodeIgniter.
-Другой парадигмой и шаблоном архитектуры, преследующей ту же цель, является шаблон Model-View-Controller. Изначально он
-задумывался и широко использовался для создания настольных приложений с графическим интерфейсом, а теперь он в основном
-использвуется в веб-приложениях благодаря популяризации веб-фраемворков, таких как Symfony, Zend, CodeIgniter.
+
### Model-View-Controller
-MVC - это архитектурный шаблон и парадигма, которая делит приложение на три основных уровня, описанных в следующих пунктах:
+**MVC**
+Это архитектурный шаблон и парадигма, которая делит приложение на три основных уровня, описанных в следующих пунктах:
+
+**Модель (The Model)**
+Содержит все поведения Доменой Модели. Этот уровень управляет всеми данными, логикой, и бизнесс-правилами назависимо от уровня представления данных. Уровень Модели является сердцем и душой каждого приложения MVC.
+
+**Контроллер (The Controller)**
+Организует взаимодействия между другими уровнями приложения, запускает действия в слое Модели для обновления ее состояния и обновления слоя Представления связанного с этой моделью.
+Кроме того, контроллер может отправлять сообщения на уровень Представления для изменения конкретного отображения Модели.
+
+**Представление (The View)**
+Отображает различные Представления слоя Модели и предоставляет способ вызывать изменения в состоянии модели.
- - Модель (The Model): Содержит все поведения Доменой Модели. Этот уровень управляет всеми данными, логикой, и бизнесс-правилами
- назависимо от уровня представления данных. Уровень Модели являетяс сердцем и душой каждого приложения MVC.
- - Контроллер (The Controller): Организует взаимодествия между другими уровнями приложения, запускает дествия в слое Модели
- для обновления ее состояния и обновления слоя Представления связанного с этой моделью.
- Кроме того, контроллер может отправлять сообщения на уровень Представления для изменения конкретного отображения Модели.
- - Представление (The View): Отображает различные Представления слоя Модели и предоставляет способ вызывать изменения в
- состоянии модели.
-

-
+
+
+
### Пример Многоуровневой Архитектуры
-
+
#### Модель
-Продолжая предыдущий пример, мы упомянули, что различные задачи должны быть разделенны.
-Для этого все слои должны быть идентифицированны в нашем оригинальном запутанном коде.
-На протяжении всего этого процесса мы должны уделять особое внимание коду, соотвествующему уровню Модели, который будет ядром приложения:
+Продолжая предыдущий пример, мы упомянули, что различные задачи должны быть разделены. Для этого все слои должны быть идентифицированы в нашем оригинальном запутанном коде. На протяжении всего этого процесса мы должны уделять особое внимание коду, соответствующему уровню **Модели**, который будет ядром приложения:
+
+
```php
+
Слой Модели теперь определяется классом `Post` и классом `PostRepository`.
-Класс `Post` представляет сообщение в блоге, а класс `PostRepository` представляет всю коллеркцию доступных
-сообщений в блоге. Кроме того, еще один слой - тот, который координирует поведения Домене Модели - необходим внутри модели.
-Рассмотрим Прикладной слой (Application layer):
+Класс `Post` представляет сообщение в блоге, а класс `PostRepository` представляет всю коллекцию доступных сообщений в блоге. Кроме того, есть еще один слой - тот, который координирует необходимое поведение Модели Домена.
+Рассмотрим **Прикладной** слой (Application layer):
+
+
```php
+
+Класс `PostService` - это, так называемая Прикладная служба (Служба Приложения, Application Service), и её целью является организация поведения Домена. Ни один другой тип объекта не может напрямую взаимодействовать с внутренними слоями Модели.
+
+
#### Представление (View)
-Представление - это слой, который может отправлять и получать сообщения со слоя модели и/или со слоя конетроллера. Его основная цель -
-отобразить модель пользователю на уровне пользовательского интерфейса, а также обновлять это отображение при обновлении модели.
-В общем случае, слой Представления получает объект (часто это Объект Передачи Данных (DataTransferObject)), тем самым собирая
-всю необходимую информацию для успешного отображения. Для PHP есть несколько шаблонизаторов, которые могут помочь
-отделить представление Модели от самой Модели и от Контроллера. Самым популярным, на текущий момент, является Twig.
+Представление - это слой, который может отправлять и получать сообщения со слоя модели и/или со слоя контроллера. Его основная цель - отобразить модель пользователю на уровне пользовательского интерфейса, а также обновлять это отображение при обновлении модели.
+
+В общем случае, слой Представления получает объект (часто это Объект Передачи Данных (DataTransferObject)), тем самым собирая всю необходимую информацию для успешного отображения. Для PHP есть несколько шаблонизаторов, которые могут помочь
+отделить Представление Модели от самой Модели и от Контроллера. Самым популярным, на текущий момент, является Twig.
Посмотрим как будет выглядеть слой Представления с Twig.
->**DTO вместо экземпляров Модели?**
+
+
+> **DTO вместо экземпляров Модели?**
>
> Это старый холивар. Зачем создавать DTO вместо того чтобы передать экземпляр класса Модели?
-> Основная причина и самый локаничный ответ, знакомое нам Разделение Ответственности
->(Separation of Concerns). Возможность Представления просматривать и использовать поступающие объекты приводит к тесной
->связи между слоем Представления и слоем Модели. Фактически, изменение в уровне Модели может нарушить все представления,
->которые используют измененные экземпляры модели.
+> Основная причина и самый лаконичный ответ, знакомое нам **Разделение Ответственности** (Separation of Concerns). Возможность Представления просматривать и использовать поступающие объекты приводит к тесной связи между слоем Представления и слоем Модели. Фактически, изменение в уровне Модели может нарушить все представления, которые используют измененные экземпляры модели.
+
+
+
```twig
{% extends "base.html.twig" %}
{% block content %}
@@ -330,27 +344,25 @@ class PostService
{% endblock %}
```
-В большистве случаев, когда Модель инициирует изменение состояния, она также уведомляет связанные
-Представления, чтобы обновить пользовательский интерфейс. В типичном веб-сценарии синхронизация между Моделью и
-его представлениями может быть немного сложной из-за природы клиент-серверной архитектуры.
-В таких средах, обчыно требуется использовать JavaScript, чтобы поддерживать эту синхронизацию.
-По этой причени, JavaScript MVC фреймворки, о которых говорится ниже, стали широко популярными в последние годы:
-
- - AngularJS
- - Ember.js
- - Marionette.js
- - React
-
- #### Контроллер (Controller)
-
-Слой Контроллера отвечает за организацию и взаимодествие слоёв Модели и Представления.
-Он получает сообщения от слоя Представления и запускает поведения модели для выполнения
-желаемого действия. Кроме того, он отправляет сообщения в Представления для отрисовки отображения Модели.
-Обе операции выполняются благодаря прикладному уровню, который отвечает за организацию, взаимодействие и инкапсуляцию
-поведения Домена.
-
-В терминах веб-приложения на PHP, Контроллер, обычно, охватывает набор классов, которые для достижения
-своих целей "Общаются на HTTP". Другими словами они получают HTTP запрос и HTTP запросом дают ответ.
+
+
+В большинстве случаев, когда Модель инициирует изменение состояния, она также уведомляет связанные Представления, чтобы обновить пользовательский интерфейс. В типичном веб-сценарии синхронизация между Моделью и её представлениями может быть немного сложной из-за природы клиент-серверной архитектуры. В таких средах, обычно требуется использовать JavaScript, чтобы поддерживать эту синхронизацию.
+По этой причине, JavaScript MVC фреймворки, о которых говорится ниже, стали широко популярными в последние годы:
+- AngularJS
+- Ember.js
+- Marionette.js
+- React
+
+
+
+#### Контроллер (Controller)
+
+Слой Контроллера отвечает за организацию и взаимодействия слоёв Модели и Представления. Он получает сообщения от слоя Представления и запускает поведение Модели для выполнения желаемого действия.
+Кроме того, он отправляет сообщения в Представления для отрисовки отображения Модели. Обе операции выполняются благодаря прикладному уровню, который отвечает за организацию, взаимодействие и инкапсуляцию поведения Домена.
+
+В терминах веб-приложения на PHP, Контроллер, обычно, охватывает набор классов, которые для достижения своих целей "Общаются на HTTP". Другими словами они получают HTTP Request и дают ответ в виде HTTP Response.
+
+
```php
render('posts/update-result.html.twig');
}
}
```
-### Инверсия зависемостей. Гексогональная архитектура.
+
+
+### Инверсия зависимостей. Гексагональная архитектура.
-Следую основному правилу Многоуровневой архитектуры, существует риск инкапсулирования инфраструктурных проблем в реализацию
-Доменных интерфейсов.
+Следую основному правилу Многоуровневой архитектуры, существует риск инкапсулирования инфраструктурных проблем в реализацию Доменных интерфейсов.
+Например, класс PostRepository из предыдущего MVC примера, был помещен в Домен предметной области. Однако размещение инфраструктурных деталей прямо в теле нашего Домена нарушает Разделение Ответственности (Domain Separation).
+Это создает проблемы. Трудно избежать нарушения основных правил многоуровневой архитектуры, что приводит к написанию кода который тяжело поддается тестированию, т.к. уровень Домена осведомлен о технических реализациях.
-Например, класс PostRepository из предыдущего MVC примера, должен быть помещен Домен предметной области.
-Однако размещение инфраструктурных деталей прямо в теле нашего Домена нарушает Разделение Ответственности
-(Domain Separation). Это создает проблемы; трудно избежать нарушения основных правил многоуровневой архитектуры, что приводит
-к написанию кода которых тяжело поддается тестированию, т.к. уровень Домена осведомлен о технических реализациях.
+
#### Принцип Инверсии Зависимостей (The Dependency Inversion Principle (DIP))
-Как мы можем это исправить? Поскольку уровень Доменной Модели связан с конкретной реализаций
-инфраструктуры, можно применить принцип инверсии зависимости (DIP), переместив Инфраструктурный слой выше
-всех остальных слоёв.
-
->**Принцип Инверсии Зависимостей**
->Модули более выского уровня не должны зависеть от нижележащий уровней. Оба должны связываться через абстракции.
->Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций. _Robert C. Martin_
-
-При использовании принципа Инверсии Зависемостей, схема архитектуры меняется, и уровень инфраструктуры, который
-можно назвать модулем низкого уровня, теперь зависит от пользовательского интерфейса, Прикладного слоя, и Доменного слоя,
-которые являются высокоуровневыми модулями. Зависимость была инвертирована.
-
-Но что такое Гексагональная Архитектура и как она вписывается во все это?
-Гексогональная Архитектура (так же именуемая как Порты и Адаптеры) была определена Алистером
-Кокберном в его книге _"Hexagonal Architecture"_. Он изображает приложение как шестиугольник,
-где каждая строна представляет Портс одним или неколькими Адаптерами.
-Порт - это коннектор с подключаемым Адаптером, который преоброзует внешний вход во что-то, что
-может понять внутренее приложение. С точки зрения DIP, Порт был бы модулем выского уровня, а Адаптер
-был бы модулем низлежащего уровня. Кроме того, если приложению необходимо отправить сообщение во внешний сервис, оно
-также будет использовать порт с адаптером для преобразования сообщения в язык понятный внешнему сервису и последующей отправкой сообщения.
-По этой причине Гексагональная архитектура воспитывает концепцию симметрии в приложении, а также
-является основной причиной, по которой меняется схема архитектуры.
-Её часто представляют в виде шестиугольника, потому что больше не имеет смысла говорить о верхнем или нижнем слое.
-Вместо этого, в Гексагональной Архитектуре говорится в внешнем слое и внутренем.
+Как мы можем это исправить? Поскольку уровень Доменной Модели связан с конкретной реализаций инфраструктуры (PostRepository), можно применить принцип инверсии зависимости (DIP), переместив **Инфраструктурный** слой выше всех остальных слоёв.
+
+
+
+> **Принцип Инверсии Зависимостей**
+> Модули более высокого уровня не должны зависеть от нижележащий уровней. Оба должны связываться через абстракции.
+> Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций. _Robert C. Martin_
+
+
+
+При использовании принципа Инверсии Зависимостей, схема архитектуры меняется, и уровень инфраструктуры, который можно назвать модулем низкого уровня, теперь зависит от пользовательского интерфейса, Прикладного слоя, и Доменного слоя, которые являются высокоуровневыми модулями. Зависимость была инвертирована.
+
+Но что такое Гексагональная Архитектура и как она вписывается во все это? Гексагональная Архитектура (так же именуемая как Порты и Адаптеры) была определена Алистером Кокберном в его книге _"Hexagonal Architecture"_.
+Он изображает приложение как шестиугольник, где каждая сторона представляет Порт с одним или несколькими Адаптерами.
+**Порт** - это коннектор с подключаемым **Адаптером**, который преобразует внешний вход во что-то, что может понять внутреннее приложение. С точки зрения DIP, **Порт** был бы модулем высокого уровня, а **Адаптер** был бы модулем нижележащего уровня. Кроме того, если приложению необходимо отправить сообщение во внешний сервис, оно также будет использовать **Порт** с **Адаптером** для преобразования сообщения в язык понятный внешнему сервису и последующей отправкой сообщения.
+По этой причине **Гексагональная** архитектура воспитывает концепцию симметрии в приложении, а также является основной причиной, по которой меняется схема архитектуры.
+Её часто представляют в виде шестиугольника, потому что больше не имеет смысла говорить о верхнем или нижнем слое. Вместо этого, в Гексагональной Архитектуре говорится о внешнем слое и внутреннем.
+
+
#### Применение Гексогональной Архитектуры
-Продолжим рассматривать приме с блогом. Первая концепция, которая нам нужна, это Порт, через который
-внешний мир может общаться с приложением. Для этого случая мы будем использовать HTTP-порт и соответствующий ему Адаптер.
-Внешним будет порт для отправки сообщений в приложение. В пример блога использовалась база данных для
-хранения постов блога, поэтому нам так же необходим Порт для извлечения постов из базы данных:
+Продолжим рассматривать пример с блогом. Первая концепция, которая нам нужна, это **Порт**, через который внешний мир может общаться с приложением. Для этого случая мы будем использовать HTTP-порт и соответствующий ему Адаптер.
+Внешним будет порт для отправки сообщений в приложение. В примере блога использовалась база данных для хранения постов блога, поэтому нам так же необходим **Порт** для извлечения постов из базы данных:
+
+
+
```php
+
+Этот **интерфейс** представляет собой **Порт**, через который приложение будет получать информацию о постах блога, и он будет расположен на уровне **Доменного** слоя. Теперь нужен **Адаптер** для этого **Порта**.
+**Адаптер** отвечает за определение способа извлечения сообщений из блога с использованием определенной технологии.
+
+
+
```php
+
+После того, как мы определили Порт и его Адаптер, последним шагом будет рефакторинг класса PostService, чтобы он использовал новый механизм. Это может быть легко достигнуто с помощью Иньекции Зависимостей (Dependency Injection):
+
+
+
```php
postRepository = $postRepository;
}
+
public function createPost($title, $content)
{
$post = Post::writeNewFrom($title, $content);
$this->postRepository->add($post);
+
return $post;
}
}
```
-Это простой пример Гегсогональной архитектуры. Это гибкая архитектура, которая способствует Разделению
-Ответственности, как в Многоуровневой Архитектуре. Это также способствует симметрии, благодаря
-наличию внутренней части приложения, которая связывается с внешним слоем через Порты.
-Отныне, это будет основополгающая архитектура, используемая для построения и объяснения CQRS и
-Event Sourcing.
+
+
+Это простой пример Гегсагональной архитектуры. Это гибкая архитектура, которая способствует Разделению Ответственности, как в Многоуровневой Архитектуре. Это также способствует симметрии, благодаря наличию внутренней части приложения, которая связывается с внешним слоем через Порты. Отныне, это будет основополагающая архитектура, используемая для построения и объяснения CQRS и Event Sourcing.
Более детальный разбор этой архитектуры вы можете найти в главе _"Приложение. Гексагональная архитектура в PHP"_.
-Для более подробного примера вам следует перейти к _Главе 11 "Приложение"_, в которой объясняются такие сложные темы,
-как транзакционность и другие сквозные вопросы.
+Для более подробного примера вам следует перейти к _Главе 11 "Приложение"_, в которой объясняются такие сложные темы, как транзакционность и другие сквозные вопросы.
+
+
### Command Query Responsibility Segregation (CQRS)
-Гексагональная архитектура - это хорошая основопологающая архитектура, но она имеет некоторые ограничения.
-Например, сложные пользовательские интерфейсы могут требовать Агрегированной информации, отображаемой
-в различных формах (Глава 8, Агрегаты), или они могут требовать данных, полученных из нескольких агрегатов.
-И в этом сценарии мы могли бы реализовать множество методов поиска в Репозиториях (возможно, столько же,
-сколько представлений пользовательского интерфейса есть в приложении). Или, может быть, мы решим
-перенести эту сложность в Службу Приложений (Application Service), используя сложные структуры для
-сбора и объедининя данных из различных Агрегатов. Пример:
+Гексагональная архитектура - это хорошая основополагающая архитектура, но она имеет некоторые ограничения. Например, сложные пользовательские интерфейсы могут требовать Агрегированной информации, отображаемой в различных формах (Глава 8, Агрегаты), или они могут требовать данных, полученных из нескольких агрегатов. И в этом сценарии мы могли бы реализовать множество методов поиска в различных Репозиториях (возможно, столько же, сколько есть представлений пользовательского интерфейса в приложении). Или, может быть, мы решим перенести эту сложность в Службу Приложений (Application Service), используя сложные структуры для сбора и объединения данных из различных Агрегатов. Пример:
+
+
```php
**Command Query Separation (CQS)**
->Задание вопроса не должно менять ответ - Бертран Мейер.
->Этот принцип разработки гласит, что каждый метод должен быть либо командой, выполняющей действие, либо
->запросом, возвращающим данные вызывающей стороне, но не обоими сразу. Wikipedia
-
-CQRS стремится к еще более агрессивному Разделению Проблем, деля модель на две части:
- - Модель Записи (The Write Model): также известная как Командная модель (Command Model), она выполняет запись
-и несет ответственность за истинное поведение домена.
- - Модель Чтения (The Read Model): она берет на себя ответственность за чтение в приложении и расматривается как
- нечто что должно выходить за пределы предметной области.
-
-Каждый раз, когда кто-то запускает команду для модели записи, выполняется запись в нужное хранилище данных.
-Кроме того, она запускает обновление Модели Чтения, чтобы в ней отобразились последние изменения.
-
-Это строгое разделение вызывает еще одно проблему: Согласованность в Конечном Итоге (Eventual Consistency).
-Согласованность модели чтения теперь зависит от команд, выполняемых Моделью Записи. Другими словами, модель чтения
-в конечном итоге непротиворечива. То есть каждый раз, когда Модель Записи выполняет команду,
-она запускает процесс, который будет отвечать за обновление модели чтения в соответствии с последними
-обновлениями модели записи. Есть некоторый лаг во времени, когда пользовательский интерфейс может представить
-устаревшую информацию пользователю. В веб-сценарии это происходит часто, поскольку мы несколько ограничены текущими
-технологиями.
-
-Подумайте о системе кэширования стоящим перед веб-приложением. Каждый раз, когда база данных обновляется новой информацией,
-данные на уровен кэша потенциально могут быть устаревшими, поэтому каждый раз, когда она обновляется,
-должен быть процесс, который обновляет систему кэша. Системы кэширования в конечном итоге становятся согласованными.
-
-Такие процессы, в терминалогии CQRS, называются Проекции Модели Записи (Write Model Projections)
-или просто Проекции. Мы проецируем Модели Записи на Модель Чтения. Этот процесс может быть синхронным или
-асинхронным, в зависимости от ваших потребностей, и этом может быть сделанно благодаря полезному тактическому
-шаблону проектирования - Глава "События Домена" - который будет подробно объяснен позже в книге.
-Основной проекций Модели Записи является сбор всех опубликованных событий домена и обновление модели чтения всей информацией,
-поступившей из событий.
+
+
+Когда этими конструкциями злоупотребляют, построение пользовательских представлений может стать действительно болезненным. Мы должны принять компромисс между тем, чтобы заставлять Службу Приложений возвращать Доменную Модель или возвращать некие DTO`s. В последнем варианте (DTO), мы избегаем тесной связи между
+Доменной Моделью и кодом Инфраструктуры (веб-контроллеры, cli контроллеры и т.д.).
+
+К счастью, есть другой подход. Если проблема заключается в множественных и разрозненных представлениях, то мы можем исключить их из Доменной Модели и начать рассматривать их как чисто инфраструктурную проблему. Эта опция базируется на принципе разработки, Разделение Команд и Запросов (CQS, Command Query Separation). Этот принцип был определен Бертраном Мейером (Bertrand Meyer), и, в свою очередь, он породил новый архитектурный паттерн под названием
+"Разделение Ответственности на Запросы и Команды" (CQRS, Command Query Responsibility Segregation), как это определенно Грегом Янгом (Greg Young).
+
+
+
+> **Command Query Separation (CQS)**
+> Задание вопроса не должно менять ответ - Бертран Мейер.
+> Этот принцип разработки гласит, что каждый метод должен быть либо командой, выполняющей действие, либо запросом, возвращающим данные вызывающей стороне, но не обоими сразу. Wikipedia
+
+
+
+**CQRS** стремится к еще более агрессивному Разделению Проблем, деля модель на две части:
+- Модель Записи (The Write Model): также известная как Командная модель (Command Model), она выполняет запись и несет ответственность за истинное поведение домена.
+- Модель Чтения (The Read Model): она берет на себя ответственность за чтение в приложении и рассматривается как нечто что должно выходить за пределы предметной области.
+
+
+
+Каждый раз, когда кто-то запускает команду для модели записи, выполняется запись в нужное хранилище данных. Кроме того, она запускает обновление Модели Чтения, чтобы в ней отобразились последние изменения.
+
+Это строгое разделение вызывает еще одно проблему - Согласованность в Конечном Итоге (Eventual Consistency).
+Согласованность модели чтения теперь зависит от команд, выполняемых Моделью Записи. Другими словами, модель чтения в конечном итоге непротиворечива. То есть каждый раз, когда Модель Записи выполняет команду, она запускает процесс, который будет отвечать за обновление модели чтения в соответствии с последними обновлениями модели записи. Есть некоторый лаг во времени, когда пользовательский интерфейс может представить устаревшую информацию пользователю. В веб-сценарии это происходит часто, поскольку мы несколько ограничены текущими технологиями.
+
+Подумайте о системе кэширования стоящим перед веб-приложением. Каждый раз, когда база данных обновляется новой информацией, данные на уровне кэша потенциально могут быть устаревшими, поэтому каждый раз, когда она обновляется, должен быть процесс, который обновляет систему кэша. Системы кэширования в конечном итоге становятся согласованными.
+
+Такие процессы, в терминалогии CQRS, называются Проекции Модели Записи (Write Model Projections) или просто Проекции. Мы проецируем Модели Записи на Модель Чтения. Этот процесс может быть синхронным или асинхронным, в зависимости от ваших потребностей, и этом может быть сделано благодаря полезному тактическому шаблону проектирования - Глава "События Домена" - который будет подробно объяснен позже в книге.
+
+Основной проекций Модели Записи является сбор всех опубликованных событий домена и обновление модели чтения всей информацией, поступившей из событий.
+
+
#### Модель записи
-Модель записи является истиным владельцем поведения Домена. Продолжая
-наш пример, интерфейс репозитория будет урощен до следующего:
+
+Модель записи является истинным владельцем поведения Домена. Продолжая
+наш пример, интерфейс репозитория будет упрощен до следующего:
+
+
+
```php
+
+Теперь `PostRepository` освобожден от всех задач чтения, кроме одной: функция byId, которая отвечает за загрузку Агрегата по его ID, для дальнейшей работы с ним.
+
+Так же будут удалены все методы запросов (query) из модели `Post`, оставив только методы команд. Это приводит к тому, что мы избавляемся от всех методов получения данных и любых других методов, предоставляющих информацию о Агрегате Post. Вместо этого будут опубликованы Доменные События, чтобы запустить проекцию Модели Записи использую подписку на них (события):
+
+
```php
id = $id;
@@ -681,10 +692,14 @@ class Post extends AggregateRoot
}
```
+
+
Все действия, которые инициируют изменение состояния, реализуются
-через события Домена. Для каждого опубликованного Доменого События существует
+через события Домена. Для каждого опубликованного Доменного События существует
соотвествующий метод apply, отвечающий за отражение изменения состояния:
+
+
```php
+
#### Модель чтения
-Модель Чтения, так же известная как модель запросов (Query Model), является
+Модель Чтения, так же известная как модель запросов (Query Model), является
денормализованной, в интересах Домена, моделью данных.
-Фактически, в CQRS все задачи чтения считаются процессами отчетности в
-инфраструктурной задаче. Как правило, при использовании CQRS Модель Чтения зависит от
-потребностей пользовательского интерфейса и сложности представлений, состовляющих
-пользовательский интерфейс. В ситуации, когда модель чтения определяется в терминах реляционных баз данных,
-простейшим подходом было бы установить взаимно-однозначные отношения между
-таблицами базы данных и представлениями пользовательского интерфейса. Эти
-таблицы базы данных и представления пользовательского интерфейса будут
-обновлены с использованием проекций Модели Записи, инициированных событиями домена,
- опубликованными стороной записи:
-
+Фактически, в CQRS все задачи чтения считаются процессами отчетности в инфраструктурной задаче. Как правило, при использовании CQRS Модель Чтения зависит от потребностей пользовательского интерфейса и сложности представлений, состовляющих пользовательский интерфейс. В ситуации, когда модель чтения определяется в терминах реляционных баз данных, простейшим подходом было бы установить взаимно-однозначные отношения между таблицами базы данных и представлениями пользовательского интерфейса.
+Эти таблицы базы данных и представления пользовательского интерфейса будут
+обновлены с использованием проекций Модели Записи, инициированных событиями домена, опубликованными стороной записи:
+
+
+
```sql
-- Определение представляния UI для поста с его комментариями
CREATE TABLE single_post_with_comments (
@@ -762,12 +775,14 @@ INSERT INTO single_post_with_comments VALUES
SELECT * FROM single_post_with_comments WHERE post_id = 1;
```
-Важной особенностью этого архитектурного стиля является то, что
- Модель Чтения должна быть полностью одноразовой, поскольку истинное состояние приложения
-определяется Моделью Записи. Это означает что Модель Чтения может быть удалено
-и пересоздано при необходимости использую проекции Модели Записи.
+
+
+Важной особенностью этого архитектурного стиля является то, что Модель Чтения должна быть полностью одноразовой, поскольку истинное состояние приложения определяется Моделью Записи. Это означает что Модель Чтения может быть удалена и пересоздана при необходимости используя проекцию Модели Записи.
+
+Ниже мы можем увидеть некоторые примеры возможных представлений в приложении блога:
+
+
-Ниже мы можеи увидеть некоторые примеры возможных представлений в преложении блога:
```sql
SELECT * FROM
posts_grouped_by_month_and_year
@@ -782,13 +797,15 @@ posts_by_author
WHERE author_id = 1;
```
-Важно отметить, что CQRS не ограничевается реализацией модели для реляционной
+
+
+Важно отметить, что CQRS не ограничивается реализацией модели для реляционной
базы данных. Это зависит исключительно от потребностей создаваемого приложения.
-Это может быть реляционная база данных, документно-ориентированная база данных, хранилище типа ключ-значение,
-или что-либо, что лучше всего соответствует потребностям вашего приложения. После приложения для публикации постов в блоге мы
-будет использовать `Elasticsearch` (базу данных, ориентированную на документы)
- - для реализации модели чтения.
-
+Это может быть реляционная база данных, документно-ориентированная база данных, хранилище типа ключ-значение, или что-либо, что лучше всего соответствует потребностям вашего приложения.
+Далее в приложении для публикации постов в блоге мы будет использовать `Elasticsearch` (базу данных, ориентированную на документы) для реализации модели чтения.
+
+
+
```php
+
+Код Модели Чтения был существенно упрощен до одного запроса к индексу Elasticsearch.
-Этот код показывает, что Модель Чтения на самом деле не нуждается в
-объектно-реляционном преобразователе, посколько это может быть излишним.
-Однако Модель Записи может выиграть от использования объектно-реляционого
-преобразования, поскольку это позволит вам организовать и структурировать Модель Чтения
-в соответствии с потребностями приложения.
+Этот код показывает, что Модель Чтения на самом деле не нуждается в объектно-реляционном преобразователе, посколько это может быть излишним.
+Однако Модель Записи может выиграть от использования объектно-реляционного
+преобразования, поскольку это позволит вам организовать и структурировать Модель Чтения в соответствии с потребностями приложения.
+
+
#### Синхронизация Модели Записи с Моделью Чтения
-Здесь начинается сложная часть. Как мы синхронизируем Модель Чтения с
+Здесь начинается сложная часть. Как мы синхронизируем Модель Чтения с
Моделью Записи? Мы уже говорили, что сделаем это с помощью Событий Домена,
-захваченных в тразакции Модели Записи. Для каждого типа захваченного События Домена
-будет выполнена соответствующая проекция. Таким образом, будет установлено
+захваченных в транзакции Модели Записи. Для каждого типа захваченного События Домена будет выполнена соответствующая проекция. Таким образом, будет установлено
взаимно-однозначное отношение между Событиями Домена и проекциями.
Давайте посмотрим на пример настройки проекций, для лучшего понимания идеи.
Прежде всего, нам нужно определить каркас для проекций:
+
+
```php
+
Определение проекции `Elasticsearch` для события `PostWasCreated` достаточно просто:
+
+
```php
+
Реализация Проекции является своего рода специализированным слушателем
-Событий Домена. Основное различие между этой Проекций и слушателем Доменых Событий по умолчанию в том,
-что Проекция реагирует на группу Доменных Событий, а не только на одно.
+Событий Домена. Основное различие между этой Проекций и слушателем Доменных Событий по умолчанию в том, что Проекция реагирует на группу Доменных Событий, а не только на одно.
+
+
```php
projections[get_class($event)])) {
@@ -905,6 +933,8 @@ class Projector
}
```
+
+
Следующий код показывает, как будет выглядеть поток между проекцией и событиями:
```php
@@ -936,11 +966,12 @@ $events = [
$projector->project($event);
```
-Этот код является своего рода синхронным, но процесс может быть и
-асинхронным, если это необходимо. И вы могли бы информировать своих клиентов об этих
-не синхроннизированных данных, разместив несколько предупреждений в слое представления.
+
+
+Этот код является своего рода синхронным, но процесс может быть и асинхронным, если это необходимо. И вы могли бы информировать своих клиентов об этих
+не синхронизированных данных, разместив несколько предупреждений в слое представления.
-В следующем примере мы будем использовать PHP-расширение amqplib в сочетании с
+В следующем примере мы будем использовать PHP-расширение amqplib в сочетании с
ReactPHP:
```php
@@ -975,6 +1006,8 @@ $events = [
$projector->project($event);
```
+
+
Чтобы это работало, нам нужен асинхронная проекция. Вот наивная реализация этого:
```php
@@ -1006,7 +1039,9 @@ class AsyncProjector
}
```
-И потребитель событий с использованием брокера RabbitMQ будет
+
+
+И потребитель событий с использованием брокера RabbitMQ будет
выглядеть примерно так:
```php
@@ -1056,7 +1091,9 @@ $consumer->on(
$loop->run();
```
-Отсюда все становится проще. Мы заставляем все репозитории использовать
+
+
+Отсюда все становится проще. Мы заставляем все Репозиторий использовать
экземпляр проекции, а затем так же запускаем процесс проецирования:
```php
@@ -1065,6 +1102,7 @@ class DoctrinePostRepository implements PostRepository
{
private $em;
private $projector;
+
public function __construct(EntityManager $em, Projector $projector)
{
$this->em = $em;
@@ -1092,49 +1130,50 @@ class DoctrinePostRepository implements PostRepository
}
```
-Экземпляр `Post` и записанные события запускаются и сохраняются в одной транзакции. Это гарантирует, что никакие
-события не будут потеряны, так как мы спроецируем их на модель чтения, если транзакция прошла успешно.
+
+
+Экземпляр `Post` и записанные события запускаются и сохраняются в одной транзакции. Это гарантирует, что никакие события не будут потеряны, так как мы спроецируем их на модель чтения, если транзакция прошла успешно.
В результате между Моделью Записи и Моделью чтения не будет никаких несоответствий.
->**ORM или без ORM**
+
+
+> **ORM или без ORM**
>
->Один из наиболее распространных вопросов при реализации CQRS - действительно ли нужен объектно-реляционный маппер
-> (ORM)? Мы твердо верим, что использование ORM для модели записи прекрасно и дает все преимущества использования
->инструмента, который поможет нам сэкономить много работы в случае использования реляционной базы данных.
->Но мы не должны забывать, что нам все еще нужно сохранять и извлекать состояние Модели Записи используя
->реляционную базу данных
+> Один из наиболее распространных вопросов при реализации CQRS - действительно ли нужен объектно-реляционный маппер (ORM)?
+> Мы твердо верим, что использование ORM для модели записи прекрасно и дает все преимущества использования инструмента, который поможет нам сэкономить много работы в случае использования реляционной базы данных.
+> Но мы не должны забывать, что нам все еще нужно сохранять и извлекать состояние Модели Записи используя реляционную базу данных.
+
+
### Event Sourcing
-CQRS - это мощная и гибкая архитектура. Это дает дополнительное преимущство в отношении сбора и
-сохранения Событий Домена (которые произошли во время выполнения операции Агрегата),
-предоставляя вам высокую степень детализации того, что происходит в вашем Домене. События в Домене
-являютяс одни из ключевых тактических паттернов из-за их значения в Домене, поскольку они описывают
-прошлые события.
->**Будьте осторожны с записью слишком большого количества событий**
->Постоянно растущее число событий - это звоночек. Это может выявить пристрастие к записи событий
->Домена, что, скорее всего, стимулируется бизнесом.
+CQRS - это мощная и гибкая архитектура. Это дает дополнительное преимущество в отношении сбора и сохранения Событий Домена (которые произошли во время выполнения операции Агрегата), предоставляя вам высокую степень детализации того, что происходит в вашем Домене. События в Домене являются одни из ключевых тактических паттернов из-за их значения в Домене, поскольку они описывают прошлые события.
+
+
+
+> **Будьте осторожны с записью слишком большого количества событий**
+>
+> Постоянно растущее число событий - это звоночек. Это может выявить пристрастие к записи событий Домена, что, скорее всего, стимулируется бизнесом.
+
+
Используя CQRS, мы смогли бы записать все соответствующие события, которые произошли на уровне Домена.
-Состояние доменной модели может быть представлено путем воспроизведения событий домена, которые мы записали
-ранее. Нам просто нужен инструмент для последовательного хранения всех этих событий. Нам нужно
-хранилище событий.
+Состояние доменной модели может быть представлено путем воспроизведения событий домена, которые мы записали ранее. Нам просто нужен инструмент для последовательного хранения всех этих событий. Нам нужно хранилище событий.
+
+
+
+> Основная идея, лежащая в основе Event Sourcing, заключается в отображении состояния Агрегатов в виде линейной последовательности событий.
+
+
+
+С помощью CQRS мы частично достигли следующего: сущность Post изменяет свое состояние с помощью событий Домена, но она сохраняется, как уже объяснялось, тем самым сопоставляя объект с строкой в таблицей базы данных.
->Основная идея, лежащая в основе Event Sourcing, заключается в отображении состояния Агрегатов в виде линейной
->последовательности событий.
+`Event Sourcing` делает еще один шаг вперед. Сейчас мы использовали одну таблицу базы данных для хранения состояния всех постов блога, другую для хранения состояния всех комментариев постав блога и т.д., использование `Event Sourcing` мы можем использовать одну таблицу базы данных, в которой будут храниться все События Домена, опубликованные всеми агрегатами в Модели Домена. Да, вы прочитали это правильно. Единая таблица базы данных.
-С помощью CQRS мы частично достигли следующего: сущность Post изменяет свое состояние с помощью
-событий Домена, но она сохраняется, как уже объяснялось, тем самым сопоставляя объект с строкой в таблицей базы данных.
+Следуя этому подходу, инструменты, подобные объектно-реляционному мапперу, больше не нужны. Единственным необходимым инструментом был бы простой уровень абстракции базы данных, к которому можно добавлять события:
-`Event Sourcing` делает еще один шаг вперед. Сейчас мы использовали одну таблицу базы данных для
-хранения состояния всех постов блога, другую для хранения состояния всех комментариев постав блога и т.д.,
-использование `Event Sourcing` мы можем использовать одну таблицу базы данных, в которой будут
-храниться все События Домена, опубликованные всеми агрегатами в Модели Домена. Да, вы прочитали
-это правильно. Единая таблица базы данных.
+
-Следуя этому подходу, инструменты, подобные объектно-реляционному маперу, больше не нужны.
-Единственным необходимым инструментом был бы простой уровень абстракции базы данных, к которому можно
-добавлять события:
```php
interface EventSourcedAggregateRoot
{
@@ -1149,15 +1188,18 @@ class Post extends AggregateRoot implements EventSourcedAggregateRoot
foreach ($events as $event) {
$post->applyThat($event);
}
+
return $post;
}
}
```
-Теперь у Агрегата `Post` есть метод, который при заданном наборе событий (другими словами, потоке событий)
-может пошагово воспроизводить состояние до тех пор, пока оно не достигнет текущего.
-Следующим шагом будет создание адаптера порта для `PostRepository`, который будет извлекать все
-опубликованные события из Агрегата `Post` и добавлять их в хранилище данных, куда добавляются
-все событий. Это то что мы называем хранищем событий (event store).
+
+
+
+Теперь у Агрегата `Post` есть метод, который при заданном наборе событий (другими словами, потоке событий) может пошагово воспроизводить состояние до тех пор, пока оно не достигнет текущего.
+Следующим шагом будет создание адаптера порта для `PostRepository`, который будет извлекать все опубликованные события из Агрегата `Post` и добавлять их в хранилище данных, куда добавляются все событий. Это то что мы называем хранилищем событий (event store).
+
+
```php
class EventStorePostRepository implements PostRepository
@@ -1184,10 +1226,13 @@ class EventStorePostRepository implements PostRepository
}
```
-Так выглядит реализация `PostRepository`, когда мы используем хранилище событий для сохранения
-всех событий, опубликованных Агрегатом `Post`. Теперь нам нужен способ восстановать Агрегат из его истории событий.
-Метод востановления, реализуется Агрегатом `Post` и используется для восстановления состояния сообщения в блоге из
+
+
+Так выглядит реализация `PostRepository`, когда мы используем хранилище событий для сохранения всех событий, опубликованных Агрегатом `Post`. Теперь нам нужен способ восстановить Агрегат из его истории событий. Метод восстановления, реализуется Агрегатом `Post` и используется для восстановления состояния сообщения в блоге из
инициированных событий:
+
+
+
```php
class EventStorePostRepository implements PostRepository
{
@@ -1199,12 +1244,16 @@ class EventStorePostRepository implements PostRepository
}
}
```
-Хранилище событий это рабочая лошадка, которая несет на себе всю ответственность за сохранение
-и восстановление потоков событий. Его публичный API состоит из двух простых методов:
-`append` и `getEventsFrom`. Первый добавляет поток событий в хранилище событий, а второй получает потоки
-событий, чтобы запусть построение Агрегата.
-Мы могли бы использовать key-value хранилище для реализаци хранения всех событий:
+
+
+Хранилище событий это рабочая лошадка, которая несет на себе всю ответственность за сохранение и восстановление потоков событий. Его публичный API состоит из двух простых методов:
+`append` и `getEventsFrom`. Первый добавляет поток событий в хранилище событий, а второй получает потоки событий, чтобы запустить построение Агрегата.
+
+Мы могли бы использовать key-value хранилище для реализации хранения всех событий:
+
+
+
```php
class EventStore
{
@@ -1256,20 +1305,20 @@ class EventStore
}
}
```
+
+
+
Эта реализация хранилища событий основана на Redis, широко используемом key-value хранилище.
-События добавляются в список с использованием префиксных событий: помимо этого, перед сохранением событий
-мы извлекаем некоторые метаданные, такие как класс события или дата создания, это может пригодиться позже.
+События добавляются в список с использованием префиксных событий: помимо этого, перед сохранением событий мы извлекаем некоторые метаданные, такие как класс события или дата создания, это может пригодиться позже.
+
+Очевидно, что с точки зрения производительности, Агрегату очень затратно обходить всю историю событий, чтобы постоянно находиться в актуальном состоянии. Это особенно заметно, когда поток событий содержи сотни или тысячи событий.
-Очевидно, что с точки зрения производительности, Агрегату очень затратно обходить всю историю событий, чтобы постоянно
-находиться в актуальном состоянии. Это особенно заметно, когда поток событий содержи сотни или тысячи событий.
+Лучший способ преодолеть эту ситуацию - это сделать снимок Агрегата (snapshot) и воспроизвести только те события в потоке событий, которые произошли после создания снимка.
+Снимок - это просто сериализованная версия состояния Агрегата, преимуществено основанный на времени. При одном подходе, снимок делается каждые n запущенный событий. При другом подходе снимок делается каждые n секунд.
-Лучший способ преодолеть эту ситуацию - это сделать снимок Агрегата (snapshot) и воспроизвести только
-те события в потоке событий, которые произошли после создания снимка.
-Снимок - это просто сериализованная версия состояния Агрегата, преимуществено основанный на времени. При одном подходе, снимок делается
-каждые n запущенный событий. При другом подходе снимок делается каждые n секунд.
+Следуя нашему примеру, мы будем использовать первый способ создания снимков. В метаданных события мы храним даполнительное поле, версию, с которой мы начнем воспроизводить историю Агрегата.
-Следуя нашему примеру, мы будем использовать первый способ создания снимков. В метаданных события мы
-храним даполнительное поле, версию, с которой мы начнем вопроизводить историю Агрегата.
+
```php
class SnapshotRepository
@@ -1312,8 +1361,13 @@ class SnapshotRepository
}
}
```
-Теперь нам необходимо провести рефакторинг класса `EventStore`, чтобы он начал использовать
-`SnapshotRepository` для загрузки Агрегата с допустимыми временными затратами.
+
+
+
+Теперь нам необходимо провести рефакторинг класса `EventStore`, чтобы он начал использовать `SnapshotRepository` для загрузки Агрегата с допустимыми временными затратами.
+
+
+
```php
class EventStorePostRepository implements PostRepository
{
@@ -1335,9 +1389,13 @@ class EventStorePostRepository implements PostRepository
}
}
```
-Нам просто нужно периодически делать снимки Агрегата. Мы можем делать это синхронно или асинхронно
-с помощью процесса, отвечающего за мониторинг хранилища событий. Следующий код представляет собой простой пример,
-демонстрирующий реализацию процесса создания снимка Агрегата:
+
+
+
+Нам просто нужно периодически делать снимки Агрегата. Мы можем делать это синхронно или асинхронно с помощью процесса, отвечающего за мониторинг хранилища событий. Следующий код представляет собой простой пример, демонстрирующий реализацию процесса создания снимка Агрегата:
+
+
+
```php
class EventStorePostRepository implements PostRepository
{
@@ -1363,32 +1421,25 @@ class EventStorePostRepository implements PostRepository
}
}
```
->***ORM или без ORM***
->Из представленного варианта использования архитектурного стиля ясно, что использование ORM только для
->сохранения/извлечения событий было бы излишним. Даже если мы используем реляционную базу данных для их хранения,
->нам нужно только сохранять/извлекать события из хранилища данных.
+
+
+
+> ***ORM или без ORM***
+> Из представленного варианта использования архитектурного стиля ясно, что использование ORM только для сохранения/извлечения событий было бы излишним. Даже если мы используем реляционную базу данных для их хранения, нам нужно только сохранять/извлекать события из хранилища данных.
+
+
## Резюмируем
-Поскольку существует множество вариантов архитектурных стилей, возможно, вы немного запутались в этой главе.
-Чтобы сделать выбор вы должны рассмотреть компромиссы для каждого из них.
-Ясно одно: подход Большой Комок Грязи - не вариант, так как код будет
+
+Поскольку существует множество вариантов архитектурных стилей, возможно, вы немного запутались в этой главе. Чтобы сделать выбор вы должны рассмотреть компромиссы для каждого из них. Ясно одно: подход Большой Комок Грязи - не вариант, так как код будет
очень быстро "портиться". Многоуровневая Архитектура является лучшим вариантом, но
-она имеет некоторые недостатки,такие как тесная связь между слоями.
-Можно утверждать, что наиболее сбалансированным вариантом будет Гексогональная
-Архитектура, поскольку она может использоваться в качестве базовой архитектуры и обеспечивает
-высокую степень развязки и симметрии между внетренней и внешней частью приложения. Это то, что мы рекомендуем
-для большинства сценариев.
+она имеет некоторые недостатки, такие как тесная связь между слоями.
+Можно утверждать, что наиболее сбалансированным вариантом будет Гексагональная
+Архитектура, поскольку она может использоваться в качестве базовой архитектуры и обеспечивает высокую степень развязки и симметрии между внутренней и внешней частью приложения. Это то, что мы рекомендуем для большинства сценариев.
Мы также рассматриваем CQRS и EventSourcing как относительно гибкие архитектуры,
которые помогут вам в борьбе с высокой сложностью проекта.
-CQRS и EventSourcing являются мощными подходами, но не позволяйте фактору
-крутости отвлекать вас от ценности, которую они предоставляют.
-Поскольку они оба идут некоторыми накладными расходами, у вас должна быть техническая
-причина для оправдания использования этих подходов. Эти архитектурыне стили
-действительно очень полезны, и эвристически узнать необходимость применения можно посчитав количество
-заявителей в репозиториев CQRS и количеству инициированных событий для
-EventSourcing. Если число методов поиска начинает расти. а хранилища становятся
-сложными в обслуживании, то пришло время рассмотреть вопрос об использовании CQRS,
-чтобы разделить задачи чтения и записи. И после этого, если объем событий в каждом
-Агрегате имеет тенденции к росту, и бизнес заинтересован в более детальной информации,
-то можно подумать о том, может ли окупиться переход на EventSourcing.
\ No newline at end of file
+CQRS и EventSourcing являются мощными подходами, но не позволяйте фактору
+крутости отвлекать вас от ценности, которую они предоставляют. Поскольку они оба идут некоторыми накладными расходами, у вас должна быть техническая
+причина для оправдания использования этих подходов. Эти архитектурные стили
+действительно очень полезны, и эвристически узнать необходимость применения можно посчитав количество заявителей в репозитории CQRS и количеству инициированных событий для EventSourcing. Если число методов поиска начинает расти. а хранилища становятся сложными в обслуживании, то пришло время рассмотреть вопрос об использовании CQRS, чтобы разделить задачи чтения и записи. И после этого, если объем событий в каждом Агрегате имеет тенденции к росту, и бизнес заинтересован в более детальной информации, то можно подумать о том, может ли окупиться переход на EventSourcing.