26 KiB
Build 060.21 — Runtime Integration Contracts
Архитектурное обоснование
Назначение документа
Данный документ фиксирует архитектурные решения, принимаемые перед началом реализации Build 060.21 — Runtime Protocol Integration.
Build 060.20.1 завершил важнейший этап архитектурной декомпозиции подсистемы Trades Feed.
В результате архитектурного аудита было принято решение перенести владение инфраструктурным состоянием проверки согласованности потока сделок (Trade Stream Consistency) из общего Runtime Registry в специализированное хранилище состояний:
TradeStreamStateStore
Тем самым Runtime окончательно перестал владеть состоянием предметной области.
После завершения данного этапа стало возможным провести повторный аудит уже всей подсистемы получения сделок в контексте полной архитектуры Dzentra.
Основной целью Build 060.21 является определение архитектурных контрактов взаимодействия между уже реализованными подсистемами без изменения их ответственности.
Именно этот Build завершает проектирование слоя Runtime и подготавливает основу для его прикладной реализации в последующих этапах.
Предпосылки Build 060.21
К началу данного Build в проекте уже реализованы практически все фундаментальные компоненты подсистемы получения сделок.
Независимо друг от друга существуют:
WebSocket Runtime
WebSocket Adapter
Trades Feed
Trade Stream Consistency
Trade Recovery
Каждая из перечисленных подсистем имеет собственную область ответственности, собственный публичный API и полностью покрыта модульными тестами.
При этом отсутствует единый слой интеграции между транспортной инфраструктурой и предметной областью получения рыночных данных.
Именно отсутствие такого слоя не позволяет перейти к реализации полноценного жизненного цикла получения Trade Stream.
Цель Build 060.21
Build 060.21 не создаёт нового поведения системы.
Он не добавляет:
- новые алгоритмы;
- новые модели;
- новые механизмы обработки данных.
Его задача значительно более фундаментальна.
Build формализует публичные контракты взаимодействия между уже существующими подсистемами.
После завершения этапа каждая подсистема будет взаимодействовать исключительно через утверждённые Protocol.
Это позволит:
- полностью устранить риск циклических зависимостей;
- изолировать Runtime от бизнес-логики получения данных;
- обеспечить независимое тестирование компонентов;
- подготовить систему к дальнейшей реализации Runtime Service.
Место Build 060.21 в общей дорожной карте
Развитие подсистемы Trades Feed выполняется последовательно.
060.18
Trade Stream Consistency
↓
060.19
Trade Recovery
↓
060.20
Trade Runtime (первая архитектура)
↓
060.20.1
Перенос владельца состояния
↓
060.21
Runtime Integration Contracts
↓
060.22
Trade Runtime Service
↓
060.23
Acquisition Integration
↓
060.24
Reconnect & Runtime Recovery
↓
060.25
Integration & Regression
↓
060.26
Final Documentation
Каждый этап вводит только один новый архитектурный уровень.
Именно это позволяет сохранять стабильность системы на протяжении всей миграции.
Архитектурный результат Build 060.20.1
После завершения предыдущего этапа архитектура приобрела следующий вид.
Trade
│
▼
TradeStreamConsistencyController
│
▼
TradeStreamStateStore
│
▼
TradeStreamState
При этом Runtime полностью перестал владеть инфраструктурным состоянием.
Это решение соответствует общей архитектуре Dzentra.
Каждый модуль отвечает исключительно за собственную область ответственности.
Никакие инфраструктурные компоненты не владеют состоянием предметной области.
Что остаётся нерешённым
Несмотря на завершённую декомпозицию подсистем Consistency и Recovery, между Runtime и Trades Feed по-прежнему отсутствует архитектурный слой взаимодействия.
На сегодняшний день Runtime существует как полностью самостоятельная транспортная подсистема.
Trades Feed также существует как самостоятельная подсистема получения рыночных данных.
Однако отсутствует формализованный контракт, определяющий:
- каким образом Feed использует Runtime;
- каким образом Runtime предоставляет свои возможности;
- где проходит граница ответственности между транспортной инфраструктурой и бизнес-логикой получения сделок.
Именно устранение этой неопределённости является предметом Build 060.21.
Основной архитектурный принцип
В ходе архитектурного аудита было принято ключевое решение, которое определяет всю дальнейшую разработку Runtime.
Runtime остаётся полностью инфраструктурным слоем.
Это означает:
Runtime предоставляет инфраструктурные возможности.
Runtime не управляет предметной областью.
Runtime ничего не знает о сделках.
Runtime ничего не знает о свечах.
Runtime ничего не знает о котировках.
Runtime ничего не знает о механизмах проверки последовательности сообщений.
Runtime ничего не знает о восстановлении пропусков.
Все знания о предметной области остаются внутри подсистем Market Data Acquisition.
Именно это решение становится фундаментом всех последующих Build.
Почему Runtime не должен зависеть от Acquisition
На первый взгляд может показаться естественным сделать Runtime частью Trades Feed.
Однако подобное решение приводит к нарушению слоистой архитектуры.
Рассмотрим зависимости.
Правильное направление выглядит следующим образом:
Trades Feed
│
▼
Runtime Protocol
│
▼
Runtime Implementation
То есть предметная область использует инфраструктуру.
Но никогда наоборот.
Если же Runtime начнёт зависеть от Feed, получится следующая схема:
Runtime
│
▼
Trades Feed
В этом случае инфраструктура начинает знать о прикладной области.
Позже Runtime неизбежно начнёт содержать:
- обработку Trade;
- обработку Quote;
- обработку Candles;
- обработку Recovery;
- обработку Consistency.
Фактически Runtime превратится во второй Acquisition Layer.
Подобное решение противоречит принципу Single Responsibility и разрушает возможность повторного использования Runtime другими потоками данных.
Архитектурная роль Runtime
После завершения Build 060.21 Runtime окончательно получает следующую ответственность.
Runtime отвечает исключительно за:
• жизненный цикл WebSocket;
• транспортные подключения;
• отправку команд;
• получение транспортных сообщений;
• переподключение;
• heartbeat;
• генерацию инфраструктурных событий.
Runtime не принимает решений относительно содержимого сообщений.
Runtime не знает, что именно передаётся через WebSocket.
Для него существует лишь поток транспортных данных.
Архитектурная роль Trades Feed
В отличие от Runtime, Trades Feed отвечает исключительно за предметную область получения сделок.
Именно здесь сосредоточена логика:
- подписки на поток сделок;
- обработки транспортных сообщений;
- преобразования сообщений в каноническую модель;
- проверки последовательности;
- восстановления пропусков;
- передачи данных в следующие уровни системы.
Таким образом Runtime предоставляет инфраструктуру, а Feed определяет, каким образом эта инфраструктура используется.
Новый слой интеграции
Для устранения прямых зависимостей вводится отдельный слой интеграционных контрактов.
После Build 060.21 взаимодействие будет выглядеть следующим образом.
Runtime
Runtime Protocol Layer
▲
│
│
Trades Runtime Adapter
▲
│
│
Trades Feed
Feed зависит исключительно от публичных Protocol.
Runtime также реализует только Protocol.
Ни одна сторона не знает о внутреннем устройстве другой.
Какие Protocol должны появиться
После архитектурного анализа становится очевидно, что существующих Protocol недостаточно.
В настоящий момент имеются лишь транспортные контракты.
WebSocketTransportProtocol
WebSocketSessionProtocol
WebSocketSubscriptionManagerProtocol
Они описывают низкоуровневые механизмы работы WebSocket.
Но они ничего не говорят о жизненном цикле Runtime как сервиса.
Следовательно требуется следующий уровень абстракции.
Runtime Service Protocol
Главным новым контрактом становится Runtime Service Protocol.
Именно он описывает полный жизненный цикл Runtime.
Примерный набор операций выглядит следующим образом.
connect()
disconnect()
subscribe()
unsubscribe()
send()
is_connected()
connection_state()
Обращает на себя внимание важная особенность.
Все перечисленные методы относятся исключительно к транспортной инфраструктуре.
Ни один из них не содержит понятий:
- Trade;
- Quote;
- Candle;
- Recovery;
- Consistency.
Тем самым сохраняется полная независимость Runtime.
Runtime Event Protocol
Следующим уровнем становятся инфраструктурные события.
На сегодняшний день существуют отдельные Event-модели.
Однако отсутствует единый контракт их использования.
После Build 060.21 Runtime публикует только инфраструктурные события.
Например:
Connected
Disconnected
ReconnectStarted
ReconnectFinished
HeartbeatTimeout
TransportError
Получатель сам принимает решение, что делать с этими событиями.
Runtime ничего не знает о реакции системы.
Runtime Command Protocol
Аналогичным образом формализуется слой команд.
Вместо непосредственного вызова внутренних механизмов Runtime вводится единый командный контракт.
Например:
ConnectCommand
DisconnectCommand
SubscribeCommand
UnsubscribeCommand
ShutdownCommand
Все команды являются транспортными.
Они не содержат бизнес-логики.
Runtime Message Flow
После завершения Build поток взаимодействия становится полностью линейным.
Trades Feed
│
▼
Runtime Service Protocol
│
▼
Runtime
│
▼
WebSocket
│
▼
Exchange
Обратный поток строится аналогичным образом.
Exchange
│
▼
Runtime
│
▼
Runtime Events
│
▼
Trades Feed
│
▼
Consistency
│
▼
Recovery
Каждый уровень отвечает только за собственную часть обработки.
Никакие слои не пересекают границы ответственности.
Build Scope
В рамках Build 060.21 производится исключительно интеграция Runtime Protocol Layer.
Изменения не затрагивают:
- Recovery;
- Consistency;
- Validation;
- Runtime Supervisor;
- Reconnect;
- Scheduler;
- Heartbeat.
Все перечисленные компоненты продолжают существовать в прежнем виде.
Изменяется исключительно способ их последующего подключения к Runtime.
План реализации Build 060.21
Работы выполняются небольшими независимыми этапами.
Этап 060.21.1
Аудит существующих Runtime Protocol.
Проверка:
- websocket_protocol.py;
- runtime_commands.py;
- runtime_events.py.
Этап 060.21.2
Расширение Runtime Protocol Layer.
Добавляются отсутствующие инфраструктурные контракты.
Этап 060.21.3
Создание Runtime Service Protocol.
Появляется единый контракт взаимодействия с Runtime.
Этап 060.21.4
Интеграция существующих компонентов Runtime через новые Protocol.
Без изменения поведения.
Этап 060.21.5
Полный прогон Runtime Unit Tests.
Подтверждение отсутствия регрессии.
Ожидаемый результат
После завершения Build 060.21 архитектура Runtime приобретает окончательный вид.
Acquisition Layer
Trades Feed / Quotes Feed / OHLC Feed
│
│
▼
Runtime Service Protocol
│
▼
┌────────────────────────────┐
│ Runtime Layer │
│ │
│ Commands │
│ Events │
│ Session │
│ Transport │
│ Subscription Manager │
└────────────────────────────┘
│
▼
Exchange Transport
Все последующие Build будут использовать именно этот публичный слой.
Никаких дополнительных прямых зависимостей от Runtime больше вводиться не будет.
Архитектурные гарантии после Build 060.21
После завершения данного этапа система получает следующие гарантии.
1. Инверсия зависимостей полностью соблюдается
Ни один инфраструктурный компонент не знает о предметной области.
Runtime не импортирует:
- Trades Feed;
- Quotes Feed;
- Candles Feed;
- Recovery;
- Consistency.
2. Runtime становится полностью переиспользуемым
Любой поток данных сможет использовать Runtime без модификации его кода.
Например:
Trades Feed
Quotes Feed
OHLC Feed
Order Book Feed
Funding Feed
Index Feed
Все они будут работать через одинаковый Runtime Service Protocol.
3. Runtime становится тестируемым независимо
Все Runtime Unit Tests могут запускаться без:
- Feed;
- Acquisition;
- Exchange Adapter;
- Recovery.
Тестируется исключительно инфраструктурное поведение.
4. Feed становится независимым от реализации Runtime
Trades Feed знает только публичный контракт Runtime.
Следовательно Runtime можно заменить другой реализацией без изменения Feed.
Например:
Current WebSocket Runtime
↓
Future FIX Runtime
↓
Future gRPC Runtime
↓
Future Simulator Runtime
Feed останется неизменным.
5. Build 060.22 становится локальным
Следующий Build будет посвящён реализации Runtime Service.
Поскольку интерфейсы уже определены в Build 060.21, изменения затронут только внутреннюю реализацию Runtime.
Публичные контракты останутся неизменными.
Это существенно снижает риск регрессии.
Итог
Build 060.21 завершает формирование архитектурного слоя Runtime Protocol Integration.
В результате:
- Runtime окончательно отделяется от предметной области Market Data Acquisition;
- взаимодействие осуществляется исключительно через публичные Protocol;
- все транспортные зависимости становятся инвертированными;
- Runtime превращается в независимый инфраструктурный сервис;
- создаётся стабильная контрактная база для последующих Build 060.22–060.25 без необходимости дальнейшего изменения архитектуры Protocol Layer.
Приложение A. Эволюция архитектуры Runtime
До Build 060.21
Trades Feed
│
▼
WebSocketTransportProtocol
│
▼
Runtime Components
Commands
Events
Session
Transport
Недостатки данной схемы:
- отсутствует единая точка входа в Runtime;
- Feed вынужден знать набор отдельных инфраструктурных компонентов;
- невозможно заменить Runtime целиком;
- отсутствует единый сервисный контракт.
После Build 060.21
Trades Feed
│
▼
RuntimeServiceProtocol
│
┌────────────────┴────────────────┐
│ │
▼ ▼
Runtime Commands Runtime Events
│ │
└────────────────┬────────────────┘
▼
Runtime Implementation
│
▼
WebSocketTransportProtocol
│
▼
WebSocket
│
▼
Exchange
В новой архитектуре весь Runtime скрывается за единым публичным сервисным контрактом.
Trades Feed больше не зависит от внутренних компонентов Runtime.
Приложение B. Dependency Graph
После Build 060.21 зависимости приобретают следующий вид.
Trades Feed
│
▼
RuntimeServiceProtocol
│
▼
Runtime
│
├──────────────► Runtime Commands
│
├──────────────► Runtime Events
│
├──────────────► Session Protocol
│
├──────────────► Subscription Protocol
│
└──────────────► Transport Protocol
│
▼
Exchange Adapter
Ни одна зависимость не направлена обратно к Feed.
Приложение C. Build Boundary
В Build 060.21 разрешается изменять только следующие компоненты.
runtime/
websocket_protocol.py
runtime_commands.py
runtime_events.py
При необходимости допускается добавление новых файлов Protocol Layer.
Не допускается изменение:
consistency/
recovery/
validation/
processing/
analytics/
storage/
Также не изменяются:
Trades Feed
Recovery Controller
Consistency Controller
Exchange Adapter
Их интеграция будет выполняться на следующих этапах Roadmap.
Приложение D. Следующие этапы
После завершения Build 060.21 дальнейшая последовательность работ выглядит следующим образом.
060.22
Runtime Service Integration
↓
060.23
Acquisition Integration
↓
060.24
Reconnect & Runtime Recovery
↓
060.25
Integration & Regression
↓
060.26
Final Documentation
Таким образом Build 060.21 завершает исключительно проектирование и интеграцию контрактов Runtime Protocol Layer, создавая стабильную основу для последующей реализации Runtime Service без нарушения уже сформированной архитектуры подсистемы Market Data Acquisition.