Зачем всё так сложно: постановка и архитектура

от автора

Постановка и бизнес-процесс

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

Что необходимо для выполнения основной задачи

  1. Список участников с номерами и планируемым временем старта (для формирования протокола).

  2. Устройства с приложением для фиксации времени старта и финиша по номерам участников.

Роли в рамках задачи

  • Организатор — работа со списком участников: добавление, присвоение номеров, назначение времени старта.

  • Судья — фиксация старта, финиша, отказа от участия или происшествия.

  • Наблюдатель (зритель) — просмотр списка участников и их статуса.

Процесс и его основные этапы

  1. До даты проведения

    • Добавить информацию о соревновании: условия, маршрут, категории.

    • Заполнить список участников (предварительная регистрация / импорт).

    • Указать планируемое время старта для каждого участника.

  2. При проведении, до старта

    • Присвоить номера участникам, которые прибыли на место.

    • Добавлять новых участников и определять для них плановое время старта (если разрешена регистрация в день соревнования).

  3. Во время проведения

    • Контролировать появление участников на старте в соответствии с плановым временем.

    • Отмечать фактическое время старта.

    • Отмечать фактическое время финиша.

    • Фиксировать отказ от участия после старта (вместе с временем события).

    • Присваивать номера опоздавшим участникам и назначать им новое плановое время старта.

    • При необходимости регистрировать новых участников прямо во время соревнования.

  4. После проведения

    • Зафиксировать итоговые результаты в протоколе.

Части процесса

Части процесса

Детализация получилась заметно объёмнее первоначальной формулировки задачи, но она хорошо показывает, сколько функций необходимо обеспечить для реального использования. В дальнейшем информации станет ещё больше, когда мы начнём рассматривать отдельные функции и технические решения.

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

Обязательные требования

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

  2. Фиксация событий должна быть возможна при нестабильном соединении — данные не должны теряться.

  3. Необходимо вести лог событий, поступающих от судей, и обеспечивать его просмотр.

  4. Приложение должно одинаково хорошо работать на мобильных телефонах, планшетах и десктопах.

Дополнительные требования

  1. Возможность заранее опубликовать информацию о соревновании для всех посетителей сайта.

  2. Возможность наблюдать за ходом соревнования в реальном времени (любой посетитель видит обновления данных об участниках).

  3. Возможность опубликовать итоговый протокол и другие материалы для всеобщего доступа.

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

Оценка работы «на местности»

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

Первое посещённое соревнование подтвердило все наши ожидания: роли и процесс полностью соответствовали описанному.

А вот второе соревнование проходило практически ночью, и тут возникли неожиданные нюансы:

  1. На финише номера финиширующих участников не были видны из-за темноты. Судья сначала фиксировал время, а потом, когда участник подъезжал ближе, заносил номер. Если бы финиш освещался так, чтобы номера хорошо читались, свет слепил бы спортсменов. Значит, порядок фиксации финиша может быть разным: либо сначала номер, потом время (как предполагалось изначально), либо сначала время, а затем номер.

  2. На старте тоже оказалось не всё просто: из-за темноты участники ориентировались на звук таймера, а не на время, отображаемое на экране.

Таким образом, мы должны дополнить обязательные требования:

  • На старте необходим обратный отсчёт с отображением таймера и звуковыми сигналами «3… 2… 1… Старт».

  • На финише нужно предусмотреть возможность сначала зафиксировать время, а затем ввести номер участника и отправить данные на сервер.

Связь на местности была ожидаемо неустойчивой, поэтому нам потребуется минимизировать объём передаваемых данных и обеспечить работу в офлайн-режиме.

Архитектура приложения

В качестве основы мы выбираем ASP.NET Core MVC на языке C#. Приставка «MVC» не должна вводить в заблуждение: SPA может обмениваться с сервером не только JSON-пакетами, но и готовыми HTML-фрагментами, которые вставляются прямо в контейнеры на странице. Контроллеры у нас будут и те, что отдают HTML, и те, что возвращают JSON, — в зависимости от потребностей конкретной функции.

База данных — PostgreSQL, она пользуется заслуженной популярностью, особенно в последнее время.

