Привет! Помоги выбрать веб-фреймворк? Требования: модный, молодежный, популярный, качественный фреймворк для соло-технономада.
Надо ли нам каждый месяц читать очередной пост про это?
Несколько лет участия в проектах на границе энтерпрайза и системщины окончательно отбили нюх. Чтобы разобраться в вопросе, я заглянул в топ гугла и обнаружил там кучу однобоких рейтингов. Наверное, самым лучшим оказался 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, всегда при чем.
Вот что страшно, это то, что между ними (то есть по сути, на первом месте) находится 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 и перетереть за всю хурму. Как раз будет несколько месяцев, чтобы подготовиться к защите любимого фреймворка — готовьтесь тщательней :-)
Автор: olegchir