Как большинство Java проектов выглядят изнутри
Меня зовут Аксёнов Вячеслав, я бэкенд разработчик и в последние годы пишу веб приложения на java/kotlin. За всю свою практику я встречался с различными системами как в продакшене, так и в пет проектах. Некоторые системы имели свои “велосипеды”, но большинство базировались на очень похожих технических решениях.
Основная идея этой статьи описать основные технические задачи, которые ставятся перед современными веб приложениями. А также перечислить те фреймворки и библиотеки, которые чаще всего используются для решения этих задач. Бонусом захватим немного инфраструктуры.
Таким образом новички, которые не знают, чего им ждать от корпоративной разработке или в каком фреймворке подтягивать свои навыки, смогут увидеть картину мира чуть шире и сделать правильный выбор.
Какие технические задачи бывают?
Для начала давайте разберем, какие самые распространенные проблемы и задачи ставятся перед современными веб приложениями. Ниже я привожу список самых популярных задач, с которыми приходится работать разработчику.
Маршрутизация запросов, построение слоя контроллера.
Написание сложной и ветвистой бизнес логики.
Работа с базами данных.
Работа с транспортом для сообщений.
Тестирование.
Статический анализ кода.
CI/CD.
Маршрутизация запросов / слой контроллера
Задачи, которые входят в этот слой - это направлять каждый http запрос на тот метод, который займется его обработкой. В это также входит описание модели данных, которая передается на вход, а также сериализация запроса и десериализация ответа.
На данный момент самым популярным фреймворком для построения web сервисов является Spring, а именно Spring Boot, который сразу имеет встроенный контейнер сервлетов tomcat
, либо netty
- в зависимости от того, какой набор конфигурации выбран.
Так что для описания эндпоинтов вашего приложения вам практически всегда, в 9 из 10 случаев, придется использовать аннотации @GetMapping
и @PostMapping
. В том единственном варианте из 10 за маршрутизацию будет отвечать библиотека, которая была написана внутри компании и будет делать то же самое, что и Spring Boot, только “по-своему”.
Раз практически везде используется Spring Boot, то де факто стандартом индустрии для сериализации и десериализации http запросов и ответов является библиотека Jackson
. Она также входит в зависимости Spring Boot и активно используется внутри.
Чтобы ее использовать, потребуется создать экземпляр ObjectMapper
и сконфигурировать его, если будет нужно. Имейте в виду, что в Spring Context уже будет инициализированный экземпляр, настроенный, как нужно Spring, так что используйте его осторожно.
Также иногда используют библиотеку от Google - GSON, принципиально она не отличается от Jackson
.
Написание сложной и ветвистой бизнес логики.
Выше мы уже выяснили, что стандартом индустрии по разработке web приложений на java является Spring. Это не значит, что вы не сможете встретить условный Javalin или Ktor, так что рассмотрим основную вещь, которую очень любят в Spring и так или иначе реализовывают в любом другом фреймворке. Этим подходом является паттерн dependency injection.
Если коротко, то dependency injection это про то, что вы написали отдельный кирпичик кода - класс и используете его в тех местах, где требуется логика этого кирпичика вместо написания новой.
Так что в любом проекте, в котором вы окажетесь, будет некий контекст, в котором будут храниться эти кирпичики кода, и наличие этого контекста никак не зависит от фреймворка, выбранного для разработки. Скажу по-секрету, что даже когда один из самых прогрессивных Европейских банков отказывается от Spring и разрабатывает веб сервисы на чистой Java, у них все равно есть контекст, в который закладываются все “сервисы”.
Работа с базой данных.
Никакое веб приложение не обходится без использования хранилища данных. Таким хранилищем может быть все что угодно - текстовый файл, кэш redis. Но чаще всего, конечно, используется база данных, опять же стандартом индустрии сейчас являются:
Postgresql (удобная, производительная, бесплатная).
Oracle (чуть менее удобная, производительная, имеет вендорный формат.
MongoDB (очень удобная для стартовой разработки ввиду нереляционности, крайне распространена в облачных решениях).
Для доступа к базе данных нужно иметь возможность открывать соединения, следить за открытыми потоками, выполнять sql запросы, заниматься конвертацией и тд.
В настоящее время большое распространение имеет подход ORM - Object-Relational Mapping. Чтобы покрыть весь спектр задач для хранения информации бд, нужно решать 4 вида операций (тот самый CRUD) - create, read, update, delete.
Самые популярные реализации этого подхода заключает в себе фреймворк - Hibernate
. Он способен генерировать sql запросы в зависимости от кода и сущностей, однако делает это не всегда оптимально.
Также мы не забыли, что стандартом индустрии является Spring Boot, для него также существует реализация ORM работы с бд - Spring Data JPA
. Она представляет собой обертку над Hibernate
, с которой можно работать на более высоком уровне абстракций. Она удобно конфигурится и даже позволяет писать запросы без sql вообще. Но если есть потребность написать raw sql и выполнить его, это также можно сделать.
И наконец, самый мощный инструмент, который предоставляет самое лучшее быстродействие, но фактически не реализует ORM идеологию - jdbcTemplate
. Его суть в выполнении сырых sql запросов. Но если написать поверх него свою логику конвертации и применять его для хранения сущностей в бд по логике ORM, то получится очень быстрый и кастомизируемый инструмент.
Работа с транспортом
В качестве транспорта для сообщений используют такие синхронные способы, как http запросы GET/POST. Для них используется либо RestTemplate
, который входит в список зависимостей Spring Boot, либо более новый и WebClient
.
Для асинхронных взаимодействий используются брокеры сообщений, самые популярные из которых - rabbitmq и kafka. В этой статье я не буду погружаться в их отличие друг от друга. Остановлюсь на способе интеграции с ними из кода - для этого используются модули Spring Boot, либо самописный “велосипед”, если речь идет про большую компанию. Самые популярные расширения для Spring Boot проекта - это spring-kafka и spring-boot-starter-amqp.
Тестирование
Тестирование - это неотъемлемая часть любой уважающей себя разработки. В наших реалиях если разработка ведется не сразу в TDD парадигме (Test Driven Development), то внутри команды устанавливается порог кода, который должен быть покрыт тестами.
Тесты пишутся в следующих форматах:
unit тесты - для тестирования берется отдельный класс или даже его метод.
интеграционные тесты - тестируется отдельный участок системы вместе с интеграцией с другими элементами. Например интеграционное тестирование процесса в сервисе и его работа с базой данных.
Сторонние библиотеки в тестах нужны для решения задач непосредственно тестирования, а также мокирования (эмуляция ответа какого-то сервиса или интеграции).
Для тестирования чаще всего используют junit 5
, TestNG
, kotest
(kotlin). Для мокирования стандартом java разработки является mockito, для kotlin - mockk
. Для тестирования Spring Boot приложений используется стартер spring-boot-starter-test
, который уже включает в себя все необходимые зависимости и умеет строить Spring Context для каждого теста.
Крайне редко бывают настолько сложные и витиеватые процессы, что для тестирования одного сценария нужно вызывать много эндпоинтов одного сервиса. В таком случае нужно быть готовым к тому, что вы столкнетесь с самописными “велосипедами”, такими как отдельное Spring Boot приложение, которое занимается вызовом эндпоинтов и тестированием основного тестируемого приложения.
Статический анализ
Суть статического анализа кода - это проверка кода на соответствие условиям - отсутствие дублирующего кода, покрытия тестами, соответствие код стайлу и тд.
Как правило для проверок соответствия код стайлу используются такие штуки, как “Линтеры”. По своей природе это те же самые плагины для gradle
, maven
. Обычно они запускаются автоматически в ходе настроенного пайплайна. Иногда нужно быть готовым, что нужно вызвать команду, которая отформатирует ваш код по настроенным в линтере правилам.
Для Java самыми популярными линтерами являются - Checkstyle
и SonarLint
. Для kotlin - ktlint
Для статического анализа, с подсказками и прочими полезными штуками в подавляющем большинстве проектов используется настроенный sonarqube. Для маленьких проектов - codacy или codeclimate. Я бы рекомендовал их использовать даже для пет проектов.
Однако не все проекты имеют выстроенные процессы по поддержанию чистоты кода. Это может происходить в силу различных причин - быстро изменяющийся проект, недостаточное количество времени у команды для выстраивания процессов.
CI/CD - Continuous Integration и Continuous Deployment - это процессы, без которых невозможно представить современную разработку. Можно запаковывать jar файлы руками и руками разворачивать их на серверах, но это увеличивает вероятность ошибок, вызванных человеческим фактором. Чтобы базовые инфраструктурные действия не вызывали большой головной боли, обычно используются скрипты для сборки и деплоя.
Как правило рядовым разработчикам приходится заниматься этим довольно редко, обычно это находится в зоне devops инженеров. Как правило скрипты выполняются в окружении Jenkins, либо Gitlab CI.
Сами скрипты представляют собой набор действий, которые должны быть выполнены для достижения той или иной цели. Самое сложное может быть в том чтобы понять, как связывается код внутри приложения и с деплоем. Для этого используются системы сборки. На данный момент для бэкенда существуют две самые популярные - maven
и gradle
. В 9 случаях из 10 это maven
, он довольно грубый, но функциональный и имеет большое количество плагинов. Также изредка встречается gradle
, он в свою очередь более свежий, но менее широко распространенный. По функционалу ничем не уступает maven
в большинстве моментов.
Вывод.
В этой статье мы рассмотрели основные технические моменты, которые приходится решать бэкенд разработчику в настоящее время. А также основные способы решения задач для каждого из этих технических направлений. Буду рад информации в комментариях о том - с помощью какого инструмента в своем проекте вы решаете задачу и полностью ли вы довольны этим инструментом.
Фото от Tracy Adams на Unsplash