Возможные варианты реализации UI:

  1. Классический MVC — генерация HTML на стороне сервера с помощью Razor-шаблонов и обработка форм через POST-запросы.

  2. SPA с генерацией HTML в браузере — обмен данными с сервером в формате JSON и использование одного из современных фреймворков (Angular, React, Vue.js).

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

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

  • Для кэширования статических компонентов UI можно использовать Service Worker.

  • Компоненты UI будут работать с хранилищем в браузере (например, localStorage), которое в свою очередь будет синхронизироваться с сервером.

  • Всю клиентскую часть логично оформить как SPA/PWA-приложение для более комфортной работы на мобильных устройствах.

Технология PWA значительно упростила разработку приложений, работающих на разных платформах: нам не нужно писать «родные» приложения под каждую ОС, достаточно сделать адаптивную вёрстку и убрать элементы интерфейса браузера. С развитием Web API можно делать то, что раньше казалось невозможным (например, работать с USB/Bluetooth-устройствами или даже обновлять прошивки прямо из браузера). А если возможностей стандартных HTML-элементов не хватает, всегда можно использовать Inline SVG, Canvas или даже 3D-рендеринг.

Взаимодействие между элементами приложения

Взаимодействие между элементами приложения

Взаимодействие между элементами приложения

UI-компоненты обеспечивают навигацию, отображение и редактирование данных, обращаясь к хранилищу данных. Это всё, что нужно для SPA.

Хранилище данных работает следующим образом:

  • При запросе данных оно пытается обратиться к серверу (если есть связь) для получения актуальной информации, сохраняет ответ в localStorage и возвращает данные компонентам.

  • Если связи нет, хранилище возвращает данные из localStorage.

  • При получении команды на изменение данных хранилище сначала сохраняет изменения в localStorage, а затем инициирует отправку на сервер. Если сервер недоступен, отправка откладывается и повторяется при появлении соединения. Конфликты (одновременные правки от разных судей) — вопрос, который будем решать уже на уровне сервера; на этапе клиентского прототипа мы отложим эту тему.

Service Worker загружает с сервера компоненты, код хранилища, стили и другой статический контент, сохраняет их в кэше, а также реализует логику обновления кэшированного контента — это необходимо для работы PWA.

Серверная MVC-часть занимается сериализацией и десериализацией данных и вызывает соответствующие методы сервисов для получения или изменения данных.

Сервисы реализуют бизнес-логику: чтение и сохранение моделей, расчёт показателей участников (время, место и т. д.).

Все основные данные хранятся в PostgreSQL.

Какие готовые решения предварительно планируем использовать

Определим базовый набор готовых компонентов, которые будем применять. Список будет дополняться по мере реализации, но на старте он выглядит так:

  1. ASP.NET Core MVC — платформа для веб-приложения.

  2. Npgsql — провайдер для доступа к PostgreSQL из .NET.

  3. Vue.js — UI-фреймворк для построения компонентов. Он выбран как наиболее простой для встраивания, с отличной документацией и экосистемой. Эксперимент начинался около трёх лет назад, поэтому используется Vue 2 и соответствующее ему официальное хранилище Vuex; для современных проектов можно рассмотреть Pinia, но в рамках эксперимента это не принципиально.

  4. Vue Router — официальный маршрутизатор для построения SPA.

  5. RequireJS — библиотека для асинхронной загрузки скриптов и компонентов. Возможно, сегодня она не так актуальна (появилась нативная модульность в JS, сборщики типа Webpack), однако её применение в нашем эксперименте — осознанный шаг. Мы посвятим RequireJS отдельный разговор, в котором разберём механизмы работы модулей и альтернативные подходы.

  6. System.Text.Json — встроенный в .NET механизм работы с JSON. Раньше безоговорочным стандартом был Newtonsoft.Json, но теперь платформенный инструмент вполне успешно конкурирует с ним.

Да, в этом списке нет Entity Framework Core и Docker. Сознательно оставляем их «за бортом», чтобы сфокусироваться на минимально необходимом наборе технологий. Работать будем напрямую с ADO.NET и без контейнеризации — попробуем справиться пока без них.


В следующей статье мы перейдём к практической части: начнём с реализации пользовательского интерфейса. Создадим работающую в браузере заглушку с локальными данными, которая позволит «пощупать» внешний вид и поведение будущего приложения.

ссылка на оригинал статьи https://habr.com/ru/articles/1070910/