Weather Forecast
March 4, 2023

WeatherForecast. Dev.

Предисловие

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

Не смотря на свою банальность, в проекте используется база данных Postgres для хранения "предсказаний", более того предсказания кэшируются в базе данных Redis. Это типичная связка, "бд-кэш", используется для облегчения нагрузки на базу данных и ускорения ответа пользователю.

Исходный код всего проекта находится на GitHub. Я буду фиксировать код на состояние каждого поста в отдельных ветках. Код для этого поста находится в ветке dev.

Поехали

Посмотрим из чего состоит проект

DeployToProduction.WeatherForecast.App - ASP.NET Core приложение, которое использует только Razor-pages.

DeployToProduction.WeatherForecast.Core - библиотека с модельками

DeployToProduction.WeatherForecast.Data - библиотека описывающая абстракцию доступа к данным.

DeployToProduction.WeatherForecast.Data.Psql - библиотека с реализацией доступа к данным через базу данных Postgres.

Тут нужно поговорить подробнее. Я хотел бы отметить два момента:

  1. Данные для бизнеса - это ключевой актив. Работу с данными нужно организовывать тщательнейшим образом, сто раз всё продумать, сто раз всё проверить, сделать все возможные бэкапы, проверить, что бэкапы работают, максимально автоматизировать, чтобы избежать человеческий фактор, проверить автоматизацию... В общем вы поняли, данные - это серьезно.
  2. ORM - инструмент, который облегчает работу с данными на старте и многое скрывает от разработчика, в этом его и плюс и минус. Базы данных - это очень сложный инструмент и в устройстве работы конкретной базы данных в конкретном проекте придется разбираться, когда бизнес выйдет в свет (вырастит нагрузка, увеличится количество функционала, изменения требований посыпятся одним за одним). Поэтому, я считаю, стоит в пет-проектах потренироваться работать с базовым уровнем - SQL.

Создание схемы базы данных описывается в sql-файле:

Для выполнения этого sql используется библиотека DbUp, которая помогает с созданием и миграцией схем баз данных:

Это очень простой по сути подход, со 100% контролем происходящего - вы пишите SQL-скрипты создания всех объектов схемы БД и их последующую модификацию/миграцию. А библиотека DbUp обеспечит применение этих скриптов. Делает это она тоже довольно просто. В БД создается таблица schemaversions, в которую записываются все примененные скрипты. Таким образом каждый скрипт будет выполнен только один раз.

Ну и сам код работы с базой данных я не стал нагружать транзакциями, специфическими для Postgres конструкциями, а написал наиболее простой вариант, хоть и не корректный с точки зрения конкурентной записи в БД:

DeployToProduction.WeatherForecast.Data.Redis - библиотека с реализацией доступа к данным через кэш в Redis.

Кэширование в Redis я делаю с помощью паттерна "обертки":

Вернемся к основному приложению DeployToProduction.WeatherForecast.App и его запуску. Как вы поняли для запуска приложения нам понадобится Postgres и Redis. Их, конечно, можно установить в вашу систему, но так уже никто не носит. Для разворачивания подобных зависимостей сегодня используют Docker, с которым вы уже знакомы. Базового уровня "запустить контейнер из командной строки" вам будет достаточно. Необходимые команды есть в README.md:

Для подключения к базам данных вам нужно будет прописать ConnectionStrings в appsettings.Development.json:

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

Ну и конечно тесты. Без тестов нельзя. Логика у нас тривиальная и не требует юнит-тестов. А вот написание интеграционных и UI тестов показать хочется, потому что часто это дело кажется сложным и откладывается на потом, а потом уже поздно. Юнит тесты помогают держать дизайн кода чистым, а интеграционные тесты помогают держать чистой архитектуру. Поэтому тесты нужно писать сразу.

Для тестирования работы с базами данных я использую тот же Docker, но с помощью библиотеки Testcontainers. (Да, я хотел показать ещё один плюс от владения инструментом Docker)

DeployToProduction.WeatherForecast.Data.Psql.IntegrationTests

DeployToProduction.WeatherForecast.Data.Redis.IntegrationTests

Код тестов я специально оставил примитивным и с повторениями, чтобы было проще в нем разобраться. В боевом проекте задача по созданию тестового контейнера выносится в базовый класс, и код теста остаётся чистеньким.

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

При запуске этих тестов вы можете заметить, как в приложении Docker Desktop создаются и удаляются контейнеры из ваших тестов + 1 вспомогательных контейнер:

DeployToProduction.WeatherForecast.App.UITests - тесты UI с помощью Selenium.

Автоматизировать запуск проекта ASP.NET из тестов - задача не тривиальная, но наиболее простым способом решается с помощью Docker-a и Docker Compose. И вернемся мы к этому вопросу, когда будет говорить о контейнеризации нашего приложения. А пока, я вам предлагаю вручную запустить проект без отладки (предварительно стартанув контейнеры для разработки) и потом запустить тест.

На этом наше знакомство с проектом завершено. Далее мы запустим проект в Selectel с управляемыми базами данных Postgres и Redis.