Привет, Хабр! Помоги выбрать веб-фреймворк? Требования: модный, молодежный, популярный, качественный фреймворк для соло-технономада.
Надо ли нам каждый месяц читать очередной пост про это?
Несколько лет участия в проектах на границе энтерпрайза и системщины окончательно отбили нюх. Чтобы разобраться в вопросе, я заглянул в топ гугла и обнаружил там кучу однобоких рейтингов. Наверное, самым лучшим оказался Java Web Frameworks Index от ZeroTurnaround.
Хорош он тем, что
- создатели основательно погулили, а также притащили туда статистику StackOverflow, LinkedIn, GitHub — примерно то же самое, что сделали бы и мы;
- очевидно, что для ZeroTurnaround верное понимание расклада по фреймворкам — это основа для зарабатывания бабла.
Вот как рейтинг выглядит на момент написания статьи:
Rank | Framework | Popularity |
---|---|---|
1 | Spring MVC | 28.82 |
2 | JSF | 15.2 |
3 | Spring Boot | 13.35 |
4 | GWT | 7.74 |
5 | Grails | 6.35 |
6 | Struts | 5.4 |
7 | Dropwizard | 4.9 |
8 | Play framework | 3.26 |
9 | JHipster | 2.49 |
10 | JAX-RS | 2.44 |
11 | Vaadin | 2.15 |
12 | Seam | 1.94 |
13 | Wicket | 1.91 |
14 | Tapestry | 1.9 |
15 | Sparkjava | 0.77 |
16 | Vert.x | 0.76 |
17 | Rapidoid | 0.25 |
18 | Lagom | 0.24 |
19 | Ratpack | 0.13 |
Стойте, там Struts в первой десятке? Серьезно? Кажется, я ничего не потерял за эти несколько лет. Точнее, даже начиная с раннего средневековья.
Давайте пробежимся по списку.
Оу, Spring MVC и Spring Boot — это два разных элемента списка? Наверное, это можно понять и простить? (напишите в комментариях!). Не имеет смысла спрашивать, при чем тут Spring — он, как и Docker, всегда при чем.
Кстати, к нам на JPoint 2018 Moscow собрался Юрген Хеллер — это главный спринговец. Вот его можно дрючить вопросами типа "при чём тут спринг" по полной программе.
Но что действительно страшно, это то, что между ними (то есть по сути, на первом месте) находится JSF. Когда-то я делал на ЛОРе несколько обсуждений на тему, какой шаблонизатор для Java лучший. Годы шли, но всегда находилась половина треда с универсальным ответом: зачем тебе шаблонизатор, когда есть JSF? Вначале был просто JSP/JSTL, но потом они потихоньку сдали позиции, и остался один JSF.
Давайте глянем, что есть нового в JSF. Да, теперь мы можем больше не писать FacesContext facesContext = FacesContext.getCurrentInstance();
. Можно сделать @Inject FacesContext facesContext;
. Или если ты EL-камикадзе, то можно даже #facesContext
. В нужных местах можно навешать @FlowMap
или достать настроечку через @ManagedProperty ("#{bean.property}") private String stringProperty;
Имхо, всё это совершенно очевидные рефакторинги, в соответствии с текущей модой на синтаксис. То же касается валидации в форме <f:convertDateTime type="localDate" pattern="MM/dd/yyyy"/>
— ну запилили в Восьмерке Date-Time API, пришлось отреагировать, чтобы люди не писали бесконечных конвертеров самостоятельно. Список можно продолжить. Так и представляешь, как архитекторы Oracle пилили эти фичи за один вечер, батон колбасы и бутылку водки.
Интересная фича — это тэг <f:websocket>
, который можно юзать вот так:
<h:body>
<f:websocket channel="jaxArticle"
onmessage="function(message){alert(message)"} />
</h:body>
В целом, прогресс с 2009 года (наш эквивалент «XV века») не перестает поражать воображение.
Дальше по рейтингу — Grails и PlayFramework. Grails — это, строго говоря, вообще не Java, а JVM. C PlayFramework под Java API не встречался со времен Play 1, поэтому — можете рассказать об этом в комментариях? Пока условно будем считать PlayFramework вторым годным фреймворком из списка, просто по причине наличия чудесного Scala API (за который можно простить ему историю с ORM и прочие мелкие ляпы).
Grails. Ну, допустим. Закроем глаза, тем более что Барух обещал, что Groovy — это круто. Но у них до сих пор открыты тикеты против Java 9! Ничего личного, чуваки, но это никуда не годится. В самом Groovy тоже какая-то фигня творится с поддержкой модулей и Java 9: насколько понял, --add-opens=java.base/*
с нами навечно.
Wicket, Vaadin и GWT хотелось бы выделить в отдельную группу. С Vaadin и GWT я встречался только в смысле правки багов в чужих проектах. Но с Wicket у меня давний и болезненный опыт. Не знаю, кто первый притащил Wicket в Новосибирск, но он как эпидемия прошелся по нашим Java-компаниям. Мы писали на Wicket систему для управления профсоюзами в США. Мы писали мобильную MMO-игру. И для российских государственных компаний тоже писали разное, так что если заходите вылечиться от насморка в соседнюю больницу — осторожней, возможно, там в компьютерах полный неоперабельный Wicket. Каждый раз меня не оставляло ощущение, что Wicket не нужен вообще никогда и нигде. Может быть, про это стоит написать отдельную статью или даже целую книгу?
Давайте посмотрим еще раз на стартовую картинку. (Не знаю, кто настоящий автор, я ее нагуглил вот здесь).
Wicket появился в том же году, что и термин AJAX. В свою очередь, AJAX спас веб, благодаря этому мы все с вами такие богатые и знаменитые, хе-хе. В свою очередь, Wicket появился как средство управления Аяксом и как эксперимент был очень удачным. Потом он пошел в продакшн, и это история, полная боли и фейлов. С точки зрения архитектуры, он так никогда и не стал кластерным, и в некоторых компаниях стал причиной полного отсутствия горизонтального масштабирования. С перфомансом у него очень плохо — просто гляньте, сколько он весит в памяти и как медленно отвечает на запросы. Ну или просто откройте wicket.apache.org и посчитайте, за сколько загрузится страница.
С AJAX у него тоже так и не вышло: в 2017 году нас все еще преследуют оптимизации в названиях параметров. Пожалуйста, поднимите руки все, кто с первого раза догадается о назначении следующих параметров запроса: m
, mp
, e
, f
, sc
, dt
, wr
, ch
, bh
, pre
, bsh
, ah
, sh
, fh
, coh
, ep
, dep
, rt
, ad
, sp
, tr
.
Ответы на задачку находятся здесь. Спойлер: АД расшифровывается как «allow default». Это булевский флаг, который показывает, разрешать ли исполнение поведения по умолчанию для того элемента HTML, который слушает данное событие.
Да, многие из нас работают в банках, и там всё на GWT. Но, оглядываясь назад на этот долгий-долгий путь, давайте честно признаем: управлять JavaScript из Java — наиболее дурацкая и деструктивная идея, которая когда-либо приходила в голову.
Если посмотреть на репозиторий Wicket, становится очевидно, что в период с 2007 по середину 2010 он был скорее мертв, чем жив, и далее возродился силами всего одного пользователя GitHub — Martin Grigorov, который сделал туда около четырех тысяч коммитов.
Картинка хороша, но давайте обратим внимание на конкретные циферки.
git clone https://github.com/apache/wicket.git
cd ./wicket
И теперь долбанём адским однострочником:
git log --shortstat --pretty="%cE" | sed 's/\(.*\)@.*/\1/' | grep -v "^$" | awk 'BEGIN { line=""; } !/^ / { if (line=="" || !match(line, $0)) {line = $0 "," line }} /^ / { print line " # " $0; line=""}' | sort | sed -E 's/# //;s/ files? changed,//;s/([0-9]+) ([0-9]+ deletion)/\1 0 insertions\(+\), \2/;s/\(\+\)$/\(\+\), 0 deletions\(-\)/;s/insertions?\(\+\), //;s/ deletions?\(-\)//' | awk 'BEGIN {name=""; files=0; insertions=0; deletions=0;} {if ($1 != name && name != "") { print name ": " files " files changed, " insertions " insertions(+), " deletions " deletions(-), " insertions-deletions " net"; files=0; insertions=0; deletions=0; name=$1; } name=$1; files+=$2; insertions+=$3; deletions+=$4} END {print name ": " files " files changed, " insertions " insertions(+), " deletions " deletions(-), " insertions-deletions " net";}'
Или можно получить еще более подробную кумулятивную статистику:
sudo gem install git_fame
git fame
Более подробная статистика займет минут 30 (на SSD, на новеньком макбуке с мобильным i7).
Statistics based on master
Active files: 5,407
Active lines: 578,441
Total commits: 15,600
name | loc | commits | files | distribution (%) |
---|---|---|---|---|
martin-g | 161,089 | 98 | 2,898 | 27.8 / 0.6 / 53.6 |
Igor Vaynberg | 67,983 | 2,872 | 1,993 | 11.8 / 18.4 / 36.9 |
Juegen Donnerstag | 66,234 | 1,867 | 2,250 | 11.5 / 12.0 / 41.6 |
andrea del bene | 58,583 | 5 | 654 | 10.1 / 0.0 / 12.1 |
Eelco Hillenius | 30,287 | 2,932 | 1,051 | 5.2 / 18.8 / 19.4 |
svenmeier | 28,504 | 307 | 1,130 | 4.9 / 2.0 / 20.9 |
Martijn Dashorst | 22,470 | 1,089 | 727 | 3.9 / 7.0 / 13.4 |
Frank Bille Jensen | 19,854 | 235 | 1,403 | 3.4 / 1.5 / 25.9 |
Johan Compagner | 17,637 | 1,484 | 1,503 | 3.0 / 9.5 / 27.8 |
Jonathan Locke | 14,257 | 1,321 | 437 | 2.5 / 8.5 / 8.1 |
Jean-Baptiste Quenot | 14,022 | 277 | 448 | 2.4 / 1.8 / 8.3 |
Gerolf Seitz | 13,189 | 205 | 1,041 | 2.3 / 1.3 / 19.3 |
Matej Knopp | 8,565 | 963 | 291 | 1.5 / 6.2 / 5.4 |
Peter Ertl | 8,281 | 354 | 417 | 1.4 / 2.3 / 7.7 |
Pedro Henrique Oliveira d... | 7,474 | 98 | 169 | 1.3 / 0.6 / 3.1 |
Tobias Soloschenko | 6,373 | 100 | 161 | 1.1 / 0.6 / 3.0 |
Emond Papegaaij | 4,624 | 168 | 207 | 0.8 / 1.1 / 3.8 |
Alastair Maw | 3,257 | 422 | 172 | 0.6 / 2.7 / 3.2 |
Carl-Eric Menzel | 2,338 | 36 | 112 | 0.4 / 0.2 / 2.1 |
Jesse Long | 2,230 | 12 | 261 | 0.4 / 0.1 / 4.8 |
Jeremy Ryan Thomerson | 2,146 | 51 | 84 | 0.4 / 0.3 / 1.6 |
Andrea Del Bene | 1,999 | 46 | 450 | 0.3 / 0.3 / 8.3 |
bitstorm | 1,972 | 14 | 116 | 0.3 / 0.1 / 2.1 |
Michael Mosmann | 1,397 | 43 | 31 | 0.2 / 0.3 / 0.6 |
Felipe Campos de Almeida | 1,396 | 4 | 24 | 0.2 / 0.0 / 0.4 |
klopfdreh | 1,329 | 39 | 27 | 0.2 / 0.2 / 0.5 |
Janne Hietamaki | 996 | 218 | 46 | 0.2 / 1.4 / 0.9 |
Timo Heikki Rantalaiho | 883 | 42 | 105 | 0.2 / 0.3 / 1.9 |
Maurice Marrink | 784 | 12 | 28 | 0.1 / 0.1 / 0.5 |
Bertrand Guay-Paquet | 773 | 1 | 3 | 0.1 / 0.0 / 0.1 |
John Sarman | 767 | 8 | 21 | 0.1 / 0.1 / 0.4 |
Maxim Solodovnik | 716 | 26 | 38 | 0.1 / 0.2 / 0.7 |
sourceforge-skipoles | 605 | 40 | 42 | 0.1 / 0.3 / 0.8 |
manuelbarzi | 476 | 2 | 5 | 0.1 / 0.0 / 0.1 |
Domas Poliakas | 432 | 9 | 9 | 0.1 / 0.1 / 0.2 |
Alexander Morozov | 412 | 4 | 16 | 0.1 / 0.0 / 0.3 |
Thomas Götz | 403 | 1 | 13 | 0.1 / 0.0 / 0.2 |
Martin Funk | 313 | 3 | 20 | 0.1 / 0.0 / 0.4 |
Gwyn Richard Evans | 249 | 62 | 67 | 0.0 / 0.4 / 1.2 |
admin | 247 | 3 | 13 | 0.0 / 0.0 / 0.2 |
kensakurai | 208 | 5 | 3 | 0.0 / 0.0 / 0.1 |
Michael Haitz | 207 | 1 | 2 | 0.0 / 0.0 / 0.0 |
Guillaume Smet | 204 | 3 | 7 | 0.0 / 0.0 / 0.1 |
Cedric Gatay | 185 | 9 | 13 | 0.0 / 0.1 / 0.2 |
Thomas Matthijs | 185 | 3 | 12 | 0.0 / 0.0 / 0.2 |
Roman Grigoriadi | 169 | 1 | 12 | 0.0 / 0.0 / 0.2 |
Artur Michałowski | 156 | 4 | 6 | 0.0 / 0.0 / 0.1 |
Martin Grigorov (Netwalk) | 149 | 4 | 12 | 0.0 / 0.0 / 0.2 |
Robert Gruendler | 127 | 6 | 8 | 0.0 / 0.0 / 0.1 |
Matthias Metzger | 122 | 5 | 2 | 0.0 / 0.0 / 0.0 |
René Dieckmann | 119 | 1 | 3 | 0.0 / 0.0 / 0.1 |
Ate Douma | 114 | 14 | 15 | 0.0 / 0.1 / 0.3 |
Pedro Santos | 110 | 2 | 4 | 0.0 / 0.0 / 0.1 |
Sebastien Briquet | 110 | 3 | 3 | 0.0 / 0.0 / 0.1 |
Manuel Barzi | 105 | 5 | 6 | 0.0 / 0.0 / 0.1 |
jac-czerwinski | 94 | 4 | 4 | 0.0 / 0.0 / 0.1 |
Sven | 82 | 1 | 8 | 0.0 / 0.0 / 0.1 |
ozeray | 79 | 1 | 11 | 0.0 / 0.0 / 0.2 |
Thomas Heigl | 75 | 1 | 4 | 0.0 / 0.0 / 0.1 |
Sebastien | 71 | 2 | 4 | 0.0 / 0.0 / 0.1 |
Fridolin Jackstadt | 42 | 2 | 6 | 0.0 / 0.0 / 0.1 |
meno | 37 | 3 | 8 | 0.0 / 0.0 / 0.1 |
Thibault Kruse | 33 | 2 | 2 | 0.0 / 0.0 / 0.0 |
Vit Rozkovec | 24 | 1 | 1 | 0.0 / 0.0 / 0.0 |
Tim Fleming | 16 | 2 | 5 | 0.0 / 0.0 / 0.1 |
Luke Niesink | 13 | 2 | 4 | 0.0 / 0.0 / 0.1 |
Jan Blok | 10 | 8 | 1 | 0.0 / 0.1 / 0.0 |
Nils Schmidt | 9 | 1 | 1 | 0.0 / 0.0 / 0.0 |
Nick Pratt | 9 | 1 | 2 | 0.0 / 0.0 / 0.0 |
slowery | 8 | 1 | 2 | 0.0 / 0.0 / 0.0 |
astrapi69 | 4 | 5 | 2 | 0.0 / 0.0 / 0.0 |
Jezza | 3 | 1 | 1 | 0.0 / 0.0 / 0.0 |
tatjana19 | 3 | 1 | 1 | 0.0 / 0.0 / 0.0 |
robert mcguinness | 3 | 1 | 1 | 0.0 / 0.0 / 0.0 |
Peter Dave Hello | 3 | 1 | 1 | 0.0 / 0.0 / 0.0 |
barney2k7 | 2 | 1 | 2 | 0.0 / 0.0 / 0.0 |
bsaad | 1 | 1 | 1 | 0.0 / 0.0 / 0.0 |
Sander Evers | 1 | 1 | 1 | 0.0 / 0.0 / 0.0 |
Yoann Rodière | 1 | 1 | 1 | 0.0 / 0.0 / 0.0 |
Jeremy Thomerson | 1 | 4 | 1 | 0.0 / 0.0 / 0.0 |
Peter Lamby | 1 | 3 | 1 | 0.0 / 0.0 / 0.0 |
Dan Retzlaff | 0 | 2 | 0 | 0.0 / 0.0 / 0.0 |
Jared Renzullo | 0 | 1 | 0 | 0.0 / 0.0 / 0.0 |
Joe Schaefer | 0 | 1 | 0 | 0.0 / 0.0 / 0.0 |
Leonid Bogdanov | 0 | 3 | 0 | 0.0 / 0.0 / 0.0 |
Yoshiki Higo | 0 | 1 | 0 | 0.0 / 0.0 / 0.0 |
cvs2svn | 0 | 1 | 0 | 0.0 / 0.0 / 0.0 |
В любом случае, мы увидим, что Wicket, по сути, разрабатывается не более чем десятью людьми. Если кто-то из этих десяти человек навернется (особенно Мартин), то вашему свободному времени настанет неминуемый капец — придется вечерами и ночами сидеть и осознавать баги в рендеринге страницы.
Думаю, пора заканчивать избиение младенцев и сделать какой-то вывод.
Совсем недавно было такое время, когда мы возмущались «программистами на фреймворках». «Как же так, — говорили мы на собеседовании, — ты умеешь использовать Spring, но понятия не имеешь, как работает изнутри HashMap! Что за дичь!» В еще больший ужас мы приходили, когда человек начинал рассказывать о десятках различных фреймворков, ни один из которых он не знал даже приблизительно, но все успешно применял на практике. Совсем ужасно, когда человек сам написал пять веб-фреймворков и даже в них не разбирался!
Ну что ж, если долго жечь поляну, то в конце концов травы на ней не останется. В результате своих возмущений мы получили ситуацию, когда JavaScript-проекты растут как грибы после дождика, а вот создание новых фреймворков для Java оказалось не такой уж популярной задачей. Теперь вы легко найдете того самого Senior Framework Coder (если этот фреймворк — Spring Boot, JSF и Play), который назубок расскажет про устройство табличных компонентов и внутреннюю кухню хэшмапы, но вряд ли сможет написать пять своих фреймворков и десять вариантов хэшмапы. И ни одного такого, кто сможет написать нечто лучшее, чем Spring Boot.
Возможно, вот прямо сейчас стоит остановиться и начать раздувать большущий такой фреймворк-хайп. Что думаете?
И возвращаясь к стартовому вопросу. Эй, читатель! Помоги выбрать веб-фреймворк? Требования: модный, молодежный, популярный, качественный фреймворк, и чтобы им кто-то действительно пользовался в проде, а не как Vert.x.
UPD: если кто-то из новосибирцев пишет на Wicket и не согласен с написанным выше, предлагаю встретиться на JBreak и перетереть за всю хурму. Как раз будет несколько месяцев, чтобы подготовиться к защите любимого фреймворка — готовьтесь тщательней :-)