Время от времени я создаю реальное приложение (демо), чтобы изучить новый фреймворк или исследовать некоторые различные способы архитектуры приложения.
После экспериментов с несколькими фреймворками для реализации фронтенда, на этот раз я решил создать бэкенд. Для этого я использовал C# .Net.
Мой код можно найти здесь
В последние годы я активно использовал этот стек, и в этот раз, помимо экспериментов, я стремился создать чистый эталон, на который я смогу ссылаться при создании будущих решений.
Основные вещи, которые мне нравятся при реализации приложений в реальном мире, — это чтение о лучших практиках и их элегантная реализация, а также эксперименты с некоторыми концепциями/библиотеками, которые могут помочь в этом.
Решение
Для решения я выбрал довольно традиционную чистую архитектуру с использованием .Net 6.
Решение состоит из следующих слоев:
- api (соединяет решение и определяет конечные точки api)
- ядро (содержит основную бизнес-логику)
- данные (содержит взаимодействие с БД)
- инфраструктура (общий код, который потенциально может быть использован в различных решениях).
И я использовал следующие функции:
- new WebApplication.CreateBuilder(args)
- пространства имен с привязкой к файлам
- глобальное использование
- Entity Framework Core с SQLite db
- serilog для протоколирования, интегрированный с информацией о приложении, включая мониторинг в реальном времени
- Hellang.Middleware.ProblemDetails для последовательного вывода ошибок
- sonarlint для сканирования кода
Обоснование выбора и ретроспектива
В оставшейся части этого поста я расскажу о том, какие решения я принял.
Наслоение приложений
-
Использование отдельных проектов для данной конкретной реализации не является обязательным в рамках данного приложения. Однако это позволяет более четко определить, где должны быть конкретные обязанности.
-
Api Layer: Я рассматривал возможность использования минимальных апи .Net 6. Однако я считаю, что в данный момент это еще слишком рано, поскольку им все еще не хватает возможностей (например, группировка api, проверка модели). Я мог бы использовать что-то вроде Carter, но он полагается на FluentValidation, которую мне всегда трудно отлаживать. Я предпочитаю что-то вроде этого, что легко отлаживать и понимать.
-
Я сомневался, стоит ли объединять слой Core и слой Data в один слой. Поскольку я использую Entity Framework в слое данных, основной слой (или, по крайней мере, разработчик) должен знать концепции EF. Преимущество нынешнего разделения в том, что легче проверить взаимодействие с базой данных (как показано здесь) и что сервисы в слое ядра легче тестировать, так как хранилище можно легко сымитировать).
Особенности
-
Мне нравится функция WebApplication.CreateBuilder(args), которая появилась в .Net 6. Проще просто иметь файл program.cs, в котором настраивается хост, сервисы и конвейер запросов, вместо того, чтобы иметь отдельный файл Startup. Для больших проектов я ожидаю, что файл program.cs захочется структурировать немного больше, так как в нем может стать трудно ориентироваться
-
файловые пространства имен: даже будучи небольшим, на мой взгляд, это огромное улучшение, которое появилось в .Net 6 в плане удобочитаемости. Лично я хотел бы даже иметь возможность перейти к «без пространств имен», просто взяв структуру папок и корневое пространство имен, определенное в файле csproj, в качестве пространства имен.
-
глобальное использование: Не вижу здесь особых преимуществ, во время разработки мне приходилось вручную перемещать вещи, которые обычно обрабатываются моей IDE.
-
serilog: Мне нравится serilog для протоколирования, однако интеграция с Application Insights ограничена протоколированием событий как событий или как трасс, что не позволяет протоколировать запросы как запросы в AI.
-
Hellang.Middleware.ProblemDetails действительно хорошо работает для меня. Он позволяет очень легко добавить глобальный обработчик исключений, который обеспечивает согласованные ответы для всех типов проблем, будь то технические или функциональные, и хорошо работает с ответом на детали проблемы ApiController по умолчанию .Net для проверки модели.
-
sonarlint для сканирования кода: Я считаю, что это полезно в основном для поддержания единого стиля кода в вашем проекте (вместе с другими конфигурациями в .editorconfig).
Заключение
Я могу порекомендовать каждому создать приложение для реального мира. Это действительно побуждает вас глубже погрузиться в язык/фреймворк, чем то, что вы могли бы сделать в типичном учебнике по созданию приложений.
Если вы лучше знакомы с языком/фреймворком, это позволяет вам экспериментировать с архитектурами, с которыми вы менее знакомы.
Кроме того, если вы, как и я, любите решать головоломки, ваше время будет потрачено с большей пользой, чем на решение судоку ;).
Если посмотреть конкретно на эту реализацию на C# .Net, это может помочь вам подумать о том, как практически структурировать ваше приложение