От ограниченного контекста к микросервисам

Знание того, что должно делать наше программное обеспечение и какие проблемы оно должно решать, - это здорово, но само по себе это мало помогает нам в разработке эффективной модели.

Разделение обязанностей программного обеспечения на четко разделенные контексты позволяет нам видеть лес за деревьями во время разработки и создавать слабосвязанные, масштабируемые приложение. Кроме того, мы можем использовать эти ограниченные контексты в качестве основы для наших микросервисов.

Это часть серии статей, в которых я создаю программную систему для концептуального хедж-фонда с нуля. В первой части я оценил проект на бизнес-уровне и пришел к высокоуровневой модели нашей системы.

В этой части мы рассмотрим подробнее и рассмотрим уровень обслуживания модели, начав с основных функций системы, выполняемых торговым терминалом.

P.S. Моделирование - дело относительно субъективное, и я призываю вас оспаривать мои решения.

Обязанности

Для меня хорошее начало - определить обязанности торгового терминала. Давайте сосредоточимся на ее взаимоотношениях внутри системы изолированно.

Глядя на контекстную диаграмму (общий обзор системы), мы видим, что с торговым терминалом взаимодействуют 4 различных компонента / роли:

  • трейдер;
  • брокер;
  • Автотрейдер;
  • система мониторинга.

Чтобы определить обязанности, давайте начнем с рассмотрения основных / наиболее необходимых взаимодействий компонентов, из которых должны развиться определенные шаблоны.

Из этих взаимодействий мы можем определить конкретные обязанности торгового терминала. Мы можем сгруппировать их по направлению информационных потоков, что дает некоторую ясность в отношении наших моделей общения.

Мы знаем, что мы ожидаем от торгового терминала для всей системы и что требуется для этого, однако существует множество способов разделения ответственности. Знание только входов и выходов не является очень эффективной отправной точкой для разработки шаблонов коммуникации.

Случаи применения

Давайте разделим обязанности на поток конкретных действий, которые необходимы для выполнения задач - варианты использования.

Рассматривая один за другим варианты использования, мы видим разделение ответственности, поскольку очень мало действий повторяется через границы. Здесь начинают формироваться ограниченные контексты. Прежде чем обозначать каждый контекст как отдельную услугу, давайте рассмотрим действия более подробно.

У нас есть 2 повторяющихся действия: авторизация вызывающего / вызывающего при запросе действия и аутентификация нашего клиента при отправке запросов брокеру.

Безопасность и авторизация имеют решающее значение и будут рассмотрены более подробно, когда мы получим четкое представление о системе, которую хотим защитить.

Аутентификация наших клиентов, скорее всего, будет основана на токенах. Ни одна из обязанностей не может и не должна быть разделена как отдельные контексты.

Предоставление фида цен и информации об аккаунте в виде необработанных данных по сравнению с отображением их в пользовательском интерфейсе также являются почти идентичными вариантами использования, где отличается только последний шаг. Это хорошо отделяет наш будущий компонент пользовательского интерфейса от внутренней логики.

Сохранение логики котировок в ее собственном контексте имеет смысл, поскольку обработка потенциально тысяч отдельных подписок на поток цен может выиграть от масштабирования по оси Y.

В отличие от оси X и оси Z, которые состоят из запуска нескольких идентичных копий приложения, масштабирование по оси Y разбивает приложение на несколько различных служб. Каждая служба отвечает за одну или несколько тесно связанных функций . - Масштабный куб

Однако почти все, что касается информации о счете (маржа, капитал и т. Д.), Можно получить из баланса счета, списка заказов и цен активных позиций. Нет смысла запрашивать информацию об аккаунте у брокера с каждым тиком при подписке на фид цен. Мы могли бы использовать котировки для самостоятельного расчета той же информации и периодически проверять результаты у брокера.

Перед выполнением заказа мы должны убедиться, что он удовлетворяет требованиям управления рисками, чтобы учетная запись соответствовала установленным ограничениям в случае выполнения заказа. Это напомнило мне, что я упустил одну из основных обязанностей, которые мы сначала возложили на наш терминал, - автоматическое управление положением и счетом. Терминал должен контролировать открытые позиции и при необходимости вмешиваться.

Я чувствую взаимосвязь между предоставлением информации об аккаунте и мониторингом управления рисками, поскольку и то, и другое зависит от знания открытых позиций и их стоимости. Вернуться к доске для рисования…

Альтернативный вариант использования в основном касается исключительно управления рисками. Информация об учетной записи является лишь побочным продуктом расчетов и может быть передана необходимым сторонам. Это сокращает взаимодействие с внешней системой (брокером), поскольку мы можем основывать вычисления на списке заказов (который мы можем получить из службы исполнения) и ценовом потоке ( который уже обрабатывается службой рыночных каналов).

Компонент управления рисками по-прежнему требует баланса счета, валюты, кредитного плеча и некоторых других входных данных для формул. Это может быть получено, например, один раз в день, обеспечивая при этом, чтобы расчеты совпадали со всем, что на стороне брокера.

С помощью этой лучшей альтернативы нам удалось определить 4 четко разделенных ограниченных контекста: исполнитель, рыночный канал, управление учетной записью и пользовательский интерфейс. . Они охватывают основные обязанности торгового терминала, и каждая из них станет отдельной службой.

Обратите внимание, что я избавился от контекста ведения журнала. Ответственность за ведение журнала должна быть интегрирована в каждый компонент. Кроме того, существует множество отличных решений для управления журналами, поэтому нет необходимости изобретать велосипед с помощью нашего собственного сервиса.

Услуги

С четко обозначенными границами мы можем отобразить нашу диаграмму контейнера (уровень 2 модели C4), где каждый определенный нами ограниченный контекст представляет собой одну службу.

Контейнер - это что-то вроде серверного веб-приложения, одностраничного приложения, настольного приложения, мобильного приложения, схемы базы данных, файловой системы и т. Д. По сути, контейнер - это отдельно запускаемый / развертываемый блок (например, отдельное пространство процессов), который выполняет код или хранит данные . - Модель C4

Обратите внимание, что я назначил конкретные технологии только что созданным контейнерам (.NET Core и Vue.js). Это первоначальный прогноз, основанный на моем опыте, и его следует оценить перед тем, как сделать окончательный выбор и начать разработку.

Хотя я подключил службы друг к другу, представляя информацию, которой будет происходить обмен, мы еще не обсуждали средства связи между микросервисами. Поскольку это такая важная тема, особенно в нашем случае, когда информация должна передаваться быстро, я рассмотрю ее в отдельной статье.

Резюме

Изложив основные требования к нашей системе с помощью контекстной диаграммы бизнес-уровня, пришло время углубиться в нашу модель и определить конкретные компоненты, которые помогут нам достичь наших целей.

Мы увидели, как достичь более низкого уровня понимания нашей системы с помощью обязанностей, вариантов использования и ограниченных контекстов. Этот пошаговый процесс привел к четко разделенным услугам и лучшему пониманию системы, которую мы собираемся построить.

Нам еще предстоит обсудить специфику межсервисного взаимодействия (анализируется далее в части 3 этой серии), и мы не выяснили, как эффективно управлять данные в нашей системе. На эти и многие другие важные вопросы нужно будет ответить, прежде чем мы сможем уверенно приступить к программированию.

Предстоит обсудить множество интересных тем, и я надеюсь встретиться с вами по пути!