Files
dzentra_bot/docs/migrations/build_060_20_1.md

1062 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.md — архитектурная спецификация Build.
- build_060_20.md — Engineering Migration Report предыдущего 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.21060.24.
Build **060.20.1** считается полностью завершённым.
Он фиксирует окончательную архитектуру владения инфраструктурным состоянием подсистемы **Trades Feed (Time & Sales)** и служит базой для перехода к следующему этапу — **Build 060.21 — Runtime Protocol Integration**.