Постановка и бизнес-процесс
Итак, проводится некое соревнование с раздельным стартом, и нам необходимо вести хронометраж. Для этого на старте и финише размещаются судьи, которые фиксируют время старта и финиша каждого участника. После завершения заезда все данные сводятся в итоговый протокол. Выглядит вполне просто и логично (пока что), но давайте погрузимся в детали.
Что необходимо для выполнения основной задачи
-
Список участников с номерами и планируемым временем старта (для формирования протокола).
-
Устройства с приложением для фиксации времени старта и финиша по номерам участников.
Роли в рамках задачи
-
Организатор — работа со списком участников: добавление, присвоение номеров, назначение времени старта.
-
Судья — фиксация старта, финиша, отказа от участия или происшествия.
-
Наблюдатель (зритель) — просмотр списка участников и их статуса.
Процесс и его основные этапы
-
До даты проведения
-
Добавить информацию о соревновании: условия, маршрут, категории.
-
Заполнить список участников (предварительная регистрация / импорт).
-
Указать планируемое время старта для каждого участника.
-
-
При проведении, до старта
-
Присвоить номера участникам, которые прибыли на место.
-
Добавлять новых участников и определять для них плановое время старта (если разрешена регистрация в день соревнования).
-
-
Во время проведения
-
Контролировать появление участников на старте в соответствии с плановым временем.
-
Отмечать фактическое время старта.
-
Отмечать фактическое время финиша.
-
Фиксировать отказ от участия после старта (вместе с временем события).
-
Присваивать номера опоздавшим участникам и назначать им новое плановое время старта.
-
При необходимости регистрировать новых участников прямо во время соревнования.
-
-
После проведения
-
Зафиксировать итоговые результаты в протоколе.
-
Детализация получилась заметно объёмнее первоначальной формулировки задачи, но она хорошо показывает, сколько функций необходимо обеспечить для реального использования. В дальнейшем информации станет ещё больше, когда мы начнём рассматривать отдельные функции и технические решения.
В дополнение к описанному процессу есть ряд важных требований.
Обязательные требования
-
На всех устройствах организаторов и судей должно быть синхронизировано время непосредственно перед началом соревнования.
-
Фиксация событий должна быть возможна при нестабильном соединении — данные не должны теряться.
-
Необходимо вести лог событий, поступающих от судей, и обеспечивать его просмотр.
-
Приложение должно одинаково хорошо работать на мобильных телефонах, планшетах и десктопах.
Дополнительные требования
-
Возможность заранее опубликовать информацию о соревновании для всех посетителей сайта.
-
Возможность наблюдать за ходом соревнования в реальном времени (любой посетитель видит обновления данных об участниках).
-
Возможность опубликовать итоговый протокол и другие материалы для всеобщего доступа.
Получился вполне приличный объём информации, а мы ещё ничего не начали реализовывать. Самое время ещё раз проверить все сформулированные требования, потому что вносить изменения имеет смысл именно на этом этапе, — когда начнётся проектирование и реализация, правки потребуют гораздо больших затрат.
Оценка работы «на местности»
После того как основная задача была сформулирована, мы решили подтвердить актуальность требований, понаблюдав за работой организаторов в реальных условиях.
Первое посещённое соревнование подтвердило все наши ожидания: роли и процесс полностью соответствовали описанному.
А вот второе соревнование проходило практически ночью, и тут возникли неожиданные нюансы:
-
На финише номера финиширующих участников не были видны из-за темноты. Судья сначала фиксировал время, а потом, когда участник подъезжал ближе, заносил номер. Если бы финиш освещался так, чтобы номера хорошо читались, свет слепил бы спортсменов. Значит, порядок фиксации финиша может быть разным: либо сначала номер, потом время (как предполагалось изначально), либо сначала время, а затем номер.
-
На старте тоже оказалось не всё просто: из-за темноты участники ориентировались на звук таймера, а не на время, отображаемое на экране.
Таким образом, мы должны дополнить обязательные требования:
-
На старте необходим обратный отсчёт с отображением таймера и звуковыми сигналами «3… 2… 1… Старт».
-
На финише нужно предусмотреть возможность сначала зафиксировать время, а затем ввести номер участника и отправить данные на сервер.
Связь на местности была ожидаемо неустойчивой, поэтому нам потребуется минимизировать объём передаваемых данных и обеспечить работу в офлайн-режиме.
Архитектура приложения
В качестве основы мы выбираем ASP.NET Core MVC на языке C#. Приставка «MVC» не должна вводить в заблуждение: SPA может обмениваться с сервером не только JSON-пакетами, но и готовыми HTML-фрагментами, которые вставляются прямо в контейнеры на странице. Контроллеры у нас будут и те, что отдают HTML, и те, что возвращают JSON, — в зависимости от потребностей конкретной функции.
База данных — PostgreSQL, она пользуется заслуженной популярностью, особенно в последнее время.
Возможные варианты реализации UI:
-
Классический MVC — генерация HTML на стороне сервера с помощью Razor-шаблонов и обработка форм через POST-запросы.
-
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.
Какие готовые решения предварительно планируем использовать
Определим базовый набор готовых компонентов, которые будем применять. Список будет дополняться по мере реализации, но на старте он выглядит так:
-
ASP.NET Core MVC — платформа для веб-приложения.
-
Npgsql — провайдер для доступа к PostgreSQL из .NET.
-
Vue.js — UI-фреймворк для построения компонентов. Он выбран как наиболее простой для встраивания, с отличной документацией и экосистемой. Эксперимент начинался около трёх лет назад, поэтому используется Vue 2 и соответствующее ему официальное хранилище Vuex; для современных проектов можно рассмотреть Pinia, но в рамках эксперимента это не принципиально.
-
Vue Router — официальный маршрутизатор для построения SPA.
-
RequireJS — библиотека для асинхронной загрузки скриптов и компонентов. Возможно, сегодня она не так актуальна (появилась нативная модульность в JS, сборщики типа Webpack), однако её применение в нашем эксперименте — осознанный шаг. Мы посвятим RequireJS отдельный разговор, в котором разберём механизмы работы модулей и альтернативные подходы.
-
System.Text.Json — встроенный в .NET механизм работы с JSON. Раньше безоговорочным стандартом был Newtonsoft.Json, но теперь платформенный инструмент вполне успешно конкурирует с ним.
Да, в этом списке нет Entity Framework Core и Docker. Сознательно оставляем их «за бортом», чтобы сфокусироваться на минимально необходимом наборе технологий. Работать будем напрямую с ADO.NET и без контейнеризации — попробуем справиться пока без них.
В следующей статье мы перейдём к практической части: начнём с реализации пользовательского интерфейса. Создадим работающую в браузере заглушку с локальными данными, которая позволит «пощупать» внешний вид и поведение будущего приложения.
ссылка на оригинал статьи https://habr.com/ru/articles/1070910/