Сравнение JSP и VueJS
Споры о том, насколько SPA лучше или хуже проверенных серверных технологий, не утихают до сих пор. Сторонники SPA (React, Angular, VueJS) в один голос говорят насколько это просто и удобно. Сторонники серверных технологий (PHP, JSP, ASP) ничего не говорят, потому что их мало и они заняты разработкой. Из-за того, что оба подхода достаточно разные, то и сравнивать их очень сложно. Зачастую сравнение сваливается во вкусовщину, так как нет людей, которые бы разрабатывали как с помощью одних, так и с помощью других. И даже если такие уникумы находятся, никто в здравом уме не будет реализовывать сложную функциональность одновременно и на той, и на другой технологии. Кроме меня.
TL;TR Я смог разработать такой компонент без каких-либо сложностей.
Начало
Так получилось, что leosatdata.com написан с помощью JSP, а r2cloud-ui с помощью VueJS. И вот мне понадобилось реализовать компонент по отображению OpenAPI в обоих проектах. В этот момент возникла уникальная ситуация:
- Нужно реализовать абсолютно одинаковый компонент как в r2cloud-ui, так и в r2server.
- У него должен быть один и тот же дизайн - bootstrap4. Несмотря на то, что приложения разные, я решил сделать максимально похожий user experience. Это удобно по нескольким причинам: во-первых, достаточно знать один набор компонент, во-вторых, пользователи, вполне очевидно, будут использовать и то, и другое приложение.
Требования
Прежде, чем начать сравнивать фреймворки, я хотел бы описать требования:
- компонент должен быть не зависимым от приложения. Это прежде всего значит, что его можно встраивать не только в моё приложение, но и в любое другое.
- он должен отображать описание OpenAPI с помощью bootstrap4. Это описание должно быть максимально похожим на стандартный swagger-ui.
- (опционально) 80% покрытия тестами.
После того как были определены требования, я без проблем написал необходимый код. Результаты моих ощущений ниже.
Простота старта
JSP vs VueJS
Для JSP начало работы достаточно простое:
- создать стандартный maven проект
- положить описание в
/META-INF/tags
Однако, для VueJS старт очень запутанный. Я открыл официальный гид по созданию компонентов и увидел, что там рекомендуется начать с конфигурации rollup. Несмотря на то, что стандартом индустрии является webpack, я не нашёл упоминания о нём в документации. rollup действительно позволяет быстро начать разрабатывать компонент, но как только захочется посмотреть промежуточный результат, то тут ожидается облом. rollup просто компилирует файлы в разные форматы и ни о каком dev сервере речи нет.
"scripts": {
"build": "npm run build:umd & npm run build:es & npm run build:unpkg",
"build:umd": "rollup --config build/rollup.config.js --format umd --file dist/vue-openapi-bootstrap.umd.js",
"build:es": "rollup --config build/rollup.config.js --format es --file dist/vue-openapi-bootstrap.esm.js",
"build:unpkg": "rollup --config build/rollup.config.js --format iife --file dist/vue-openapi-bootstrap.min.js"
}
Простота упаковки
JSP vs VueJS
Тут у обоих фреймворков нет проблем. Для JSP упаковка - это стандартная команда maven:
mvn package
В VueJS соответственно:
npm build
Тестирование
JSP vs VueJS
Опять же, из-за rollup и общей путаницы с технологиями, начать тестировать компонент на VueJS нетривиально. Если честно, я так и не осилил переход на webpack с полноценными тестами и покрытием кода.
В JSP же всё относительно просто: я просто скопировал подход для тестирования тэгов, который использовал ранее и сразу получил страницу index.html, которая загружается в браузер простым кликом.
Скорость разработки
JSP vs VueJS
Да, инженерная мысль шагнула далеко вперед за последние 20 лет и разрабатывать на VuejS получается значительно быстрее. Например, синтаксис чуть более компактный. Сравните вывод одного и того же блока на VueJS:
<p>Available values:
{{ param.schema.items.enum.join(', ') }}
</p>
И на JSP:
<p>Available values:
<c:forEach items="${curParam.schema.items.getEnum()}" var="curEnum" varStatus="enumStatus"><c:if test="${!enumStatus.first}">, </c:if>${curEnum}</c:forEach>
</p>
Ещё одной вещью, значительно ускоряющей разработку (не путать со стабильностью кода!), является отсутствие строгой типизации. Сама по себе доменная модель OpenAPI нетривиальная, поэтому в JSP мне приходилось загружать её из JSON с помощью специальной библиотеки swagger-parser-v3
. И даже после того, как я её загрузил, мне приходилось делать различные приседания, чтобы сгруппировать объекты в более удобном виде:
private static Map<String, Operation> getOperationsByType(PathItem item) {
Map<String, Operation> result = new HashMap<>();
if (item.getGet() != null) {
result.put("get", item.getGet());
}
...
return result;
}
В javascript же такой проблемы не было, так как json - это JavaScript Object Notation. Что как бы намекает на глубокую поддержку внутри самого языка. Из-за этого загрузка выглядела достаточно просто:
openapi = response.data
Следующей неудобной штукой при разработке были вспомогательные методы. Например, необходимо было в зависимости от http метода отобразить цвет. В VueJS - это делается с помощью объявления метода прямо в файле:
methods: {
getColorByMethod (method) {
...
}
}
И использование (всё в том же файле):
<span :class="`badge ${getColorByMethod(method)}`">
В JSP же пришлось объявлять специальные функциональные методы в jsp-openapi.tld
:
<function>
<name>getColorByMethod</name>
<function-class>ru.r2cloud.openapi.OpenAPIHelper</function-class>
<function-signature>java.lang.String getColorByMethod(ru.r2cloud.openapi.OperationDetails)</function-signature>
</function>
Описывать их в java коде:
public class OpenAPIHelper {
public static String getColorByMethod(OperationDetails method) {
...
}
}
И использовать внутри JSP:
<span class="badge ${openapiHelper:getColorByMethod(method)}">
Простота переиспользования
JSP vs VueJS
Тут оба фреймворка постарались и сделали вполне неплохое переиспользование своих компонент. Подключить jsp tag в проект можно описав зависимость:
<dependency>
<groupId>ru.r2cloud.openapi</groupId>
<artifactId>jsp-openapi</artifactId>
<version>1.0</version>
</dependency>
И добавив на страницу:
<%@ taglib prefix="openapi" uri="https://github.com/dernasherbrezon/jsp-openapi" %>
<openapi:bootstrap4-openapi openapi="${entity}"/>
Во VueJS примерно так же просто:
"dependencies": {
"vue-openapi-bootstrap": "1.0.1"
}
Использование на странице:
<template>
<vue-openapi-bootstrap :openapi="openapi"/>
</template>
<script>
import vueOpenapiBootstrap from 'vue-openapi-bootstrap/src/vue-openapi-bootstrap'
export default {
components: {vueOpenapiBootstrap}
}
</script>
Выводы
Несмотря на то, что JSP уже почти 20 лет, разрабатывать переиспользуемые компоненты на нём достаточно просто. Конечно, чувствуется возраст технологии и некоторые вещи можно было бы сделать проще. Тем не менее ужасов, которые рисуют поклонники javascript и SPA, нет. При правильном дизайне и тот, и другой фреймворк предоставляют достаточно мощные инструменты для написания и переиспользования компонентов.