1063 lines
38 KiB
Markdown
1063 lines
38 KiB
Markdown
# Build 060.20.1 — Trade Stream State Ownership Refactoring
|
||
|
||
**Engineering Migration Report**
|
||
|
||
---
|
||
|
||
# Контроль документа
|
||
|
||
| Свойство | Значение |
|
||
|----------|----------|
|
||
| Build | 060.20.1 |
|
||
| Название | Trade Stream State Ownership Refactoring |
|
||
| Статус | Completed |
|
||
| Проект | Dzentra |
|
||
| Подсистема | Market Data Acquisition |
|
||
| Компонент | Trades Feed (Time & Sales) |
|
||
| Версия | 1.0 |
|
||
|
||
---
|
||
|
||
# Связанные документы
|
||
|
||
- [Build 060.20.1 Architecture](build_060_20_1_architecture.md) —
|
||
архитектурная спецификация Build.
|
||
- [Build 060.20 Engineering Migration Report](build_060_20.md) —
|
||
предыдущий Build.
|
||
|
||
---
|
||
|
||
# Цель Build
|
||
|
||
Build 060.20 завершил формирование первой версии инфраструктурного слоя сопровождения состояния подсистемы **Trades Feed (Time & Sales)**.
|
||
|
||
В рамках предыдущего этапа было принято решение вынести долгоживущее состояние из `TradeStreamConsistencyController` в отдельную инфраструктурную подсистему **Trade Runtime**, представленную универсальным `TradeRuntimeRegistry`.
|
||
|
||
Данное решение стало важным промежуточным этапом развития архитектуры, поскольку впервые отделило бизнес-логику проверки непрерывности потока сделок от хранения сопровождаемого состояния.
|
||
|
||
Однако сразу после завершения Build 060.20 был проведён дополнительный архитектурный аудит, целью которого являлась проверка соответствия реализованной инфраструктуры общей архитектуре Dzentra.
|
||
|
||
В ходе аудита система анализировалась уже не изолированно в рамках подсистемы Trades Feed, а как часть полной архитектуры автоматической торговой системы, включающей:
|
||
|
||
- Market Data Acquisition;
|
||
- Data Validation & Normalization;
|
||
- Market Data Storage;
|
||
- Market Data Processing;
|
||
- Feature Engineering;
|
||
- Market State Estimation;
|
||
- Forecasting Models;
|
||
- Trading Decision;
|
||
- Risk Management;
|
||
- Execution Management System.
|
||
|
||
Такой аудит позволил определить фактическое место инфраструктурного состояния внутри всей архитектуры проекта.
|
||
|
||
Результаты анализа показали, что выбранная в Build 060.20 модель Runtime является избыточной относительно реально существующей ответственности компонентов.
|
||
|
||
---
|
||
|
||
# Предпосылки
|
||
|
||
К моменту начала настоящего Build подсистема Trades Feed уже обладала полностью завершёнными базовыми компонентами.
|
||
|
||
В систему входили:
|
||
|
||
- каноническая модель `Trade`;
|
||
- REST Pipeline;
|
||
- Trade Recovery;
|
||
- Trade Stream Consistency;
|
||
- механизм восстановления пропусков;
|
||
- единая каноническая обработка сделок независимо от источника данных.
|
||
|
||
Кроме того, Build 060.20 внедрил отдельную инфраструктурную подсистему Runtime, предназначенную для сопровождения долгоживущего состояния.
|
||
|
||
Архитектура приобрела следующий вид.
|
||
|
||
```text
|
||
Trade Recovery
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
Trade Stream Consistency
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
Trade Runtime
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
TradeStreamState
|
||
```
|
||
|
||
Практическая эксплуатация данной модели показала, что бизнес-логика работает корректно.
|
||
|
||
Все тесты успешно проходили.
|
||
|
||
Однако возник более фундаментальный вопрос.
|
||
|
||
**Кто действительно является владельцем инфраструктурного состояния Trade Stream?**
|
||
|
||
Именно ответ на этот вопрос и стал основной причиной проведения дополнительного архитектурного аудита.
|
||
|
||
---
|
||
|
||
# Причины проведения архитектурного аудита
|
||
|
||
После завершения Build 060.20 дальнейшее развитие проекта переходило к следующим этапам:
|
||
|
||
- Runtime Protocol Integration;
|
||
- Runtime Service Integration;
|
||
- Acquisition Integration;
|
||
- Reconnect & Runtime Recovery.
|
||
|
||
До начала этих работ было принято решение провести дополнительную архитектурную проверку.
|
||
|
||
Главной задачей аудита являлось не изменение поведения системы.
|
||
|
||
Напротив.
|
||
|
||
Требовалось определить, соответствует ли уже реализованная инфраструктура долгосрочной архитектуре Dzentra.
|
||
|
||
Особое внимание уделялось одному вопросу.
|
||
|
||
**Какой компонент действительно должен владеть долгоживущим состоянием Trade Stream?**
|
||
|
||
Именно от ответа на этот вопрос зависело дальнейшее развитие всей подсистемы получения рыночных данных.
|
||
|
||
В случае неверного выбора владельца состояния ошибки постепенно распространялись бы на последующие Build, затрагивая Runtime Integration, WebSocket Integration и Composition Root.
|
||
|
||
Поэтому было принято решение выполнить архитектурную коррекцию до начала следующих этапов разработки.
|
||
|
||
---
|
||
|
||
# Основная задача Build
|
||
|
||
Настоящий Build не изменяет бизнес-логику подсистемы Trades Feed.
|
||
|
||
Не изменяются:
|
||
|
||
- алгоритмы проверки последовательности сделок;
|
||
- алгоритмы дедупликации;
|
||
- механизм восстановления истории;
|
||
- каноническая модель `Trade`;
|
||
- публичное поведение `TradeStreamConsistencyController`;
|
||
- публичное поведение `TradeRecoveryController`.
|
||
|
||
Build полностью сосредоточен исключительно на одной архитектурной задаче.
|
||
|
||
**Определить единственного владельца инфраструктурного состояния подсистемы Trade Stream.**
|
||
|
||
После завершения Build архитектура должна удовлетворять следующим принципам:
|
||
|
||
- владелец состояния определяется предметной областью, а не уровнем инфраструктуры;
|
||
- каждый stateful-компонент самостоятельно владеет своим состоянием;
|
||
- инфраструктурное хранилище располагается внутри собственной подсистемы;
|
||
- Runtime приложения не становится владельцем бизнес-состояния;
|
||
- Composition Root продолжает отвечать исключительно за создание графа зависимостей.
|
||
|
||
Именно достижение этих целей составляет полный Scope настоящего Build.
|
||
|
||
---
|
||
|
||
# Результаты архитектурного аудита
|
||
|
||
Архитектурный аудит проводился уже после полного завершения Build 060.20.
|
||
|
||
Его задачей являлась не проверка корректности работы алгоритмов.
|
||
|
||
Все алгоритмы уже были подтверждены модульными тестами.
|
||
|
||
Основной целью аудита являлось определение **истинственного владельца инфраструктурного состояния подсистемы Trades Feed**.
|
||
|
||
Для этого реализованная архитектура была рассмотрена не изолированно, а как часть полной архитектуры Dzentra.
|
||
|
||
Анализ выполнялся относительно общей цепочки обработки данных.
|
||
|
||
```text
|
||
Exchange
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
Market Data Acquisition
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
Data Validation & Normalization
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
Market Data Processing
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
Feature Engineering
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
Market State Estimation
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
Forecasting Models
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
Trading Decision
|
||
```
|
||
|
||
При рассмотрении данной архитектуры выяснилось, что состояние Trade Stream существует исключительно внутри первого модуля — **Market Data Acquisition**.
|
||
|
||
Никакая последующая подсистема не использует внутреннее состояние проверки последовательности сообщений.
|
||
|
||
Оно необходимо исключительно для обеспечения корректности поступающего потока сделок.
|
||
|
||
Следовательно, это состояние не является инфраструктурным состоянием приложения в целом.
|
||
|
||
Оно является внутренним состоянием одной конкретной подсистемы.
|
||
|
||
Именно это наблюдение стало ключевым результатом проведённого аудита.
|
||
|
||
---
|
||
|
||
# Анализ ответственности Runtime
|
||
|
||
После завершения Build 060.20 архитектура выглядела следующим образом.
|
||
|
||
```text
|
||
Trade Recovery
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
Trade Stream Consistency
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
Trade Runtime
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
TradeStreamState
|
||
```
|
||
|
||
На первый взгляд подобная декомпозиция выглядела логичной.
|
||
|
||
Runtime действительно сопровождал долгоживущее состояние.
|
||
|
||
Однако дальнейший анализ показал наличие фундаментальной архитектурной проблемы.
|
||
|
||
Runtime ничего не знает о состоянии Trade Stream.
|
||
|
||
Он:
|
||
|
||
- не проверяет последовательность сообщений;
|
||
- не знает алгоритмов дедупликации;
|
||
- не знает правил восстановления;
|
||
- не знает структуры `TradeStreamState`;
|
||
- не принимает никаких решений относительно состояния.
|
||
|
||
Фактически Runtime выступал исключительно в роли словаря объектов.
|
||
|
||
Подобная ответственность сама по себе не образует самостоятельную архитектурную подсистему.
|
||
|
||
Она является лишь механизмом хранения объектов.
|
||
|
||
Следовательно, Runtime не обладает собственной предметной ответственностью.
|
||
|
||
---
|
||
|
||
# Владение состоянием
|
||
|
||
Во время аудита был сформулирован основной архитектурный вопрос.
|
||
|
||
> Кто принимает решения относительно жизненного цикла TradeStreamState?
|
||
|
||
Ответ оказался однозначным.
|
||
|
||
Только один компонент системы.
|
||
|
||
```text
|
||
TradeStreamConsistencyController
|
||
```
|
||
|
||
Именно он:
|
||
|
||
- создаёт состояние;
|
||
- использует состояние;
|
||
- изменяет состояние;
|
||
- читает состояние;
|
||
- определяет момент возникновения нового состояния;
|
||
- определяет необходимость обращения к состоянию.
|
||
|
||
Никакой другой компонент системы этого не делает.
|
||
|
||
Следовательно, именно подсистема **Trade Stream Consistency** является единственным владельцем собственного состояния.
|
||
|
||
Runtime при этом владельцем состояния не является.
|
||
|
||
Он лишь временно хранил объект, полностью принадлежащий другой подсистеме.
|
||
|
||
С точки зрения Domain-Driven Design подобная ситуация означает нарушение принципа единственного владельца агрегата.
|
||
|
||
---
|
||
|
||
# Определение владельца инфраструктурного состояния
|
||
|
||
После завершения анализа было сформулировано главное архитектурное решение настоящего Build.
|
||
|
||
**Владельцем инфраструктурного состояния является не Runtime приложения, а сама подсистема Trade Stream Consistency.**
|
||
|
||
Это означает следующее.
|
||
|
||
Состояние должно располагаться рядом с компонентом, который:
|
||
|
||
- полностью определяет его жизненный цикл;
|
||
- изменяет его;
|
||
- гарантирует его корректность;
|
||
- несёт ответственность за его согласованность.
|
||
|
||
Таким компонентом является исключительно `TradeStreamConsistencyController`.
|
||
|
||
Поэтому инфраструктурное хранилище должно быть частью той же самой подсистемы.
|
||
|
||
Именно это решение полностью соответствует принципу локального владения состоянием, используемому в профессиональных распределённых системах обработки рыночных данных.
|
||
|
||
---
|
||
|
||
# Почему Trade Runtime был удалён
|
||
|
||
Важно понимать, что удаление Trade Runtime не означает отказ от идеи инфраструктурного слоя.
|
||
|
||
Наоборот.
|
||
|
||
Build 060.20 оказался необходимым промежуточным этапом развития архитектуры.
|
||
|
||
Именно благодаря выделению Runtime стало очевидно, что:
|
||
|
||
- бизнес-логика уже полностью отделена от хранения состояния;
|
||
- само состояние является самостоятельной инфраструктурной сущностью;
|
||
- оставалось лишь определить её истинственного владельца.
|
||
|
||
После проведения аудита стало понятно, что универсальный Runtime Registry является избыточной абстракцией.
|
||
|
||
Он не предоставляет собственной предметной функциональности.
|
||
|
||
Он лишь дублирует ответственность будущего специализированного хранилища.
|
||
|
||
Поэтому Build 060.20.1 удаляет универсальный Runtime Registry и заменяет его специализированным компонентом, принадлежащим подсистеме Consistency.
|
||
|
||
Это не изменение поведения системы.
|
||
|
||
Это уточнение архитектурных границ ответственности.
|
||
|
||
---
|
||
|
||
# Новая модель владения состоянием
|
||
|
||
После завершения архитектурного аудита была утверждена новая схема сопровождения состояния Trade Stream.
|
||
|
||
Архитектура приобрела следующий вид.
|
||
|
||
```text
|
||
Trade Recovery
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
Trade Stream Consistency
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
TradeStreamStateStore
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
TradeStreamState
|
||
```
|
||
|
||
В данной модели отсутствуют лишние инфраструктурные уровни.
|
||
|
||
Каждый компонент обладает собственной предметной ответственностью.
|
||
|
||
---
|
||
|
||
# Разделение ответственности компонентов
|
||
|
||
## TradeStreamConsistencyController
|
||
|
||
Контроллер остаётся центральной точкой проверки непрерывности потока сделок.
|
||
|
||
Он отвечает за:
|
||
|
||
- получение состояния торгового инструмента;
|
||
- проверку поступающих сделок;
|
||
- обнаружение дубликатов;
|
||
- обнаружение нарушения последовательности;
|
||
- обнаружение конфликтующих сообщений.
|
||
|
||
При этом контроллер больше не владеет состоянием непосредственно.
|
||
|
||
Он работает исключительно через специализированное хранилище.
|
||
|
||
---
|
||
|
||
## TradeStreamStateStore
|
||
|
||
Build 060.20.1 вводит новый инфраструктурный компонент.
|
||
|
||
```text
|
||
TradeStreamStateStore
|
||
```
|
||
|
||
Данный компонент становится единственным владельцем объектов `TradeStreamState`.
|
||
|
||
Его ответственность строго ограничена хранением состояния.
|
||
|
||
Store:
|
||
|
||
- создаёт состояние при первом обращении;
|
||
- возвращает существующее состояние;
|
||
- удаляет состояние;
|
||
- очищает внутреннее хранилище;
|
||
- не содержит бизнес-логики проверки последовательности.
|
||
|
||
Store не знает:
|
||
|
||
- что такое пропуск сделок;
|
||
- что такое дедупликация;
|
||
- как работает Recovery;
|
||
- какие проверки выполняет Consistency Controller.
|
||
|
||
Подобное разделение полностью соответствует принципу Single Responsibility Principle.
|
||
|
||
---
|
||
|
||
## TradeStreamState
|
||
|
||
Класс `TradeStreamState` остаётся неизменным.
|
||
|
||
Он продолжает отвечать исключительно за состояние одного торгового инструмента.
|
||
|
||
В частности, он хранит:
|
||
|
||
- последний обработанный Trade ID;
|
||
- окно обнаружения дубликатов;
|
||
- историю последних сделок;
|
||
- внутреннее состояние проверки последовательности.
|
||
|
||
Build 060.20.1 не изменяет алгоритмы данного класса.
|
||
|
||
Изменяется исключительно способ владения экземплярами.
|
||
|
||
---
|
||
|
||
# Почему Store располагается внутри Consistency
|
||
|
||
Во время проектирования рассматривались два варианта размещения нового компонента.
|
||
|
||
## Вариант 1
|
||
|
||
```text
|
||
runtime/
|
||
|
||
trade_stream_state_store.py
|
||
```
|
||
|
||
## Вариант 2
|
||
|
||
```text
|
||
consistency/
|
||
|
||
trade_stream_state_store.py
|
||
```
|
||
|
||
После анализа был выбран второй вариант.
|
||
|
||
Причины данного решения следующие.
|
||
|
||
Во-первых.
|
||
|
||
Store хранит исключительно состояние подсистемы Consistency.
|
||
|
||
Во-вторых.
|
||
|
||
Никакая другая подсистема Acquisition данным состоянием не пользуется.
|
||
|
||
В-третьих.
|
||
|
||
При дальнейшем развитии проекта аналогичные специализированные Store могут появиться и в других подсистемах.
|
||
|
||
Например:
|
||
|
||
```text
|
||
Quotes Feed
|
||
|
||
↓
|
||
|
||
QuoteStateStore
|
||
```
|
||
|
||
```text
|
||
Order Book Feed
|
||
|
||
↓
|
||
|
||
OrderBookStateStore
|
||
```
|
||
|
||
```text
|
||
Candles Feed
|
||
|
||
↓
|
||
|
||
CandleStateStore
|
||
```
|
||
|
||
Каждая подсистема будет самостоятельно владеть собственным состоянием.
|
||
|
||
Это значительно лучше соответствует принципу высокой связности (High Cohesion).
|
||
|
||
---
|
||
|
||
# Отказ от универсального Registry
|
||
|
||
Build 060.20 использовал универсальный Registry.
|
||
|
||
Подобная архитектура выглядела следующим образом.
|
||
|
||
```text
|
||
TradeStreamConsistencyController
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
TradeRuntimeRegistry
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
TradeStreamState
|
||
```
|
||
|
||
После проведения аудита данная схема была признана избыточной.
|
||
|
||
Причины отказа от Registry:
|
||
|
||
- отсутствовала собственная предметная ответственность;
|
||
- Registry не использовался другими подсистемами;
|
||
- Registry являлся универсальным контейнером без собственной бизнес-функции;
|
||
- существование отдельного Runtime создавало ложное впечатление владения состоянием приложения.
|
||
|
||
Поэтому Registry был полностью удалён.
|
||
|
||
Его функции были заменены специализированным `TradeStreamStateStore`.
|
||
|
||
---
|
||
|
||
# Изменения публичного API
|
||
|
||
Архитектурная коррекция практически не изменила внешний контракт подсистемы.
|
||
|
||
Основным изменением стала замена зависимости.
|
||
|
||
До Build 060.20.1:
|
||
|
||
```text
|
||
TradeStreamConsistencyController
|
||
|
||
↓
|
||
|
||
TradeRuntimeProtocol
|
||
```
|
||
|
||
После Build 060.20.1:
|
||
|
||
```text
|
||
TradeStreamConsistencyController
|
||
|
||
↓
|
||
|
||
TradeStreamStateStoreProtocol
|
||
```
|
||
|
||
Для вызывающего кода логика проверки сделок полностью сохранилась.
|
||
|
||
Изменился исключительно способ получения состояния.
|
||
|
||
Это позволило провести миграцию без изменения поведения системы.
|
||
|
||
---
|
||
|
||
# Изменённые файлы
|
||
|
||
В рамках Build 060.20.1 были изменены исключительно компоненты, относящиеся к сопровождению состояния подсистемы Trade Stream.
|
||
|
||
Бизнес-логика проверки последовательности сообщений при этом не изменялась.
|
||
|
||
---
|
||
|
||
## Новые файлы
|
||
|
||
Добавлены новые специализированные компоненты хранения состояния.
|
||
|
||
```text
|
||
src/market_data/acquisition/consistency/
|
||
|
||
trade_stream_state_store.py
|
||
|
||
trade_stream_state_store_protocol.py
|
||
|
||
trade_stream_state_store_exceptions.py
|
||
```
|
||
|
||
Данные файлы полностью заменяют прежнюю инфраструктурную реализацию Runtime Registry.
|
||
|
||
---
|
||
|
||
## Изменённые файлы
|
||
|
||
### Trade Stream Consistency Controller
|
||
|
||
```text
|
||
src/market_data/acquisition/consistency/
|
||
|
||
trade_stream_consistency_controller.py
|
||
```
|
||
|
||
Изменения:
|
||
|
||
- внедрена зависимость `TradeStreamStateStoreProtocol`;
|
||
- удалена зависимость `TradeRuntimeProtocol`;
|
||
- получение состояния выполняется через Store;
|
||
- публичное поведение контроллера полностью сохранено.
|
||
|
||
---
|
||
|
||
### Тесты Consistency Controller
|
||
|
||
```text
|
||
tests/unit/market_data/acquisition/consistency/
|
||
|
||
test_trade_stream_consistency_controller.py
|
||
```
|
||
|
||
Изменения:
|
||
|
||
- заменены фикстуры Runtime Registry;
|
||
- внедрён `TradeStreamStateStore`;
|
||
- обновлены проверки хранения состояния;
|
||
- подтверждено отсутствие изменения бизнес-поведения.
|
||
|
||
---
|
||
|
||
# Удалённые файлы
|
||
|
||
После завершения миграции универсальная Runtime-подсистема больше не использовалась.
|
||
|
||
Поэтому она была полностью удалена.
|
||
|
||
Удалены следующие файлы.
|
||
|
||
```text
|
||
src/market_data/acquisition/runtime/trade/
|
||
|
||
trade_runtime_registry.py
|
||
|
||
trade_runtime_protocol.py
|
||
|
||
trade_runtime_exceptions.py
|
||
```
|
||
|
||
Одновременно были удалены соответствующие модульные тесты.
|
||
|
||
```text
|
||
tests/unit/market_data/acquisition/runtime/trade/
|
||
|
||
test_trade_runtime_registry.py
|
||
```
|
||
|
||
После удаления выполнена полная проверка проекта.
|
||
|
||
Ни одного использования Runtime Registry в кодовой базе больше не осталось.
|
||
|
||
---
|
||
|
||
# Дополнительная архитектурная корректировка
|
||
|
||
Во время проведения миграции была обнаружена ещё одна преждевременная архитектурная абстракция.
|
||
|
||
Первоначальная версия `TradeStreamStateStore` содержала метод
|
||
|
||
```text
|
||
register()
|
||
```
|
||
|
||
а также исключение
|
||
|
||
```text
|
||
TradeStreamStateAlreadyExistsError
|
||
```
|
||
|
||
Подобный интерфейс был унаследован от удалённого Runtime Registry.
|
||
|
||
После дополнительного анализа было установлено, что специализированное хранилище состояния не является Registry.
|
||
|
||
Следовательно, операция регистрации объектов ему не требуется.
|
||
|
||
В результате были выполнены следующие изменения.
|
||
|
||
Удалены:
|
||
|
||
- метод `register()`;
|
||
- исключение `TradeStreamStateAlreadyExistsError`;
|
||
- вся связанная документация.
|
||
|
||
После этого публичный контракт Store был существенно упрощён.
|
||
|
||
---
|
||
|
||
# Итоговый контракт TradeStreamStateStore
|
||
|
||
После завершения Build публичный интерфейс хранилища состоит исключительно из операций сопровождения состояния.
|
||
|
||
```text
|
||
get_or_create()
|
||
|
||
↓
|
||
|
||
get()
|
||
|
||
↓
|
||
|
||
contains()
|
||
|
||
↓
|
||
|
||
remove()
|
||
|
||
↓
|
||
|
||
clear()
|
||
```
|
||
|
||
Подобный контракт соответствует типичной архитектуре специализированных State Store, используемых в высоконагруженных системах обработки потоковых данных.
|
||
|
||
---
|
||
|
||
# Изменения модульных тестов
|
||
|
||
Build 060.20.1 существенно усилил тестовое покрытие новой архитектуры.
|
||
|
||
Помимо обновления существующих тестов был создан отдельный набор тестов для самого хранилища состояния.
|
||
|
||
Добавлен новый файл.
|
||
|
||
```text
|
||
tests/unit/market_data/acquisition/consistency/
|
||
|
||
test_trade_stream_state_store.py
|
||
```
|
||
|
||
Покрыты следующие сценарии.
|
||
|
||
- создание пустого Store;
|
||
- создание нового состояния;
|
||
- повторное получение существующего состояния;
|
||
- независимость состояний разных символов;
|
||
- получение существующего состояния;
|
||
- отсутствие состояния;
|
||
- удаление состояния;
|
||
- удаление отсутствующего состояния;
|
||
- очистка Store;
|
||
- идемпотентность очистки;
|
||
- совместимость с Protocol;
|
||
- отсутствие побочных эффектов между символами.
|
||
|
||
В результате новый инфраструктурный компонент получил собственное независимое тестовое покрытие.
|
||
|
||
---
|
||
|
||
# Регрессионное тестирование
|
||
|
||
После завершения всех изменений была выполнена полная проверка подсистем, затронутых миграцией.
|
||
|
||
Успешно пройдены:
|
||
|
||
```text
|
||
Trade Stream State
|
||
|
||
13 passed
|
||
```
|
||
|
||
```text
|
||
Trade Stream Consistency
|
||
|
||
19 passed
|
||
```
|
||
|
||
```text
|
||
Trade Stream State Store
|
||
|
||
12 passed
|
||
```
|
||
|
||
```text
|
||
Trade Recovery
|
||
|
||
70 passed
|
||
```
|
||
|
||
Общий подтверждённый результат.
|
||
|
||
```text
|
||
102 passed
|
||
```
|
||
|
||
Ни одного изменения поведения бизнес-логики обнаружено не было.
|
||
|
||
Все изменения ограничились исключительно архитектурой владения состоянием.
|
||
|
||
---
|
||
|
||
# Подтверждённые архитектурные инварианты
|
||
|
||
По итогам Build 060.20.1 были окончательно закреплены архитектурные принципы сопровождения состояния подсистемы Trades Feed.
|
||
|
||
Данные инварианты считаются обязательными для всех последующих Build.
|
||
|
||
---
|
||
|
||
## 1. Владелец состояния определяется предметной областью
|
||
|
||
Инфраструктурное состояние принадлежит не уровню приложения и не Runtime.
|
||
|
||
Его владельцем является исключительно та подсистема, которая:
|
||
|
||
- создаёт состояние;
|
||
- изменяет его;
|
||
- принимает решения относительно его жизненного цикла.
|
||
|
||
В случае Trades Feed таким владельцем является подсистема **Trade Stream Consistency**.
|
||
|
||
---
|
||
|
||
## 2. Каждая подсистема владеет только собственным состоянием
|
||
|
||
Trade Stream Consistency не имеет доступа к состояниям других компонентов.
|
||
|
||
Аналогично другие подсистемы не должны использовать внутреннее состояние Trade Stream.
|
||
|
||
Таким образом обеспечивается независимость компонентов и отсутствие скрытых связей между ними.
|
||
|
||
---
|
||
|
||
## 3. Runtime приложения не является владельцем бизнес-состояния
|
||
|
||
Runtime отвечает исключительно за жизненный цикл компонентов приложения.
|
||
|
||
В его область ответственности могут входить:
|
||
|
||
- запуск сервисов;
|
||
- остановка сервисов;
|
||
- переподключение;
|
||
- планирование задач;
|
||
- контроль соединений;
|
||
- мониторинг.
|
||
|
||
Runtime не должен хранить внутреннее состояние отдельных предметных подсистем.
|
||
|
||
---
|
||
|
||
## 4. Специализированные State Store являются инфраструктурными компонентами своих подсистем
|
||
|
||
Каждая подсистема может иметь собственное специализированное хранилище состояния.
|
||
|
||
Например.
|
||
|
||
```text
|
||
Trade Stream Consistency
|
||
|
||
↓
|
||
|
||
TradeStreamStateStore
|
||
```
|
||
|
||
В дальнейшем аналогичный подход может использоваться и для других потоков рыночных данных.
|
||
|
||
Например.
|
||
|
||
```text
|
||
Quotes Feed
|
||
|
||
↓
|
||
|
||
QuoteStateStore
|
||
```
|
||
|
||
```text
|
||
Order Book Feed
|
||
|
||
↓
|
||
|
||
OrderBookStateStore
|
||
```
|
||
|
||
```text
|
||
Candles Feed
|
||
|
||
↓
|
||
|
||
CandleStateStore
|
||
```
|
||
|
||
При этом каждое хранилище остаётся частью своей предметной подсистемы.
|
||
|
||
---
|
||
|
||
## 5. Store не содержит бизнес-логики
|
||
|
||
`TradeStreamStateStore` отвечает исключительно за сопровождение жизненного цикла объектов состояния.
|
||
|
||
В нём отсутствуют:
|
||
|
||
- проверка последовательности;
|
||
- дедупликация;
|
||
- восстановление истории;
|
||
- обработка сообщений биржи;
|
||
- принятие каких-либо предметных решений.
|
||
|
||
Все подобные алгоритмы продолжают находиться в `TradeStreamConsistencyController` и `TradeStreamState`.
|
||
|
||
---
|
||
|
||
## 6. Composition Root остаётся единственной точкой композиции
|
||
|
||
Создание экземпляров компонентов производится только в Composition Root.
|
||
|
||
После Build 060.20.1 граф зависимостей становится проще.
|
||
|
||
```text
|
||
TradeStreamConsistencyController
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
TradeStreamStateStore
|
||
|
||
│
|
||
|
||
▼
|
||
|
||
TradeStreamState
|
||
```
|
||
|
||
При этом ни Store, ни State не знают о способе своего создания.
|
||
|
||
---
|
||
|
||
# Что сознательно не входит в Scope Build
|
||
|
||
Настоящий Build не изменяет архитектуру остальных подсистем Acquisition.
|
||
|
||
В частности, вне Scope остаются:
|
||
|
||
- WebSocket Runtime;
|
||
- Supervisor;
|
||
- Scheduler;
|
||
- Reconnect;
|
||
- Heartbeat;
|
||
- Runtime Commands;
|
||
- Runtime Events;
|
||
- Transport Messages.
|
||
|
||
Также Build не изменяет:
|
||
|
||
- Trade Recovery;
|
||
- REST Pipeline;
|
||
- Canonical Trade Model;
|
||
- REST Adapter;
|
||
- WebSocket Adapter;
|
||
- обработчики сообщений;
|
||
- механизм восстановления пропусков.
|
||
|
||
Все перечисленные компоненты продолжают работать без изменений.
|
||
|
||
---
|
||
|
||
# Заключение
|
||
|
||
Build 060.20.1 завершает архитектурную корректировку, начатую после Build 060.20.
|
||
|
||
Первоначальная реализация Runtime Registry успешно выполнила свою роль промежуточного этапа развития архитектуры.
|
||
|
||
Она позволила:
|
||
|
||
- отделить хранение состояния от бизнес-логики;
|
||
- подтвердить необходимость выделенного инфраструктурного слоя;
|
||
- провести полноценный архитектурный аудит;
|
||
- определить фактического владельца состояния.
|
||
|
||
По результатам аудита была сформирована окончательная модель сопровождения состояния Trade Stream.
|
||
|
||
Её ключевой принцип заключается в следующем.
|
||
|
||
> Инфраструктурное состояние принадлежит не уровню Runtime, а предметной подсистеме, которая им управляет.
|
||
|
||
Для Trades Feed такой подсистемой является **Trade Stream Consistency**.
|
||
|
||
В результате архитектура стала проще, более локализованной и лучше соответствует общей декомпозиции Dzentra.
|
||
|
||
---
|
||
|
||
# Итоги Build
|
||
|
||
В рамках Build 060.20.1 были выполнены следующие работы.
|
||
|
||
- проведён полный архитектурный аудит Build 060.20;
|
||
- определён единственный владелец инфраструктурного состояния;
|
||
- удалена преждевременная подсистема `TradeRuntimeRegistry`;
|
||
- внедрён специализированный `TradeStreamStateStore`;
|
||
- упрощён публичный контракт хранения состояния;
|
||
- удалены неиспользуемые абстракции (`register()` и `TradeStreamStateAlreadyExistsError`);
|
||
- обновлены существующие модульные тесты;
|
||
- создан полный набор тестов для `TradeStreamStateStore`;
|
||
- подтверждено отсутствие регрессий;
|
||
- подтверждена совместимость архитектуры с последующими Build 060.21–060.24.
|
||
|
||
Build **060.20.1** считается полностью завершённым.
|
||
|
||
Он фиксирует окончательную архитектуру владения инфраструктурным состоянием подсистемы **Trades Feed (Time & Sales)** и служит базой для перехода к следующему этапу — [Build 060.21 — Runtime Protocol Integration](build_060_21.md).
|