The Darkest Library

[RU] JSP — это некстген. How do you do, fellow kids?

Недавно в Твиттере обнаружил тред, в котором человек спрашивает: “используются ли 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 первой строчкой? Не старпёр, а визионер!

olegchir

Links: Facebook | Twitter | Instagram

Indie game developer. All opinions are my own.

Add comment

Follow me (@olegchir)

Don't be shy, get in touch. I love meeting interesting people and making new friends.

Most popular

Most discussed