Недавно в Твиттере обнаружил тред, в котором человек спрашивает: “используются ли JSP до сих пор?”. И ему отвечают на это: нет, но есть альтернативы вроде Thymeleaf, Freemarker, Velocity, Pebble, Rocker. Меня это настолько триггернуло, что придется развернуть подробнее.
Все эти штуки — ни разу не альтернативы.
Freemarker и все-все-все
Вот так выглядит Freemarker:
<html> <head> <title>Welcome!</title> </head> <body> <h1> Welcome ${user}<#if user == "Big Joe">, our beloved leader</#if>! </h1> <p>Our latest product: <a href="${latestProduct.url}">${latestProduct.name}</a>! </body> </html>
Здесь мы видим плейсхолдеры (${latestProduct.url}) и управляющие конструкции (<#if user == “Big Joe”>). В синтаксисе есть куда более сложные элементы, а документация напоминает полный текст “Войны и Мира”.
(При желании так можно делать не только с HTML. Я на работе генерил им XML, и это позволило двум человекам за неделю вытянуть довольно безнадежный проект с сорванными дедлайнами).
Остальные шаблонизаторы недалеко ушли от него. По мне так, Freemarker чуть ли не самый лучший из них. Есть нюансы: например, для Spring может оказаться полезней использовать Thymeleaf, они хорошо интегрируются.
Наверное, тут стоит показать ещё Rocker, который даёт самый приятный глазу синтаксис:
@import java.util.* @args (List<User> users) @views.main.template("Loops") -> { <ul> <!-- standard for loop --> @for (int i = 0; i < users.size(); i++) { <li>@users.get(i).getFirstName()</li> } <!-- standard 'for each' loop --> @for (User user : users) { <li>@user.getFirstName()</li> } <!-- for each loop with additional loop information <li>0: John, first: true, last: false</li> <li>1: Martin, first: false, last: false</li> <li>2: Anna, first: false, last: true</li> --> @for ((i, user) : users) { <li>@i.index(): @user.getFirstName(), first: @i.first(), last: @i.last()</li> } </ul> }
Не дайте обмануть себя няшному внешнему виду — это не настоящая Java, а просто слегка причесанный синтаксис, испытавший влияние React JSX из JavaScript и Razor из экосистемы .NET.
Машина времени: Java Server Pages
Еще в 1999 году, когда выпускали JSP, инженеры Sun знали о разработке фронтенда больше. чем некоторые в 2021 году, .
Синтаксис не блещет какой-то особой новизной и изобилует негуманоидными символами процента (%) и скобочек, используемых как разделители:
<p>Counting to three:</p>
<% for (int i=1; i<4; i++) { %>
<p>This number is <%= i %>.</p>
<% } %>
<p>OK.</p>
В чем отличие от шаблонизаторов, перечисленных выше? Во Freemarker-подобных штуках, “шаблон” — это текстовый файл (возможно, сжатый в какое-то временное представление), в котором плейсхолдеры заполняются реальными значениями непосредственно перед рендерингом.
JSP — это полноценная высокоуровневая абстракция поверх Java Servlets. Код, написанный в JSP — это настоящая Java, которая скомпилируется и будет выполняться как JVM байткод. Разработчик может в одном файле смешивать вёрстку и полноценный исполняемый код.
С тех далёких пор разработчики забросили развитие JSP. Но JSP всё ещё успешно живут в самой популярной версии Java — Java 8. На момент написания этой статьи, последней версией джавы была 17, и в разработке находится 18, но в индустрии почему-то упорно игнорируют эти нововведения.
Наше время: React JSX
Нет худа без добра, интерфейс научились генерировать на фронтенде. И уж если фронтендеру захотелось ништяков — он их или найдет, или напишет за две недели.
React JSX позволяет писать вёрстку прямо внутри JavaScript-кода, и разработчику даже не нужно вставлять негуманоидные символы, чтобы отделить одно от другого.
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
ReactDOM.render(
element,
document.getElementById('root')
);
Созданные в джаваскрипте функции можно прозрачно использовать в шаблонах. А всё потому, что JSX – это всего лишь синтаксический сахар для функции:
React.createElement(component, props, ...children)
Поэтому вот такой шаблон:
<MyButton color="blue" shadowSize={2}>
Click Me
</MyButton>
После работы JSX процессора превратится в следующий код:
React.createElement(
MyButton,
{color: 'blue', shadowSize: 2},
'Click Me'
)
Сейчас React JSX — это мэйнстрим в мире фронтенда, любой джуниор про него слышал начиная с курсов “войти в айти”. Мало кто сейчас знает о Freemarker или Razor, но о React слышали все.
Схватка двух йокодзун
Историческая справка: выражение “схватка двух йокодзун” произошло от старинной аудиозаписи, где спортивный комментатор агенства РБК Александр Хорлин пытается записать новость о борьбе сумо, но раз за разом скатывается в истерический хохот.
Выбор технологии тут — не только вопрос красивого синтаксиса. Мир Freemarker и JSP/JSX очень отличаются.
Представители школы плейнтекстовой шаблонизации утверждают, что нужно отделять логику и представление. Мне видится, что все эти перекладывания переменных между контекстами нужны, в первую очередь, чтобы отгородить мир “Настоящего Кода” от мира “богомерзкой вёрстки”. Им грезится, что разработчик никогда не опускается до редактирования вёрстки. Он всего лишь “натягивает” результат работы верстальщика, вписывая $-плейсхолдеры куда-то в самый центр нечитаемой HTML каши.
Это желание разделять консёрны не ограничивается лишь шаблонизатором. Весь арсенал “паттернов проектирования” был брошен на то, чтобы бэкендерам откреститься от фронтенда. Открываешь проект, а там MVC погоняет MVVM, DTO перекладывается в DTO на каждый риквест — одним словом, ад. Мне кажется, это потому, что сам фронтенд не рассматривается ими как предметная область, с которой надо работать разработчику. Им противно.
Но ведь надо. Зачастую, грамотный фронтенд является единственным конкурентным преимуществом продукта, и именно над ним ты работаешь 98% времени, а не над тремя строчками “сохрани всё в базу” на бэкенде. Тут можно было бы поговрить про GraphQL, но это тема для отдельного поста.
React предлагает другую идею: мы утверждаем, что логика и отображение в графических приложениях очень сильно связаны. Поэтому разделять их не стоит. Разделять приложение стоит по смыслу, распиливая его на компоненты. Например, ты можешь выделить заголовок страницы в один компонент, а основную часть с бесконечной лентой — в другой.
Если вам кажется, что я сейчас несу чушь, то почитайте : Why did we build React? и Displaying Data.
Самое главное:
- Java, JavaScript, и любой другой полноценный язык программирования — намного удобней, чем органиченный набор фичей шаблона. Ты можешь всё.
- Больше не нужно использовать наборы негуманоидных символов ($, #, %, …) для переключения между языком шаблона и основным языком.
- Можно прозрачно использовать готовый код и библиотеки. Без необходимости написания интеграции между ними (перекладывания функций и переменных из контекста в контекст, обязательного собирания библиотеки тэгов, обмазывания XML-конфигурациями и т.п.).
- Полученные таким образом страницы куда проще и удобней расширять.
- IDE может предоставить в шаблонах все те же богатые фичи (коданализ, рефакторинги, навигация, справка…)
Шаблоны — это плохо, JSX — хорошо, ладненько? Рыночек порешал. Поехали дальше.
Будущее
С одной стороны, ни один вменяемый человек сейчас не начнет делать фронтенд на JSP или Freemarker. Настояее фронтенда — React, Vue, Angular, и тому подобное.
С другой стороны, Java никуда не девалась, и она всё ещё является отличным языком. Как язык она явно лучше, чем TypeScript. В интервью с Гришей Петровым, Гослинг даже посмеялся, что TypeScript — это такая эрзац-Java. Вначале из Java убрали типы и получили JavaScript, а потом TypeScript добавил их назад.
Как язык она может и лучше, а вот практики разработки фронтенда — ужасные.
Но кто знает, может, всё ещё впереди?
В мире JavaScript происходит движение в сторону генерации страниц на сервере и статического инлайнинга. В смысле, не все ещё перешли на Svelte, но он хотя бы существует. Java умела генрировать страницы на сервере с самого начала.
Самая большая проблема в том, что браузер работает не на Java, а на JavaScript. Кроме как в браузере, нормальных средств делать интерфейс в 2021 году нет. Возможно, выстрелит Compose Multiplatform на языке Kotlin, но это его всемирное доминирование вилами на воде писано, на момент написания статьи мы ждём в нём поддержку iOS.
У компиляторов Java в JavaScript сложилась какая-то непростая судьба. Когда ты вспоминаешь о GWT, первым вопросом будет: “он ещё живой, что ли?”. И да, живее всех живых, хоть и не особо популярен. GWT 3, скорее всего, будет поддерживать J2CL — новый гугловый транспилятор из Java в JavaScript и станет совсем шоколадно. Хорошая новость: J2CL можно использовать и без GWT.
А ещё развивается GraalVM, который с помощью Native Image может копилировать Java-код в запускаемые exe-бинари. В GraalVM уже есть реализация JavaScript, в которой поддерживается полная совместимость с последней спецификацией ECMA. Этот интерпретатор даже можно запустить в режиме Native Image, хотя при этом и пропадёт весь интероп между JS и Java.
Если сложить все эти вещи воедино, то возможно, в ближайшем бущуем Java может стать отличным инструментом для создания современного, надежного фронтенда.
И, следуя самым современным трендам, синтаксис для описания веб-страниц там должен быть совсем как JSX. В каком-то смысле, мы снова вернемся к JSP.
Возможно, стоит обновить резюме и вписать JSP первой строчкой? Не старпёр, а визионер!
Add comment