Русский
Русский
English
Статистика
Реклама

Joker

Мы вас посчитали теперь я не знаю, зачем вы ходите на конференции. Зато знаю, почему не ходите

17.11.2020 12:21:43 | Автор: admin
Идти вперед туда, где не ждут; атаковать там, где не подготовились.
Искусство войны, Сунь-Цзы

На прошлой неделе я набросал простую математическую модель принятия решения и оценки того, пойдете вы на конференцию или нет. Для того, чтобы модель была наглядной, нам понадобятся Саша (в очках) и Женя (улыбается), вот они:



Математическая модель для конференции и участников


Давайте познакомимся с нашими героями поближе:


  • Саша, приходит на конференцию за знаниями и кругозором, смотреть доклады, задать пару своих вопросов спикерам, если выпадет шанс, и обязательно вести конспект.
  • Женя, в свою очередь, приходит на конференцию, чтобы встретиться с друзьями и бывшими коллегами, познакомиться с новыми людьми, выпить пару бокалов пенного или сухого на вечеринке и во второй день прийти на конференцию не ранее, чем к обеду, потому что ну что мы на этих докладах не видели.

Впрочем, только ситхи всё возводят в абсолют, а в реальности такие Саша и Женя в природе встречаются очень редко. Выраженность этих признаков, как и всё в нашем мире, градиентно распределена среди всех участников (и даже неучастников!) конференций. Представьте себя на месте наших героев: у вас есть свой набор ожиданий от конференции, давайте возьмем их сумму за единицу, которую можно распределить между Сашей и Женей. Эту единицу мы назовем Business or Banquet Ratio (далее просто BOBR).



Вы так или иначе окажетесь на нашей прямой, которая, по сути, является математической моделью множества всех участников конференции:


  1. Вот, например, с бокалом и без улыбки у нас будет СЕНЯ (Четверть от Саши, три четверти от Жени: 75% ради нетворкинга, 25% ради докладов). Кого-то притягивает атмосфера большого события и общество единомышленников, такие люди проводят время в кулуарах и на выставке, иногда заходя на пару интересующих докладов и проводя почти все время на выставке и в кулуарах со старыми и новыми знакомыми.
  2. Кто-то наоборот на три четверти ходит ради докладов, знаний и кругозора, однако эти знания можно получить, общаясь с интересными людьми, задавая вопросы докладчикам и коллегам, так что условная четверть ваших ожиданий будет зависеть не от самих докладов, а от того, кто их рассказывает и в каком круге вы их потом обсуждаете. Тут имя не получилось, к сожалению.
  3. Другие ходят на конференцию слушать доклады совместно с друзьями и коллегами, постоянно общаясь и обсуждая то, что удалось услышать на докладе или в кулуарах конференции, разделяя время на знания и общение пополам. Получается САНЯ! Как видите, модель выходит довольно складной

Теперь давайте посмотрим на место конференции в этом графике. Очевидно, в отличие от участника, конференция в нашем представлении может иметь сумму значений как меньше единицы, так и больше, поэтому мы получаем две зоны, которые характеризуют хорошую конференцию и плохую:



Длина отрезка BOBR, находящегося внутри площади прямоугольника, с вершинами в точке 0 и точке, занимаемой конференцией, будет ожиданием того, сколько участников будут реально довольны участием в конференции.


Давайте прикинем, где бы оказались наши конференции при таком подходе.


Мы не будем делать поправок по шкале Саши (доклады и спикеры), потому что с ней и в онлайне все в порядке судя по отзывам участников летнего сезона, программы получились полноценные, на эту осень тоже (если интересно, посмотрите обзоры программ в нашем блоге).


А теперь немного отвлечемся от математики и постараемся понять, что именно добавляет ценности по шкале Жени (общение и отдых) и обеспечивает разницу между онлайном и офлайном:



Ретроспективное исследование наших проведенных конференций говорит о том, что люди приходили на них ради образовательных и тусовочных (простите за мой французский) целей примерно в равной степени. То есть примерно вот так выглядел Joker 2019:



На конференции было все: две с лишним тысячи участников, уверенная программа, дискуссионные зоны со спикерами, кулуарные беседы за чашкой кофе, вечеринка и выходной на работе, то, что доктор прописал.


image А значит, BOBR по шкале Жени включает в себя следующие слагаемые:


  1. Встретиться с друзьями, которые приехали издалека или обычно слишком заняты, обсудить с коллегами насущные проблемы.
  2. Сделать селфи для инстаграма с крутыми инженерами, разработчиками любимых инструментов или автором настольной книги.
  3. Отдохнуть, сменить обстановку, перезагрузиться, просто прогуляться в толпе интеллигентных людей.
  4. Пособирать мерч на стендах компаний-спонсоров конференции.
  5. Найти новых знакомых из огромной толпы единомышленников и оппонентов в кулуарных спорах о технологиях и жизни.

image Что можно делать в онлайне:


  1. Потрепаться в чате конференции и чатах докладов.
  2. Пообщаться со спикером в Zoom-комнате доклада.
  3. Поучаствовать в вечеринке в общей Zoom-комнате конференции с теми, кто тоже хочет обсудить всякое.

А это значит, что онлайновый JPoint 2020 выглядел уже так:



Обратите внимание на недовольного Сашу, он не смог задать свой вопрос, потому что он не из тех, кто задает вопросы в микрофон во время доклада. Он скорее всего хотел дождаться, пока они со спикером останутся один на один, чтобы обсудить что-то конкретное, но в Zoom и телеграме такая ситуация просто не происходит.


Общие комнаты в Zoom тоже вызывают сложности, связанные с языковым барьером и управлением дискуссией, задержками передачи голоса и проблемой одновременного говорения.


Впрочем, есть еще один нюанс, посмотрите на графики с количеством участников в 2019 офлайне и 2020 онлайне:



Как видите, на самом деле людей пришло вполовину меньше, и конечно, ощущения оказались не те: нет атмосферы праздника, ощущения масштаба, так что всё выглядело скорее даже так:



А мы вот так:

Команда JUG Ru Group по окончании сезона онлайн-конференций выглядела как-то так:


Как видите, наши Жени либо совсем не пришли, либо жутко расстроились от того, что увидели и чего не увидели. Это, кстати, привело к тому, что исключительно тусовочные мероприятия в индустрии встали на холд и отказались от проведения в ожидании открытия офлайна.


Всё. Из-за этого наши онлайн-конференции оказываются в левой части системы координат с минимальной длиной отрезка BOBR:


Мы, как всегда, сделали хорошую программу и собрали спикеров (шкала Саши) на онлайновых JPoint и HolyJS, но это привело к тому, что они еле-еле переползли в зеленый сегмент из-за низкого индекса по шкале Жени.


По сути, этот индекс приводит к тому, что конференции в онлайне дотягивают до BOBR с точки зрения очень небольшого количества участников.


Глядя на это, мы пошли внимательно изучать отзывы участников, думать и прогнозировать будущее.


В реальности, обстановка с коронавирусом привела к тому, что мы допрогнозировались до банального Я знаю, что ничего не знаю, а именно Мы можем прогнозировать лишь тот факт, что прогнозировать в ближайшей перспективе мы не сможем и отправились допиливать наш онлайн.


Итак, задача ставилась так, чтобы Joker 2020 и HolyJS 2020 Moscow попали примерно сюда:


Ниже я расскажу, что как мы эту задачу решаем.


Что же делать?


С самого начала локдауна и пандемии многие организаторы по всему миру ушли в виртуальные пространства: митинги в Red Dead Redemption, конференции в Animal Crossing, митапы в Minecraft Мы тоже думали об этом: организация виртуального кинотеатра кажется достаточно тривиальной задачей до тех пор, пока не пытаешься ее скалировать до нужных масштабов:


  1. Несколько сотен или тысяч человек в онлайне;
  2. Хорошие звук и видео, в идеале 4К;
  3. Стабильность подключения, видео- и голосовой связи не только для спикеров, но и для участников;
  4. Интеграция контента и нетворкинга на единой платформе;
  5. Размещение на карте всех POI и партнеров.

Каждый из этих критериев напрямую привязан к конкретным действиям, которые участники так или иначе делают на конференциях: ходят вдвоем или ищут конкретного человека, чтобы поговорить тет-а-тет, собираются в группы для обсуждения общей темы, обсуждают доклады и вот это вот всё.


За весну и лето мы упоролись и посмотрели несколько десятков онлайн-мероприятий и кучу готовых платформ, на которых они проходили и везде обнаруживались проблемы и ограничения в качестве звука/видеопотока, стабильности работы или разрозненности компонент (программа на сайте, доклады и панельные дискуссии в YouTube / Zoom, тусовка в Spatial Chat). Поэтому к лету мы делали просто понятный портал с хорошим плеером, встроенной программой и навигацией, прямыми ссылками в чаты и дискуссионные зоны.


В итоге мы решили первые три задачи из списка выше и оставили две на второй сезон, который идет уже сейчас. Что нам осталось? Правильно, сделать платформу интерактивной и интересной по шкале Жени. Для этого мы снова посмотрели на имеющиеся решения типа Gather Town и Spatial Chat и поняли, что с ними мы можем сделать полноценную онлайн-движуху, но остается последняя проблема: интеграция контентной и нетворкинговой частей.


В конце концов, никто не хочет никуда ходить, и каждое открывание чатиков, зумов и прочего кажется pain in the ass. Чтобы всем было комфортно, важно сделать так, чтобы виртуальное пространство находилось там же, где и доклады, чтобы можно было быстро и без лишних телодвижений переключаться между докладами и общением: помните, нам нельзя ронять шкалу Саши и делать просмотр докладов неудобным, шумным или привязанным к геймификации, чтобы не испортить впечатления у тех, кто пришел смотреть доклады в первую очередь.


Как мы решили задачу с нетворкингом


Поэтому мы что? Правильно! Запилили свой сервис со своей реализацией webRTC и игровыми механиками!


Рациональные люди скажут, что пилить свою версию уже существующего решения неразумно. Мы согласимся, но лучшего варианта мы для себя не нашли. Зато, попадая на главную страницу конференции, вы сможете выбрать плеер, классический вид или игровой, не переключая даже вкладки в браузере!


Вот классический плеер:



И выставка партнеров:



Или она же в игровом виде:



Давайте посмотрим, что мы сделали, чтобы нашим с вами Саше и Жене было интересно проводить время не только на докладах, но и гуляя по виртуальному пространству.


Логинимся


Логинимся? (гифку безбожно пожало, к сожалению)



Общаемся


Возможность без дополнительных свистоплясок пообщаться с теми, кто находится рядом: это базовая механика, вокруг которой все строится. Не нужно переходить между звонками или ссылками, чтобы уединиться, просто отойдите от других участников в пространстве, и вот вы вдвоем или втроем.



Как видите, если подойти ближе, то внизу появляется видео собеседника (привет, vbrekelov!) и звук.


Эта пространственная механика является основой для общения на конференции. На самом деле, Жене для нормального общения важна возможность не собраться вместе, а отгородиться в небольшой компании, именно поэтому в жизни Женя общается в замкнутом кружке или за столиком, отдельно от внешнего мира.


Отдыхаем


Карта как место проведения: единое пространство, где Женя, отдыхая от докладов, может проходить мини-квесты, общаться со спонсорами конференции и собирать лут (реальный, который потом вышлют к вам!).


Вот так примерно будет выглядеть выставка и стенды партнеров:



На карте также будут места, с которыми можно взаимодействовать в них будут квесты, веб-страницы и различные пасхалки:



Ищем друзей


Поиск друзей или интересных людей: эта штука, которая разгладит брови на лице Саши и вернет улыбку Жене, найдет нужного спикера или товарища, потерявшегося среди стендов конференции. Нужно просто ввести один из идентификаторов (почта, телеграм или игровой ник) и система любезно проводит к нужному человеку, неплохо бы иметь такую штуку в реальности.



Надеюсь, мое выражение лица на гифках показывает, что эта штука действительно позволяет немного выдохнуть, если доклады утомили.


Пробуем


Мы решили рискнуть и до выпуска в прод дать вам возможность попробовать игру вживую.
Но сразу предупреждаю: мы еще не тестировали ее на под нагрузкой, так что вы точно столкнетесь с багами разной степени критичности и непонятками. Релизную карту, спроектированную как конференционную площадку, в демке вы пока не увидите должна же сохраниться какая-то интрига!


Тем не менее, нам очень интересно, что из этого выйдет, какие баги вы найдете и что вы думаете по поводу такого нетворкинга так что заходите, играйте и пишите о своих впечатлениях в комментах!


Реклама как вывод


Как видите, в этом сезоне мы постараемся сделать наши конференции не только полезными, но и более веселыми, и это наш большой эксперимент, который состоится 25-28 ноября, на Java-конференции Joker 2020 и HolyJS 2020 Moscow (да-да, мы все еще называем конференции по городам, вот такие мы ретрограды).


Кроме того, будут еще DotNext, SmartData и DevOops (со 2-го по 12-е декабря), а если планируете отправиться на несколько конференций, то смотрите на Full Pass-билет, который даст вам доступ еще и к уже прошедшим конференциям этого сезона.


Присоединяйтесь, смотрите, хвалите, играйте и ругайте! А заодно вспомните и прикиньте, где бы вы расположили себя на графике с Сашей и Женей. ;)


Disclaimer: Давайте только не приходить в комментарии со словами, что офлайн был лучше. JUG Ru Group будут первыми в очереди на проведение старых добрых конференции, когда спикеры из Штатов и Европы смогут до нас доехать, люди не будут бояться жать друг другу руки, а риски отмены не будут кратно превышать вероятности проведения.

Подробнее..

Joker 2020 продолжение сезона онлайн-конференций

29.11.2020 22:13:53 | Автор: admin
Только что, c 25 по 28 ноября 2020 года, прошла Java-конференция Joker 2020. Это уже второй сезон конференций, проводимых JUG Ru Group в формате онлайн.

В онлайн-формате конференция стала лучше или хуже? Что нового организаторами было придумано? Кого из спикеров с какими докладами можно было увидеть и услышать? Что полезного и интересного было в докладах? Имеет ли смысл посещать конференцию в следующем году?



Второй сезон онлайн-конференций: казалось бы, что ещё можно придумать, кроме возможности просмотра докладов при вынужденных ограничениях, наложенных пандемией? Теперь часть потенциальных посетителей (стремящихся преимущественно к получению новых знаний и свежей информации в области профессиональных интересов) конференцию по-прежнему посетит и билет купит, а другая часть (которую в большей степени привлекает личное общение) увы, больше нет. Выхода из создавшейся ситуации нет или он всё же есть? Можно ли конференции стать по-прежнему привлекательной и для второй части участников конференций, которые жаждут социальности?

В замечательной статье из блога компании JUG Ru Group на Хабре Руслан ARG89 Ахметзянов постарался проанализировать ситуацию (попробуйте оценить, Вы в большей степени персонаж Саша или Женя в отношении конференций). Далее там же анонсируются дополнительные механики, добавленные в стриминговую платформу конференций для того, чтобы удовлетворить вкусы как можно большего числа участников. Удалось или нет достигнуть этим поставленных целей, постараемся разобраться далее.

В преддверии конференции также вышло 8 выпусков шоу Вторая чашка кофе с Joker, в которых в эфире ведущие успели взять интервью с Алексеем Фёдоровым, Дмитрием Чуйко, Александром Белокрыловым, Дмитрием Александровым, Олегом Шелаевым, Сергеем Егоровым, Евгением Борисовым и Тагиром Валеевым.

Так что же, собственно, сама-то конференция?

Открытие


В проведение, открытие, закрытие каждой конференции организаторы раз за разом стараются привнести что-то новое. В данном случае открытие началось с импровизаций Алексея Фёдорова и Глеба Смирнова. На правом фото Алексей Фёдоров демонстрирует возможности игрового вида конференции (о нём рассказывается далее в отдельном разделе обзора).



Все виды прошедших активностей, связанных с донесением технической информации посредством слайдов и видео, можно было бы условно разделить на

  • интервью;
  • большие доклады;
  • мини-доклады партнёров;
  • воркшопы.

Интервью


В интервью Эволюция Java и Kotlin. Что нас ждет?, взятом у Романа Елизарова, можно было узнать о пути развития языка программирования Kotlin. Накануне конференции официально было объявлено о передаче управления и координации работ по проекту Kotlin от Андрея Бреслава к Роману Елизарову. По этой причине особенно интересно было узнать мнение Романа и про его изменившийся круг обязанностей, и о возможных изменениях развития языка и платформы.



Зачем нужно знание многопоточной разработки в enterprise мини-интервью Евгения phillennium Трифонова с Юрием Бабаком, представителем компании-партнёра конференции. Любопытными показались разнообразные примеры из собственной практики, про которые Юрий живо и интересно рассказал в ответ на очень уместные вопросы Евгения.

Адская кухня: Как приготовить новую версию Java и не отравить пользователей LTS релизов? мини-интервью с Александром Белокрыловым из компании BellSoft, хорошо известной, вероятно, большинству по дистрибутиву Liberica JDK. Новостью стала информация о вхождении представителей компании в исполнительный комитет JCP.



Доклады


Доклад Кирилла Тимофеева под названием JVM-профайлер, который смог (стать кроссплатформенным) был про добавление поддержки Windows в async-profiler при его использовании из среды разработки IntelliJ IDEA. Андрей Паньгин (поздравляем его с присвоением звания Java Champion за неделю до конференции!) выступил в качестве приглашённого эксперта доклада. Отличный докладчик (автор Windows-порта), хороший доклад с глубоким пониманием темы, идеальный эксперт (автор оригинального продукта), полезная информация о скором появлении предмета обсуждения в составе IntelliJ IDEA.



Предполагаю, что аболютное большинство видевших доклад и читающих данный обзор использует Spring Boot как-никак это промышленный стандарт Java-разработки сегодня. Толстый (fat) JAR при использовании Spring Boot также абсолютно распространённая практика. Рискну предположить, что Владимир Плизга со своим докладом Spring Boot fat JAR: Тонкие части толстого артефакта представил информацию, которая наиболее практически применима и востребована. Неплохо дополнили доклад три Андрея Беляев, Когунь и Зарубин.



Доклад Thread Safety with Phaser, StampedLock and VarHandle от легендарного Heinz Kabutz (ведущий известнейшей рассылки JavaSpecialists) и его коллеги John Green. Просмотр данного доклада может быть полезно тем, что в нём акцентируется внимание о менее известных concurrency-классах Phaser, StampedLock и VarHandle (в отличие от, например, многим знакомых классов CountDownLatch и CyclicBarrier).



Spring Patterns для взрослых в исполнении (сначала буквально даже в сопровождении гитары) Евгения Борисова. Ничто не помешало в итоге Жене (ни разряжающаяся батарея ноутбука, ни стремительно заканчивающееся время) успешно завершить доклад. В отличие от привычных докладчику стиля и тем технической жести, хардкора и расчленёнки (только библиотек и фреймворков. естественно) речь в этот раз шла как раз о наиболее типовом использовании Spring Framework. Ещё один абсолютно практически применимый доклад в блестящем исполнении с рекомендацией к просмотру.



Доклад Заменят ли роботы программистов? от Тагира Валеева расстроил меня вслед за докладчиком я тоже осознал, что роботы (библиотеки, сервисы, плагины) в значительной части уже заменили программистов. Частично успокаивает то, что ими автоматизируется наиболее неинтересная и рутинная часть работы программиста. Полезной и приятной частью в подобных докладах является информация о каких-то сервисах, которые можно будет попробовать после конференции. В случае доклада Тагира это информация о сервисах Mergify (есть приложение для GitHub) для автоматизации принятия pull request и сервис Diffblue (есть плагин для IntelliJ IDEA) для автоматизации создания unit-тестов (выглядит впечатляюще, надо попробовать). Полезный, интересный и даже неожиданно, не побоюсь этого слова, философский доклад.



Мини-доклады партнёров


На мой взгляд, мини-доклады партнёров очень удачная форма докладов, относительно коротких и информативных одновременно. Подводные камни загрузчиков классов в Java и как они могут повлиять на скорость работы с XML от Ильи Ермолина (слева) и Как сказать нет архитектору? Советы по выбору размера микросервиса в исполнении Андрея Даминцева (справа) являются примерами таких докладов.



В мини-докладе Java Licensing Tips от Юрия Милютина была, например, представлены волнующие многих теперь (после изменении компанией Oracle модели лицензирования) данные о сокращении (или даже исключении) расходов на лицензирование используемой в промышленной эксплуатации Java.

После мини-доклада Самое время попробовать машинное обучение на Java у Артёма Селезнева (фото справа) взял интервью Евгений Трифонов. В какой-то степени были развенчаны мифы (или хотя бы изменено мнение) о слабой применимости Java для машинного обучения.



Воркшопы


Ещё одна замечательная форма донесения технической информации и ещё одная известная личность воркшоп (мастер-класс) Хватит писать тесты, пора писать спецификации! от Алексея Нестерова. Алексей в настоящий момент один из соведущих популярнейшего подкаста Радио-Т (т.н. Алексей второй и Алексей добрый, в отличие от Алексея Абашева).

Воркшоп на конференциях JUG Ru Group обычно разбит на две части и суммарно занимает один конференционный день, к чему надо быть готовым. Для демонстрации написания тестов использовался проект в репозитории (если используете Windows, то дополнительно придётся изменить две строчки в файле frontend/package.json). Высококвалифицированный приятный инструктор-докладчик, возможность спокойно покопаться в проекте на своём удобном привычном рабочем месте, рекомендую.



Сайт


Сайт онлайн-платформы для стриминга конференций, как уже говорилось ранее, претерпел существенные изменения. Имеющаяся функциональность была значительно расширена. Кроме добавления удобства существующим возможностям (например, изменение скорости воспроизведения и возможность догнать текущее время доклада) появился совершенно новый игровой вид конференции. Участник конференции может выбрать персонажа и совершать виртуальную прогулку по разным локациям.

Слева представлен общий план возможных локаций, справа локация Холл.



Далее локация Улица слева, Партнёрская выставка справа. При приближении к персонажам других людей внизу появляется видео рядом расположенных субъектов с возможностью диалога. Наверное, следующим шагом могут стать VR-шлемы и трёхмерное пространство выставки с видом от первого лица.



Просмотр информации о конференциях и игра


В обзорах предыдущих конференций уже рассказывалось про приложение, доступное на сайте jugspeakers.info (репозиторий с кодом находится на GitHub). Приложение состоит из двух частей:

  1. Просмотр информации о конференциях JUG Ru Group и JUG-митапах (с поиском данных о конференциях, спикерах, докладах, просмотром видео докладов и презентаций);
  2. Игра Угадай спикера.

Первая часть приложения была дополнена возможностью просмотра статистики по компании, к которым относятся спикеры на момент последнего доклада или в настоящий момент. По количеству сделанных докладов (так сказать, в командном зачёте) уверенно побеждает компания JetBrains. То есть в настоящий момент в данной компании работают спикеры, сделавшие в сумме наибольшее количество докладов в конференциях JUG Ru Group (с учётом и без учёта Java-митапов).



Во второй части приложения (в игре Угадай спикера) было добавлено 2 новых режима: угадывание компании по спикеру и спикера по компании. Можно проверить, так ли хорошо Вы знаете принадлежность спикеров к их компаниям. В режиме угадать спикера по компании правильным ответом может быть множественный выбор спикеры, относящиеся к одной компании.



Java-код программы на 100% процентов покрыт тестами, для сбора информации о покрытии кода используется библиотека JaCoCo, для контроля покрытия тестами и качества кода сервисы Codecov и SonarCloud.

На конференции Heisenbug две недели назад Евгений Мандриков, ведущий разработчик проектов JaCoCo и SonarQube, проводил воркшоп Покрытие кода в JVM. Посмотреть видео воркшопа могут обладатели билета на конференцию Heisenbug или единого билета.

Закрытие


Открывавшие три дня назад Алексей Фёдоров и Глеб Смирнов и закрыли конференцию. Традиционный выход на сцену спикеров, участников программного комитета и организаторов вынужденно пока заменён демонстрацией слайдов с фото.



В качестве итогов можно сказать, что конференция стала ещё интереснее и разнообразнее (по крайней мере, насколько ей это позволяют рамки онлайн-конференции). Любители социальности тоже получили в этом сезоне желаемое в виде возможности пообщаться, пусть виртуально.

Всем до следующих Java-конференций!

Осенне-зимний сезон онлайн-конференций JUG Ru Group продолжится конференциями DotNext, DevOops (2-5 декабря 2020 года) и SmartData (9-12 декабря 2020 года). Можно посетить любую из конференций отдельно или купить единый билет на все восемь конференций сезона (пять уже прошедших и три оставшихся), видео докладов при этом доступны сразу же после завершения конференций.
Подробнее..

Project Loom Современная маcштабируемая многопоточность для платформы Java

19.02.2021 18:05:42 | Автор: admin


Эффективное использование многочисленных ядер современных процессоров сложная, но всё более важная задача. Java была одним из первых языков программирования со встроенной поддержкой concurrency. Ее concurrency-модель, основанная на нативных тредах, хорошо масштабируется для тысяч параллельно выполняющихся стримов, но оказывается слишком тяжеловесной для современного реактивного программирования с сотнями тысяч параллельных потоков.


Ответ на эту проблему Project Loom. Он определяет и реализует в Java новые легковесные параллельные примитивы.


Алан Бейтман, руководитель проекта OpenJDK Core Libraries Project, потратил большую часть последних лет на проектирование Loom таким образом, чтобы он естественно и органично вписывался в богатый набор существующих библиотек Java и парадигм программирования. Об этом он и рассказал на Joker 2020. Под катом запись с английскими и русскими субтитрами и перевод его доклада.



Меня зовут Алан Бейтман, я работаю в группе Java Platform в Oracle, преимущественно над OpenJDK. Сегодня я буду говорить о Project Loom.


Мы занялись этим проектом в конце 2017 года (точнее, технически в начале 2018-го). Он появился как проект в OpenJDK для того, чтобы упростить написание масштабируемых многопоточных приложений. Цель в том, чтобы позволить разработчикам писать масштабируемые многопоточные приложения в так называемом синхронном стиле. Это достигается путем доведения базовой единицы многопоточности потока до такой легковесности, чтобы им можно было представлять любую параллельную задачу. Даже задачи, которые блокируются или выполняются в течение длительного времени.


Кто-то говорит: чем больше несвязанных запросов поступает в серверное приложение, тем большей степени многопоточности можно достичь.


План выступления такой:


  1. Начну с пары слов о мотивации этого проекта.
  2. Поговорю о том, как мы имплементировали эти так называемые легкие потоки.
  3. Переключусь на IDE и покажу несколько демо, напишу немного кода.
  4. Наконец, рассмотрю другие аспекты проекта.

Потоки


Платформа Java (и язык, и JVM) во многом построена на концепции потоков:


  • Если вы сталкиваетесь с исключением, то получаете трассировку стека определенного потока.
  • Вы можете связать некоторые данные с потоками, используя ThreadLocal.
  • Если вы находитесь в отладчике и выполняете пошаговое выполнение кода, вы шагаете по выполнению потока. Когда вы нажимаете step over, это означает переход к следующей инструкции в потоке, с которым вы работаете.
  • А когда вы находитесь в профайлере, профайлеры обычно группируют данные по потокам, сообщают вам, какие потоки выполняются и что они делают.

В общем, всё, что касается платформы и инструментов, связано с потоками.


В Java API поток означает java.lang.Thread. В реализации JDK есть только одна реализация потока, которая фактически основана на потоке операционной системы. Между java.lang.Thread и потоком ОС существует связь один-к-одному. Те из вас, кто уже давно работает с платформой Java, могут вспомнить зелёные потоки в ранних выпусках JDK. Я немного расскажу об этом позже. Но по меньшей мере последние 20 лет, когда мы говорим о java.lang.Thread, мы говорим о тонкой оболочке вокруг потока ОС.


Cами потоки ОС ничего не знают о Java. Они очень общие. Обычно они должны поддерживать множество разных языков и сред выполнения. Они ничего не знают о том, как эти языки и программы используют стек, и им обычно приходится выделять очень большой фиксированный стек, чтобы поддерживать универсальность
программ, которые должны выполняться.


Другой аспект потоков операционной системы заключается в том, что они проходят через ядро ОС для переключения контекста, что обычно требует
значительное количество времени. В течение многих лет это было около микросекунды или больше.


Еще одна особенность потоков операционной системы заключается в том, что ядро ОС должно иметь некоторую форму планирования. Ему нужно выбрать, какой поток
запускать на каждом ядре процессора. Веб-серверы ведут себя совсем иначе, чем, например, поток с вычислениями для воспроизводения видео. Планировщик ОС должен быть очень общим и в некотором роде компромиссным, чтобы поддерживать все различные варианты использования.


Давайте немного поговорим об использовании потоков. Можно писать многопоточные приложения в стиле, который мы называем синхронным. Простой, императивный блокирующий синхронный код. Задачи выполняются в одном потоке от начала до конца. Код обычно очень легко читать и писать. Именно так большинство из нас, я думаю, учились его писать. Мы научились работать так с одним потоком до того, как узнали, что такое поток.


Этот синхронный стиль очень хорошо сочетается с дизайном языка Java. Он очень хорошо сочетается с инструментами. И в целом, как любит говорить мой коллега Рон Пресслер, гармонично сочетается с платформой. Но поскольку поток по сути представляет собой тонкую оболочку вокруг потока ОС, это ограниченный ресурс.


Если каждая транзакция или запрос использует поток, то максимальное количество потоков это максимальное количество транзакций, которые система может обрабатывать за раз. По сути, это наш уровень многопоточности.


А с современным сервером теоретически вы можете иметь миллионы сетевых подключений. Я видел, как Хайнц Кабуц делает демо с Project Loom, где он фактически использовал два миллиона соединений. И серверы могут поддерживать подобное, если у них достаточно памяти.


Итак, если у вас миллионы сетевых подключений, но только тысячи активных потоков, потоки становятся вашим ограничивающим фактором, если на каждое соединение приходится один поток. Так что они ограничивают наш уровень многопоточности. И это, безусловно, может сильно повлиять на пропускную способность.


Ладно, что нам с этим делать?


Если потоки дорогой ресурс, почему бы нам ими не делиться? Это означает пулы потоков. Вместо создания потока для каждого запроса или транзакции мы заимствуем поток из пула, выполняем транзакцию, а затем возвращаем его в пул.


Но у пулов много проблем. Думаю, большинство тех, кто их использовал, знает о проблеме того, как они засоряют ThreadLocals. Эта так называемая утечка памяти с пулами потоков существует долгое время. Также проблематична отмена: если я хочу отменить транзакцию, но она почти завершена, я, возможно, прерываю поток после того, как он был взят для другой транзакции.


И даже если бы мы решили приведенные проблемы, этого все равно недостаточно, потому что мы все еще выполняем транзакцию от начала до конца в одном потоке. Это занимает его на протяжении всей операции, а уровень многопоточности по-прежнему ограничен количеством потоков, которые может обработать ОС.


Мы можем заметить, что для большого количества запросов и транзакций,
которые не упираются в CPU, поток проводит большую часть своего времени в ожидании, в блокировке, ожидая базу данных, IO, что-то еще. А нам, на самом деле, не нужен поток, когда он ожидает.


Предположим, что мы использовали подход, при котором поток во время ожидания возвращается в пул. Это позволяет одновременно выполнять гораздо больше транзакций. Проблема в том, что многие API, блокирующие API, удерживают поток на протяжении какой-либо операции в ожидании блокировки, ожидании данных в сокете.


Это приводит нас к созданию новых API, по существу, несовместимых со старыми. Или в итоге у нас есть синхронные и асинхронные версии API.


Другой вопрос, что это вынуждает нас разделять транзакцию или запрос на мелкие кусочки, где разные части работают на разных потоках. Большая проблема с этим мы теряем всякую связь с потоками, контекст становится очень и очень трудно отслеживать. Например, если появилось исключение, которое было брошено для определенной части или определенного этапа транзакции, у меня нет общего контекста, где оно на самом деле было брошено.


Когда мы отлаживаем, это будет отладка лишь этапа транзакции. Если мы профилируем, то не увидим многого о том, что на самом деле происходит. Потому что многие транзакции выглядят ничего не делающими, они просто ждут IO. Профайлер, который смотрит на незанятый пул потоков, не особо много видит.


Я говорю здесь о том, что мы называем асинхронным стилем. Его преимущество в том, что он очень масштабируемый. Количество транзакций больше не ограничено количеством потоков. Но его трудно читать и иногда трудно поддерживать, потому что мы потеряли контекст.


Таким образом, в целом это позволяет нам лучше использовать аппаратные ресурсы, но наше приложение сложнее писать и поддерживать.


Что приводит нас к дилемме.



Разработчики могут написать простой синхронный код и потратить больше денег на оборудование. Или, если вы хотите эффективно использовать оборудование и управлять асинхронным приложением, тогда мы больше платим разработчикам.


Итак, как нам решить эту дилемму? Что, если бы мы могли снизить стоимость потоков и иметь их неограниченное количество? Тогда мы могли бы написать простой синхронный код, который гармонирует с платформой, полностью использует оборудование и масштабируется как асинхронный код. Project Loom именно об этом.


API


Давайте пойдем дальше и поговорим немного об API.


Если Project Loom снижает стоимость потоков, то как это будет отражаться на разработчиках и на API? Эта проблема сложнее, чем кажется на первый взгляд, и мы потратили более двух лет на борьбу с ней.


Один из вариантов, с которого мы начали и к которому в итоге вернулись, это
использование для легких форм потоков java.lang.Thread. Это старый API, который существует с JDK 1.0. Проблема в том, что у него много багажа. Там есть такие вещи, как группы потоков, загрузчик классов контекстов потоков. Есть множество полей и других API, которые связаны с потоками, которые просто не интересны.


Другой вариант начать все сначала и ввести совершенно новую
конструкцию или новый API. Если вы с самого начала интересовались Project Loom, возможно, вы видели некоторые из ранних прототипов, где мы представили для дешевых легких потоков совершенно новый API под названием fiber.


Помимо изучения API, мы также много изучали, как люди используют потоки. Оказалось, что одни их части используются очень широко, другие в меньшей степени. Thread.currentThread() используется и прямо и косвенно везде, например, для блокировки.


Вопрос, который часто возникает в викторинах: Сколько раз Thread.currentThread() используется при первом использовании популярной библиотеки логирования? Люди, не знающие ответа на этот вопрос, могут ответить 2 или 5. Правильный ответ 113.


Другой широко используемый аспект потока это ThreadLocals. Они используются везде, что иногда не радует. Если сломать Thread.currentThread() или ThreadLocals, то в контексте этих новых более дешевых потоков будет не запустить много уже существующего кода. Поэтому вначале, когда у нас был fiber API, нам пришлось эмулировать Thread API, чтобы существующий код запускался в контексте того, что называлось в то время fiber. Таким образом, мы могли уйти от кода, использующего Thread, не повредив нарыв.


Итак, .currentThread() и Threadlocals очень широко используются. Но в потоках есть и редко используемый багаж. И здесь нам немного помогает расширенная политика депрекации. Если некоторые из этих старых областей со временем могли бы исчезнуть, подвергувшись депрекации, окончательной депрекации и, в конечном итоге, удалению тогда, может быть, удастся жить с java.lang.Thread.


Два года исследований, около пяти прототипов и мы пришли к выводу, что избежать
гравитационного притяжения 25 лет существующего кода невозможно. Эти новые дешевые потоки будут представлены с существующим API java.lang.Thread. То есть java.lang.Thread будет представлять и потоки ОС, и новые дешевые потоки.


Мы также решили дать этим новым потокам имя. Оно появилось благодаря Брайану Гетцу, он придумал название виртуальный поток (virtual thread).


Использование привычного Thread хорошая новость для разработчиков. Нет новой модели программирования, нет новых концепций для изучения, вместо этого вам фактически придется отучиться от некоторых старых привычек. Когда я говорю отучиться, я имею в виду такие вещи, как пулы потоков, ThreadLocals и так далее.


Как реализованы эти виртуальные потоки?



Они мультиплексируются поверх небольшого пула потоков операционной системы. Я сказал потоки во множественном числе, и вот тут уместно вспомнить уже упомянутые green threads. Ранние выпуски JDK, особенно 1.0.1.1 с классической виртуальной машиной, поддерживали модель, где потоки мультиплексировались в один-единственный поток ОС. То, что мы делаем теперь, перекликается с этим, но сейчас речь о более чем одном потоке ОС.


Итак, у нас есть набор потоков, на которые эти виртуальные потоки мультиплексируются. Под капотом виртуальная машина HotSpot была обновлена для поддержки новой конструкции: scoped stackful one-shot delimited continuations. Виртуальные потоки объединяют континуации в HotSpot с планировщиками в библиотеке Java. Когда код, выполняющийся в виртуальном потоке, блокируется, скажем, в операции блокировки или в блокирующей IO-операции, соответствующая континуация приостанавливается, стек потока, на концептуальном уровне, вымещается в кучу Java, а планировщик выберет и возобновит другой виртуальный поток в этом же потоке ОС. Исходный виртуальный поток может быть возобновлен в том же потоке ОС или в другом.


Таким образом, код, в котором есть остановка и возобновление, может делать это в разных потоках ОС с течением времени. Есть небольшой набор потоков операционной системы, который обычно как минимум соответствует количеству ядер в системе. Они поддерживают выполнение многих виртуальных потоков, осуществляя прогресс кусочек за кусочком.


Пользовательский код, использующий API Java, не знает о распределении, которое
происходит под капотом, а yield и resume происходит глубоко в библиотеках JDK, поэтому мы говорим, что планирование является вытесняющим и не требует сотрудничества со стороны кода пользователя.


С точки зрения стоимости, поток ОС слева, виртуальный поток справа.



Обычно операционная система резервирует около мегабайта стека для потока операционной системы. Некоторые ядра выделяют дополнительные данные ядра, и 16КБ не редкость. Это то, что операционная система имеет на поток ОС. Кроме того, виртуальная машина HotSpot добавляет к этому пару КБ метаданных.


Виртуальные потоки намного дешевле, текущий прототип составляет около 256 байт на виртуальный поток. Еще есть стек, он уменьшается и увеличивается по мере необходимости и обычно составляет пару КБ в этом главное преимущество
виртуальных потоков перед потоками ОС.


Переключение задач также немного лучше, в типичных ОС оно составляет около микросекунды, в некоторых случаях может быть хуже. Лучший вариант с виртуальными потоками на данный момент работает лучше, около пары сотен наносекунд. Меньший размер и лучшее время переключения контекста означают, что мы можем иметь столько потоков, сколько захотим, и уровень многопоточности может
расти без ограничений.


Самое время перейти от слайдов к IDE и показать вам несколько примеров в коде.


Демо


У меня открыта IDE с пустым методом, и мы начнем с самого начала.


import ...public class Demo {    public static void main(String[] args) throws Exception {...}    void run() throws Exception {    }}

Я упомянул, что мы ввели новый фабричный метод, и начну с использования фабричного метода Thread.startVirtualThread().


import ...public class Demo {    public static void main(String[] args) throws Exception {...}    void run() throws Exception {        Thread thread = Thread.startVirtualThread(() -> System.out.println("hello"));        thread.join();    }}

Вывел сообщение hello, ничего особенного. Это немного отличается от использования конструкторов и метода start(), здесь всего лишь один фабричный метод.


Я изменю тело лямбда-выражения, просто выведу трассировку стека, чтобы вы могли видеть, что на самом деле происходит.


void run() throws Exception {    Thread thread = Thread.startVirtualThread(Thread::dumpStack);    thread.join();}

Этот референс-метод просто вызывает дамп стека в контексте виртуального потока.



Возможно, это выглядит немного иначе, чем то, что вы видели бы с обычным java.lang.Thread, потому что фреймы, которые вы видите здесь, не те, что вы видите в обычном JDK. Это своего рода эквивалент запуска потока, потому что виртуальный поток запускает континуацию. Это дает представление о том, в чем вы можете увидеть разницу.


Давайте рассмотрим еще один из аспектов API. Что делает этот startVirtualThread()?


В дополнение к введению фабричных методов для создания виртуальных потоков, текущий прототип имеет новый билдер для создания потоков. Создадим билдер с помощью метода Thread.builder(). Мы можем при этом вызвать несколько методов, позволяющих настроить поток: является ли он потоком-демоном, какое у него имя и некоторые другие аспекты.



В числе этих методов есть virtual(). Создание виртуального потока cо startVirtualThread(), было, по сути, тем же самым. Вот длинная форма того, что я сделал минуту назад:


void run() throws Exception {    Thread thread = Thread.builder().virtual().task(() -> {        System.out.println("hello");    }).start();    thread.join();    }}

Мы снова сделали то же самое многословнее, но теперь использовали билдер потоков. А он избавляет нас от того, чтобы сначала использовать конструктор для создания потоков, а затем вызывать setDaemon() или setName(). Это очень полезно.


Это хорошее улучшение API для тех, кто в конечном итоге использует Thread API напрямую. Запускаем и получаем то же, что и в случае с startVirtualThread().


Еще мы можем создать ThreadFactory.


void run() throws Exception {    ThreadFactory factory = Thread.builder().name(prefix:"worker-", start:0).factory();}

Это создает фабрику потоков она создает потоки, которые называют себя worker-0, worker-1, worker-2 и так далее. На самом деле worker это только начальный аффикс, который добавляется к префиксу. Это еще один полезный способ создания фабрик потоков.


Покажу вам простой пример того, что вы можете делать с билдером потоков, используя возможности, которые дают нам дешёвые виртуальные потоки.


Большинство людей фактически не используют Thread API напрямую. Начиная с JDK 5, они перешли на использование ThreadExecutor и других API из java.util.concurrent.


Я хочу показать вам использование одного из этих ThreadExecutor. Мы создадим множество потоков и покажем вам, что на самом деле происходит.


Я собираюсь создать ExecutorService executor:


try (ExecutorService executor = Executors.newVirtualThreadExecutor()) {}

Этот фабричный метод для Executors создает виртуальные потоки. Обратите внимание, что здесь я использую try-with-resources. Одна из вещей, которые мы сделали в Loom, мы модернизировали ExecutorService для расширения AutoCloseable, чтобы вы могли использовать их с конструкцией try-with-resources.


Приятная вещь в том, что когда он закрыт, как на примере сверху, он гарантирует, что все задачи, которые являются потоками в этом случае, будет завершены до того, как завершится закрытие. На самом деле закрытие будет ждать, пока все задачи или потоки не будут завершены, что очень полезно. Этот тип Executor'а создает поток для каждой задачи, поэтому он сильно отличается от пулов потоков, которые вы обычно создаете с помощью фабричного класса Executors.


Давайте создадим здесь миллион потоков.


import ...  public class Demo {      public static void main(String[] args) throws Exception {...}      void run() throws Exception {          try (ExecutorService executor = Executors.newVirtualThreadExecutor()) {              IntStream.range(0, 1_000_000).forEach(i -> {                  executor.submit(() -> { });              });          }      }      String fetch(String url) throws IOException {...}      void sleep(Duration duration) {...}  }

Я использую IntStream.range(), вместо цикла for. Это вызовет метод executor.submit() один миллион раз, он создаст миллион потоков, которые ничего не делают. Если это запустить, ничего интересного не произойдет Process finished with exit code 0.


Для наглядности давайте добавим счетчик, который будет обновляться каждым из потоков.


import ...public class Demo {    public static void main(String[] args) throws Exception {...}    void run() throws Exception {        AtomicInteger counter = new AtomicInteger();        try (ExecutorService executor = Executors.newVirtualThreadExecutor()) {            IntStream.range(0, 1_000_000).forEach(i -> {                executor.submit(counter::incrementAndGet);            });        }        System.out.println(counter.get());    }    String fetch(String url) throws IOException {...}    void sleep(Duration duration) {...}  }

Мы создаем Executor, отправляем миллион задач, каждая из этих задач будет увеличивать счетчик, и когда все закончится, выводится значение счетчика. Если все работает правильно, как у нас, должен быть выведен миллион.


Отрабатывает быстро как видите, эти потоки очень дешевы в создании.


Давайте покажу вам, что еще мы можем делать с Executor'ами. У меня есть метод, который просто принимает байты из определенного URL-адреса, создает из него строку. Это не очень интересно разве что то, что это блокирующая операция.


String fetch(String url) throws IOExpection {    try (InputStream in = URI.create(url).toURL().openStream()) {        byte[] bytes = in.readAllBytes();        return new String(bytes, charsetName:"ISO-8859-1");    }}

Он создает сетевые подключения, HTTP-соединение будет ожидать результатов от сервера, мы просто воспользуемся этим как частью примера.


Давайте посмотрим вот на что:


void run() throws Exception {       try (ExecutorService executor = Executors.newVirtualThreadExecutor()) {           Callable<String> task1 = () -> fetch(url:"https://jokerconf.com/");           Callable<String> task1 = () -> fetch(url:"https://jokerconf.com/en");           String first = executor.invokeAny(List.of(task1, task2));           System.out.println(first.length());       }     }

Вот одна задача, которая получает HTML-страницу с jokerconf.com. Я собираюсь создать вторую задачу, которая будет делать то же самое, но будет получать английскую версию страницы. Если кто-то говорит на двух языках, то он сможет читать и русскую и английскую страницу, это не имеет значения.


Мы используем executor.invokeAny() и даем ему две задачи.
ExecutorService имеет несколько комбинаторов, invokeAny(), invokeAll(), они существуют уже давно. Мы можем использовать их с виртуальными потоками.


В данном случае мы подставим в first результат, в зависимости от того, какая из этих задач будет выполнена первой.


Я запущу два виртуальных потока. Один из них получит первую страницу, другой вторую, в зависимости от того, что вернется первым, я получу результат в String first. Другой будет отменен (прерван). Запускаем и получаем результат: 200160, то есть одна из страниц размером 200 КБ.


Итак, что произошло: были созданы два потока, один выполнял блокирующую операцию получения данных с первого URL-адреса, другой со второго URL-адреса, и я получил то, что пришло первое. Если запущу еще пару раз, буду получать разные значения: одна из страниц всего 178 КБ, другая 200 КБ.


Это один из комбинаторов. На самом деле, я бы мог хотеть обе страницы и что-то с ними сделать, в этом случае я мог бы использовать invokeAll().


void run() throws Exception {       try (ExecutorService executor = Executors.newVirtualThreadExecutor()) {           Callable<String> task1 = () -> fetch(url:"https://jokerconf.com/");           Callable<String> task1 = () -> fetch(url:"https://jokerconf.com/en");           executor.invokeAll(List.of(task1, task2)); List>Future>String>>                   .stream() Stream<Future<String>>                   .map(Future::join) Stream<String>                   .map(String::length) Stream<integer>                   .forEach(System.out.println);       }     }

Как видите, это не слишком интересно всё, что мы здесь делаем, это invokeAll(). Мы выполним обе задачи, они выполняются в разных потоках. InvokeAll() блокируется до тех пор, пока не будет доступен результат всех задач, потому что вы получаете здесь Future, которые гарантированно будут выполнены. Создаем поток, получаем результат, получаем длины, а затем просто выводим их. Получаем 200 КБ и 178 КБ. Вот что вы можете делать с ExecutorService.


Покажу вам еще кое-что. В рамках Loom мы немного поработали над CompletableFuture, чтобы вы могли делать подобное. Добавить задачу и получить CompletableFuture, а не Future, и тогда я смогу написать такой код:


void run() throws Exception {       try (ExecutorService executor = Executors.newVirtualThreadExecutor()) {           Callable<String> task1 = () -> fetch(url:"https://jokerconf.com/");           Callable<String> task1 = () -> fetch(url:"https://jokerconf.com/en");           CompletableFuture<String> future1 = executor.submitTask(task1);           CompletableFuture<String> future2 = executor.submitTask(task2);           CompletableFuture.completed(future1, future2) Stream<CompletableFuture<String>>                   .map(Future::join) Stream<String>                   .map(String::length) Stream<integer>                   .forEach(System.out.println);       }     }

Я вызываю в CompletableFuture-метод под названием completed(). Это возвращает мне стрим, который заполняется Future в ленивом режиме по мере их завершения. Это намного интереснее, чем invokeAll(), который я показал ранее, поскольку метод не блокируется, пока не будут выполнены все задачи. Вместо этого поток заполняется результатом в ленивом режиме. Это похоже на стримо-подобную форму CompletionService, если вы когда-нибудь такое видели.


Я запущу несколько раз, порядок, вероятно, будет случайным. В любом случае, это дает вам представление о других вещах, которые вы можете делать с CompletableFuture, стримами и виртуальными потоками.


Еще одна вещь, которую я хочу сделать, забегая вперед. Мы еще поговорим об этом подробнее после демо. В прототипе есть ограничение. Виртуальные потоки делают то, что мы называем закреплением потока ОС, когда мы пытаемся выполнить IO-операции, удерживая монитор. Я объясню это лучше после демо, но пока у меня открыта IDE, покажу вам это на практике и объясню, на что это влияет.


import ...public class Demo {    public static void main(String[] args) throws Exception {...}    void run() throws Exception {        Thread.startVirtualThread(() ->            sleep(Duration.ofSeconds(2));        }).join();    }    String fetch(String url) throws IOException {...}    void sleep(Duration duration) {...}  }

Виртуальный выполняет блокирующую операцию, спит две секунды, завершается. Пока не слишком интересно. Теперь предположим, что он должен спать, пока держит монитор.


void run() throws Exception {        Thread.startVirtualThread(() -> {            Object lock = new Object();            synchronized (lock) {                sleep(Duration.ofSeconds(2));            }        }).join();}

Я запускаю это с диагностическим свойством, которое даст мне трассировку стека, когда поток закреплен.



Мы видим трассировку стека, которая говорит мне, что поток был закреплен. Она снабжена примечаниями, которые говорят мне, где удерживается монитор. Это ограничение в нашем текущем прототипе. По сути, потоки могут блокироваться, удерживая монитор. Поток закрепляет соответствующий поток ОС, эта скорее качество сервиса текущей реализации, чем ошибка. Я вернусь к тому, что мы делаем c этим, через несколько минут. Это своего рода базовое демо.


У меня есть более полная демонстрация, переключусь для этого на немного другой проект.


package demo;import ...@Path("/")public class SleepService {    @GET    @Path("sleep")    @Producers(MediaType.APPLICATION_JSON)    public String sleep(@QueryParam("millis") long millis) throws Exception {        Thread.sleep(millis);        return "{ \"millis\": \"" + millis + "\" };    }}

Уже существуют несколько серверов, которые работают с виртуальными потоками.
Есть сервер Helidon MP. Я думаю, MP означает MicroProfile. Helidon настроен, они недавно внесли некоторые изменения, теперь вы можете запустить его со свойством, при котором он будет запускать каждый запрос в отдельном виртуальном потоке. Мой код может выполнять операции блокировки, и они не будут закреплять базовый поток ОС. У меня может быть намного больше запросов, чем потоков, работающих одновременно и выполняющих блокирующие операции, это действительно очень полезно.


Первый сервис, который я вам покажу, что-то вроде эквивалента hello world при использовании подобных служб. Запускаем код из примера выше, переходим в окно терминала и вводим curl-команду.



Curl-команда кодирует параметр миллисекунд обратно в JSON, который возвращается.
Не слишком интересно, потому что все, что было сделано, это сон. Остановлю сервер и вставлю Thread.dumpStack():


public String sleep(@QueryParam("millis") long millis) throws Exception {    Thread.dumpStack();    Thread.sleep(millis);    return "{ \"millis\": \"" + millis + "\" };}

Снова запущу сервер. Я снова выполняю команду curl, которая устанавливает HTTP-соединение с сервером, она подключается к эндпоинту сна, параметр millis=100.


curl http://localhost:8081/sleep?millis=100


Посмотрим на вывод: печатается трассировка стека, созданная Thread.dumpStack() в сервисе.



Огромная трассировка стека, мы видим здесь кучу всего: код Helidon, код Weld, JAX-RS Довольно интересно просто увидеть это всё. Это сервер, который создает виртуальный поток для каждого запроса, что довольно интересно.


Теперь посмотрим на более сложный сервис. Я показал вам комбинаторы
invokeAny и involeAll в простом демо в самом начале, когда показывал новый ExecutorService.


import ...@Path("/")public class AggregatorServices {    @GET    @Path("anyOf")    @Produces(MediaType.APPLICATION_JSON)    public String anyOf(@QueryParam("left") String left,                        @QueryParam("right") String right) throws Exception {        if (left == null || right == null) {            throw new WebApplicationException(Response.Status.BAD_REQUEST);        }        try (var executor :ExecutorService = Executors.newVirtualThreadExecutor()) {            Callable<String> task1 = () -> query(left);            Callable<String> task2 = () -> query(right);            // return the first to succeed, cancel the other            return executor.invokeAny(List.of(task1, task2));        }    }    @GET    @Path("allOf")    @Produces(MediaType.APPLICATION_JSON)    public String allOf(@QueryParam("left") String left,                        @QueryParam("right") String right) throws Exception {        if (left == null || right == null) {            throw new WebApplicationException(Response.Status.BAD_REQUEST)        }        try (var executor :ExecutorService = Executors.newVirtualThreadExecutor()) {            Callable<String> task1 = () -> query(left);            Callable<String> task2 = () -> query(right);            // if one falls, the other is cancelled            return executor.invokeAll(List.of(task1, task2), cancelOnException: true) List<Future<String>>                    .stream() Stream<Future<String>>                    .map(Future::join) Stream<String>                    .collect(Collectors.joining(delimiter:", ", prefix:"{", suffix:" }"));        }    }    private String query(String endpoint) {...}}

Здесь у нас несколько сервисов, они находятся в этом исходном файле под названием AggregatorServices. Здесь есть две службы, два метода я бы сказал: anyOf и allOf. anyOf выполняет левый и правый запросы и выбирает тот, который возвращается первым, а другой отменяет.


Начнем с anyOf. Я вызвал curl-команду:


curl http://localhost:8081/anyOf?left=/greeting\&right=/sleep?millis=200

localhost:8081 это текущий порт, эндпоинт anyOf, и я дал ей два параметра left и right. Я выполняю это и получаю hello world:


{"message":"Hello World!"}$


Причина в том, что сервис приветствия просто выводит hello world, а сервис сна спит 200 мс. Я предполагаю, что большую часть времени hello world будет быстрее, чем 200 мс, и всегда будет возвращаться hello world.


Если я уменьшу сон до 1 мс, то, возможно, сервис сна завершится раньше, чем другой сервис.


Теперь давайте изменим запрос на allOf, который объединит два результата:


curl http://localhost:8081/allOf?left=/greeting\&right=/sleep?millis=1

Запускаю и получаю два результата.


{ {"message":"Hello World!"}, { "millis": "1" } }$


Что интересно в allOf, он делает два запроса параллельно.


private String query(String endpoint) {        URI uri = URI.create("http://localhost:8081").resolve(endpoint);        return ClientBuilder.newClient() Client                    .target(uri) WebTarget                    .request(MediaType.APPLICATION_JSON) Invocation.Builder                    .get(String.class);    }

Кстати, это блокирующий код. Он использует клиентский API JAX-RS для подключения к этому эндпойнту. Он использует вызов invokeAll(), а затем .stream (), .map для получения результата, а затем Collectors.joining(), для объединения в JSON.


Это простой пример разветвления. Интересно то, что тут invokeAll() это вариант, в котором есть параметр cancelOnException. Если вы хотите вызвать несколько задач одновременно, но если одна из них не работает, вы отменяете все остальные. Это важно сделать, чтобы не застрять в ожидании завершения всех остальных задач.


В этих примерах я использую сборку для раннего доступа Loom. Мы очень близки к первому рампдауну JDK 16, поэтому код, над которым я работаю это JDK 16, каков он сейчас, плюс вся реализация Loom.


Ограничения


Поговорим об ограничениях.


В настоящее время существует два сценария, в которых виртуальные потоки, пытающиеся уступить, не освобождают базовый поток ОС. В примере я показал, как можно получить трассировку стека, когда поток закреплен, что на самом деле очень полезно для диагностики проблем такого типа.


Первый сценарий возникает, когда вы используете нативные фреймы. Если у вас есть код JNI, вы вызываете код JNI, он обращается обратно в код Java, а затем этот код Java пытается заблокироваться или совершить IO-операцию. На континуации есть нативный фрейм, мы мало что можем сделать. Это потенциально постоянное ограничение, но подобное должно происходить очень и очень редко.


Второй случай более проблематичен, и это то, что я показал в демонстрации: попытка
парковки, удерживая монитор. Скорее всего, первая версия будет с этим ограничением, это особенность реализации, влияющая на качество сервиса. В настоящее время ведутся исследования по реимплементации мониторов, чтобы преодолеть это ограничение. Но это серьезный объем работы, на это потребуется время.


На самом деле это не очень критично. По той простой причине, что всё, что сегодня использует мониторы Java, можно механически преобразовать из использования synchronized и wait-notify в использование блокировок из java.util.concurrent. Так что существуют эквиваленты мониторов в блокировках java.util.concurrent и различные формы блокировок, самый простой из которых ReentrantLock, они очень хорошо работают с виртуальными потоками.


Что вы можете сделать при подготовке к Loom?


Если вам нравится Loom и вы заинтересованы в том, чтобы подготовить код для работы с Loom, есть пара вещей, о которых стоит подумать.


Предположим, у вас миллион потоков и код, который использует много ThreadLocals. Хотя виртуальные потоки поддерживают ThreadLocals, при их большом количестве требуется много памяти. Тут есть над чем подумать. Мы уже довольно давно работаем в JDK над устранением многих из ThreadLocals, которые использовались в различных местах.


Распространенным является кэширование объектов SimpleDateFormat.
SimpleDateFormat может быть дорогостоящим в создании, они не являются потокобезопасными, поэтому люди повсеместно кэшируют их в ThreadLocals.


В JDK мы заменили кэширование SimpleDateFormats на новый неизменяемый формат даты java.date dateformatter. Он неизменяем, вы можете сохранить его
в static final поле, это достаточно хорошо. Мы удалили ThreadLocals и из некоторых других мест.


Другая сложность сводится к масштабированию приложения и обработке десятков тысяч запросов. Если у вас много данных на запрос или на транзакцию, это может занимать много места. Если у вас миллион TCP-соединений, это миллион буферов сокетов. Если вы оборачиваете каждый из них в BufferedOutputStream, PrintStream или что-то в этом роде, это много памяти. Мы работали над подобными вещами и в JDK, но я уверен, что дальше по стеку у людей будет много данных на запрос или на транзакцию.


Третье, как я уже говорил, переход от мониторов к java.util.concurrent позволяет избежать краткосрочных проблем.


Я говорил в основном о виртуальном потоке как о потоке в коде, но давайте поговорим о нескольких других вещах.


Расскажу немного об отладчике.



При отладке действительно важно, чтобы при движении по шагам, вы
работали в каком-то контексте. Обычно отладчики Java (в IntelliJ, NetBeans, Eclipse) используют интерфейс отладчика под названием JDI, где под капотом находится wire protocol, а в виртуальной машине есть интерфейс инструментов, называемый JVM Tool Interface или JVM TI, как мы его иногда называем. Это все необходимо обновить, чтобы иметь возможность поддерживать виртуальные потоки.


Оказывается, это значительный объем работы. Отладчики занимаются приостановкой и возобновлением, они фактически перечисляют потоки. Тут возникают сложности с масштабируемостью при переходе от тысяч потоков к сотням тысяч или
миллионам потоков.


Кроме того, наш подход к поддержке подобного в отладчиках оказался сбивающим с толку. Отладчик видит два потока: основной носитель (поток нашей ОС) и виртуальный поток. С этим было связано с множеством проблем, поэтому мы решили остановиться и пересмотреть все это. Так что это область сейчас работает не очень хорошо, но мы близки к тому, чтобы решить эти проблемы. Так что в это время ведется гигантский объем работы для повторной реализации и перестройки частей JVM TI для лучшей поддержки виртуальных потоков.


Итак, мы приближаемся к цели, большая часть деталей уже реализована, и мы надеемся, что очень скоро у нас будет гораздо лучшая ситуация с отладкой.


И последнее, что нужно сказать об отладчиках: кто-то спрашивает, когда мы все это доделаем, будут ли имеющиеся отладчики просто работать? Мы ожидаем, что в отладчики и инструментарий потребуется внести хотя бы некоторые небольшие изменения, чтобы они могли работать с виртуальными потоками. В основном на фронте масштабируемости, не имеет смысла пытаться визуализировать миллион потоков в отладчике. Такие вещи, как группы потоков это уже легаси, и попытки визуализировать что-либо в группах потоков, вероятно, не будут работать хорошо.


Перейдем к виртуальным потокам в профилировщике.


Это тоже очень важная область. Java Flight Recorder был обновлен в сборках Loom для поддержки виртуальных потоков. Я не был уверен, что во время доклада успею продемонстрировать использование JFR с виртуальными потоками, поэтому вместо этого я просто зафиксировал вывод команды print в JFR, просто чтобы показать вам, на что он способен.


В данном случае я сделал запись с JFR.



Он просто называется server.jfr, это имя файла записи. Эта конкретная запись была сделана при запуске сервера Jetty, настроенного для использования виртуальных потоков. Выходные данные показывают одно событие, чтение сокета. И оно произошло в виртуальном потоке. JFR по умолчанию имеет порог, кажется, около 200 мс, он может захватывать медленную операцию чтения, которая занимает больше времени, чем время порога.


Давайте расскажу, что именно здесь запечатлено. virtual = true указывает на то, что это виртуальный поток. Я распечатал всю трассировку стека, поэтому вы можете увидеть, что это действительно работает в виртуальном потоке, мы видим все фреймы, тут используются java.net.url и HTTP для чтения сокета, и это блокирует более чем на 200 мс. Это записано здесь в этой трассировке стека. Это то, что вы можете делать с JFR, что весьма полезно.


Помимо Flight Recorder, поддерживающего виртуальные потоки, существует множество других инструментов и профилировщиков, использующих JVM TI, поэтому нам приходится работать над множеством вещей, чтобы иметь возможность поддерживать профилировщики на основе JVM TI, работающие с виртуальными потоками.


В этой области есть проблемы, о которых я упоминал в контексте отладчиков, попытки визуализировать тысячи и тысячи потоков.


То же самое и с профилировщиками. Если их используют для приложения с миллионом потоков, не думаю, что следует пытаться визуализировать их все, это будет неудобно для пользователя. Это область, которая, вероятно, не будет масштабироваться, по крайней мере, с точки зрения пользовательского интерфейса. Это тип проблем, с которыми мы сталкиваемся при работе с некоторыми инструментами.


Serviceability


Чтобы иметь возможность использовать виртуальные потоки в продакшне, мы должны решить множество других задач по устранению неполадок и диагностике.


Я показал вам довольно простую распечатку трассировки стека, когда потоки закреплены. Будут и другие сценарии, значимые для разработчиков. Они не смогут идентифицировать, например, запущенные виртуальные потоки, выполняющие вычислительные задачи (упирающиеся в CPU), они никогда не блокируются. Было бы полезно идентифицировать их.


Дамп потоков это то, с чем мы боролись в течение некоторого времени. Люди привыкли использовать дампы потоков для устранения неполадок, но что это значит, если у вас миллион потоков? Вы хотите просто увидеть все потоки, но дедуплицировать их? Вы хотите иметь другие формы? Это те вещи, которые нам еще предстоит изучить.


Текущий статус того, где мы находимся с Loom


Цель состоит в том, чтобы получить первую демо-версию с виртуальными потоками. У нас был ряд проблем со стабильностью, неприятные сбои, но мы думаем, что уже решили большинство из этих проблем.


Было много тонких проблем с взаимодействием с многопоточными сборщиками мусора, которые беспокоили довольно долгое время. Мы очень надеемся, что скоро получим сборку для раннего доступа, в которой будут решены эти проблемы.


Производительность также высока, был достигнут значительный прогресс в производительности за последний год, потому что это критически важно.


Поверхность API небольшая, но, как и во всех API, очень важно получить как можно больше обратной связи. API всегда проходят доработку, не бывает так, чтобы всё получилось как надо на первой итерации, мы пройдем через другие итерации, прежде чем все будет сделано.


Поддержка отладчика, как я уже упоминал, была проблемой, мы думаем, что сейчас на правильном пути, и как только мы доделаем последние штрихи, я действительно надеюсь, что у людей, которые обслуживают IDE и отладчики, будет время поработать с нами и создать условия хорошего опыта отладки.


Что еще нужно сделать для нашего первого Preview: нам необходимо выполнить перенос на ARM64 или Aarch64, мы были сосредоточены на 64-разрядной версии Intel на сегодняшний день; и нам нужно что-то сделать с дампом потоков.


Направления для будущего развития


Я должен упомянуть еще несколько аспектов этого проекта. Это такой список из будущего: мы не ожидаем, что перечисленное в нём будет в первой версии.


Во многих случаях для запуска задачи создается виртуальный поток, который выполняет одно действие и дает один результат. В других случаях вам может понадобиться, чтобы виртуальные потоки производили стрим результатов или общались через сообщения той или иной формы.


Как вы видите в других моделях программирования, CSP или Actors. У других языков есть каналы, у Erlang есть почтовые ящики. В Java есть вещи, близкие к этому: есть BlockingQueues, SynchronousQueue, у которой нет емкости, LinkedTransferQueue, у которой есть емкость.


Профессор Даг Ли работал с нами над этим проектом, и он обновил реализации блокирующих очередей в java.util.concurrent, так что они дружелюбны к виртуальным потокам. Он также изучает то, что ближе к каналам. Текущее рабочее название этого проекта conduits, а не каналы, потому что у нас есть каналы в пакете java.nio.channels. Посмотрим, как это пойдет.


Другая область это структурированная многопоточность. При структурированном программировании последовательное выполнение ограничено каким-либо четко
определенным блоком кода. Структурированная многопоточность заключается в распространении контроля на многопоточную среду. По сути, если задача управления разделяется на несколько задач или потоков в некоторой области, то им необходимо снова объединиться, прежде чем выйти из этой области.


В ранних прототипах Project Loom у нас действительно были первые прототипы для исследований в этой области. И мы вернемся к этому, есть проблемные области, связанные с этим. Распространение исключений и ошибок, отмена выполнения и так далее. На данный момент мы сделали, и я показывал это в демонстрациях, модифицировали ExecutorService, чтоб он расширял AutoCloseable, чтобы, по крайней мере, мы могли иметь некоторую конструкцию, которая гарантирует, что все потоки завершатся до продолжения основного потока.


Со структурированной многопоточностью связано то, что мы называем структурированным serviceability или структурированным observability. Я упоминал о проблемах профилировщиков, отладчиков и других инструментов, пытающихся
визуализировать миллионы потоков. Что, если бы эти инструменты каким-то образом исследовали бы структуру или отношения между потоками. Тогда, возможно, нам лучше бы удалось это визуализировать. На это мы готовы потратить больше времени.


Последний пункт в этом списке отмена. Мы сделали несколько прототипов в этой области, несколько прототипов кооперативной отмены. В Java есть механизм прерывания, это устаревший механизм, но на самом деле он очень хорошо работает с виртуальными потоками. Для большинства разработчиков этот механизм находится на слишком низком уровне. Мы хотим понять, сможем ли мы сделать что-то лучше. У нас были механизмы отмены в ранних прототипах. Я полагаю, что основная проблема заключается в том, что наличие двух механизмов одновременно может сбивать с толку, поэтому необходимо подумать над этим немного времени, прежде чем принимать какие-то решения по этому поводу.


Главные выводы


Основные выводы из этого доклада:


Виртуальный поток это поток в коде, во время выполнения, в отладчике, профилировщике и других инструментах.


Виртуальный поток это не оболочка вокруг потока ОС, а, по сути, просто объект Java.


Создание виртуального потока действительно очень дешево, у вас их могут быть миллионы, их не надо объединять в пулы.


Блокировка в виртуальном потоке стоит мало, что позволяет использовать синхронный стиль.


Немного дополнительной информации


Один из замечательных способов внести свой вклад в такой проект, как Project Loom, это загружать его сборки (или делать их самостоятельно из кода) и пробовать его с реальными приложениями. Отправляйте отзывы о производительности, сообщениях об ошибках, проблемах и опыте. Такие вещи очень полезны для такого проекта.


Вот ссылки на сборки раннего доступа: https://jdk.java.net/loom
Список рассылки: loom-dev@openjdk.java.net
И вики-страница: https://wiki.openjdk.java.net/display/loom/Main


У нас не очень получается поддерживать вики-страницу, поэтому список рассылки лучшее место для поиска чего-либо.


Это все, что я хотел рассказать.


Напоследок традиционный слайд Safe harbor: не верьте ничему, что я говорю.



Как можно понять по этому докладу, на наших Java-конференциях хватает хардкора: тут про Java-платформу порой рассказывают те люди, которые её и делают. В апреле мы проведём JPoint, и там тоже будет интересный состав спикеров (многие знают, например, Джоша Лонга из VMware). Часть имён уже названа на сайте, а другие позже появятся там же.
Подробнее..

Ламповые стримы этой недели от JUG Ru Group дискуссия с Королем разработки и не только

21.09.2020 20:06:45 | Автор: admin


Виктория Алмазова на одном из прошедших шоу


На прошлой неделе мы уже рассказали, что можно посмотреть на YouTube в рабочий перерыв, а сегодня анонсируем новые выпуски наших разговорных ютуб-шоу по разным IT-направлениям. Каждый выпуск можно будет смотреть в прямой трансляции, лихо комментируя в чате происходящее и задавая вопросы, а можно позже в записи.


Для затравки: вы наверняка читали пост Объясните, почему мой рокет-саенс бэкенд билдится пару секунд, а четыре формы на фронте полгода. Завтра обсудим с fillpackart в прямом эфире, где он не прав. Под катом ссылки на этот и другие выпуски этой недели.


Вторник, 22 сентября: JS, тестирование и все-все-все


Тяжелое утро с HolyJS


Время: 22 сентября в 10:00 (мск)
Как смотреть: трансляция на YouTube


Евгений Кот (Wrike) и Алексей Золотых (Infobip), конечно же, тоже читали нашумевший хабрапост и решили обсудить его непосредственно с автором fillpackart. Обычно Тяжелое утро с HolyJS рассчитано на JS-разработчиков, но похоже, что в этот раз интересно будет вообще всем!


Heisenbug Show


Время: 22 сентября в 13:30 (мск)
Как смотреть: трансляция на YouTube


Шоу проведет Никита Макаров, руководитель команды автоматизации тестирования в Тинькофф. Вместе со специалистом по тестированию и спикером нескольких предыдущих Heisenbug'ов Андреем Сатариным они пообщаются о тестировании распределенных систем и обсудят особенности QA в таких проектах.




Среда, 23 сентября: Java и .NET


Вторая чашка кофе с Joker


Время: 23 сентября в 14:00 (мск)
Как смотреть: на YouTube-канале


Ведущие Андрей Когунь и Антон Архипов поговорят с Дмитрием Чуйко и Александром Белокрыловым из BellSoft. Речь пойдёт и о Liberica JDK, над которой работают Дмитрий с Александром, и просто о последних Java-новостях.


Барная стойка


Время: 23 сентября в 19:00 (мск)
Как смотреть: трансляция на YouTube


Барная стойка виртуальная замена афтерпати после конференции DotNext с разговорами о технологиях и жизни, шутками и неформальной обстановкой. Шоу ведут Михаил Щербаков и Максим Аршинов. А гость в этот раз Роман Неволин с его разносторонними IT-интересами (от функциональщины до машинного обучения), разнообразным послужным списком (от EPAM до Revolut) и разноцветными волосами.




Четверг, 24 сентября: C++ и Android-разработка


Pure Virtual Cast


Время: 24 сентября в 19:00 (мск)
Как смотреть: трансляция на YouTube


Pure Virtual Cast лайв-шоу от команды C++ Russia. Общаемся с людьми из тусовки C++ о технологиях, разработке и новостях IT.


В новом выпуске ведущие Сергей Платонов и Алексей Веселовский пригласили Александра Бычука, архитектора решений в Лаборатории Касперского. Александр проектирует бэкенд корпоративных систем, очень любит интеграцию и С++ и всегда рад обсудить C++ Enterprise Edition. О чем пойдет речь в выпуске: параллелизм и конкурентность, чем они отличаются и что есть в C++ для этого, какие проблемы. К чему приводит попытка вылечить часть болячек переходом на Go, какие при этом профиты, и какая ждет С++ программиста боль при таком переходе.


GDG live


Время: 24 сентября в 20:00 (мск)
Как смотреть: трансляция на YouTube-канале Mobius


На конференции Mobius 2019 Moscow был отлично принят доклад Степана Гончарова Gradle от А до Я. А теперь на встрече GDG этот доклад будут коллективно разбирать так что можно будет узнать по теме ещё больше и зайти по алфавиту ещё дальше!




Пятница, 25 сентября: DevOps


DevOops в рабочий полдник


Время: 25 сентября в 18:00 (мск)
Как смотреть: трансляция на YouTube


Ведущие Барух Садогурский и Алексей Кирпичников возьмут интервью у Андрея Девяткина: сооснователя консалтинг-агентства FivexL и консультанта, специализирующегося на построении cloud-native платформ доставки приложений в облаке AWS с применением инструментов HashiCorp.




Чтобы не пропускать интересные выпуски и заранее знать их темы, можно подписаться на соответствующую рассылку: Java, C++, тестирование, .NET, JS, DevOps.

Подробнее..

Новая неделя стримов от SvelteJS до Rider

28.09.2020 20:13:28 | Автор: admin


Мы продолжаем нашу серию разговорных YouTube-шоу для различных IT-специалистов. На этой неделе снова будет шесть разных выпусков для самых разных айтишников: например, джависты смогут похоливарить на тему Spring или Microprofile, а плюсовики на тему билд-систем. Полное расписание под катом.


Вторник, 29 сентября: JS и тестирование


Тяжелое утро с HolyJS


Время: 29 сентября в 10:00 (мск)
Как смотреть: трансляция на YouTube


На прошлой неделе у Тяжелого утра с HolyJS был жаркий холиварный выпуск с королём разработки. На этой должно быть более мирно: новым гостем будет Павел Малышев, лидер русскоязычного комьюнити Svelte. Он обсудит с ведущими Евгением Котом и Алексеем Золотых практику применения этого фреймворка с наглядными примерами. В последнее время о Svelte слышно всё чаще как ни ругай слово хайп, а похоже, пора запрыгивать в хайптрейн и получать хотя бы общее представление. Вот и повод это сделать!


Heisenbug Show


Время: 29 сентября в 13:30 (мск)
Как смотреть: трансляция на YouTube
Гостем выпуска станет Анастасия Бобелева QA Director в Exness. Ветераны конференции Heisenbug могут помнить доклад Анастасии Семенюк о тестировании ВКонтакте. Теперь Анастасия уже и не работает ВКонтакте, и не носит фамилию Семенюк, но поговорить с ней от этого не менее интересно. Она обсудит с ведущими работу QA в крупных компаниях, рабочие практики, результаты их применения, роль тестирования за пределами SDLC и то, как с помощью своей работы сделать мир лучше.




Среда, 30 сентября: Java и .NET


Вторая чашка кофе с Joker


Время: 30 сентября в 14:00 (мск)
Как смотреть: на YouTube-канале


Ведущие Андрей Когунь и Владимир Ситников поговорят с Дмитрием Александровым про кровавый энтерпрайз, конференции и GPU и поспорят, что лучше Microprofile или Spring.


Барная стойка


Время: 30 сентября в 19:00 (мск)
Как смотреть: на YouTube-канале


Барная стойка виртуальная замена афтепати после конференций с разговорами о технологиях и жизни, шутками и неформальной обстановкой. Михаил Щербаков и Максим Аршинов в этот раз поговорят с Кириллом Скрыганом: руководителем проекта Rider, который активно участвует в разработке и планировании IntelliJ IDEA, в прошлом один из основных разработчиков ReSharper.




Четверг, 1 октября: C++


Pure Virtual Cast


Время: 1 октября в 18:00 (мск)
Как смотреть: трансляция на YouTube


Системы сборки можно назвать одной из вечных тем в мире С++, о ней горазд поговорить любой. Но Александр Воронков забирался в тему глубже многих например, выступит с докладом о современном CMake на C++ Russia в ноябре. Вот с ним об этом и погоморим. Почему плохо (или хорошо?) писать в старом cmake-стиле? Зачем вообще cmake изучать, неужели там недостаточно знаний уровня "hello world" на cmake?




Пятница, 2 октября: DevOps


DevOops в рабочий полдник


Время: 2 октября в 18:00 (мск)
Как смотреть: канал DevOops на YouTube


В мире devops многие слышали имя Марка Смолли он и популярный конференционный спикер, и автор известных текстов. А его стаж в IT-индустрии превышает сорок лет, так что он лично застал многие тектонические сдвиги в ней. В общем, с ним явно есть о чём поговорить. Вот и поговорим!




Чтобы не пропускать интересные выпуски и заранее знать их темы, можно подписаться на соответствующую рассылку: Java, C++, тестирование, .NET, JS, DevOps.

Подробнее..

Программа Joker 2020 Java изнутри и снаружи

13.10.2020 12:18:27 | Автор: admin


До конференции Joker меньше полутора месяцев, и пришло время рассказать Хабру, о чём будут её доклады.


Если говорить в целом, то так. Помимо докладов, будут воркшопы: они хорошо подходят онлайн-формату. Будут интересные новые спикеры вроде Питера Лори (на Stack Overflow второй в мире по тегу jvm). Конечно, будут и хорошо знакомые имена: Тагир Валеев, Евгений Борисов и не только. Докладов по Spring в этот раз набралось на целый блок.


А за конкретикой приглашаем под кат там описан каждый доклад.


Чтобы быть уверенными, что конференция будет полезной, про каждый доклад мы задаём программному комитету несколько вопросов:


  • чем интересна тема,
  • чем ценен спикер,
  • кому будет полезно,
  • почему стоит слушать это здесь и сейчас.

Порой ответы программного комитета даже лучше объясняют суть доклада, чем официальное описание, поэтому в части случаев мы привели в посте их.


А вот блоки, на которые можно поделить программу:


Вне категории
Воркшопы
VM/runtime
Тулинг и фреймворки
Spring
Языки
и не только


Вне категории


Есть два доклада, на которые хочется обратить особое внимание, а не просто причислять их к какой-то категории. Во-первых, в их случае особенно важно, кто именно будет выступать вероятно, тут многие зрители придут не на тему, а на спикера. Во-вторых, тему заменят ли роботы программистов толком и не категоризируешь!


Novel but practical uses of Java, Peter Lawrey


Если вы пользуетесь Stack Overflow, возможно, Питер Лори уже не раз вам помог: он один из топовых отвечающих по тегам jvm и java. А ещё он архитектор опенсорсных библиотек OpenHFT про Chronicle Queue и Chronicle Map вы могли слышать. Но, в отличие от многих других Java-звёзд, Питер ни разу не прилетал на российские конференции. К счастью, для участия в онлайн-формате лететь не требуется, и теперь он впервые выступит на Joker.


Доклад будет как раз связан с OpenHFT. В этих библиотеках не раз прибегали к нестандартному использованию Java, пользуясь довольно экзотическими фичами. И на Joker Питер расскажет в подробностях об этой экзотике.




Заменят ли роботы программистов, Тагир Валеев


С Идеей кто к нам входит в дом? Джависту каждому знаком? Если Питер Лоури будет на Joker впервые, то доклады Тагира Валеева (lany) здесь давно знают и любят. Только недавно мы расшифровали его предыдущий доклад о маленьких оптимизациях в Java 9-16, а у него уже готов новый: в этот раз на более общую тему, чем обычно.


Разработчики любят всё автоматизировать. Не случится ли в итоге так, что софт начнёт писать себя сам, а мы все окажемся на улице? Может показаться, что раз этой дискуссии десятки лет, любое новое высказывание это воду в ступе толочь. Но интересно, что Тагир работает над инспекциями в IDE то есть как раз ему должно быть лучше других видно, что машины могут понять про код, а что не могут.




Воркшопы


У онлайн-конференций есть неожиданное преимущество: когда сидишь не в зале, а за компьютером, можешь как следует рассмотреть код в IDE спикера и быстро переключиться в свою IDE. Чтобы использовать это преимущество, мы добавили в программу два больших практических выступления, где не просто расскажут о чём-то со слайдами, а покажут всё на практике.


Хватит писать тесты, пора писать спецификации, Алексей Нестеров


В этом воркшопе-стриме-live-сессии Алексей покажет, как с нуля создать и запустить TDD-цикл для Spring Boot-приложения, с примерами на JUnit 5.


Чем интересна тема: Все любят рассказывать, как нужно тестировать, насколько полезно TDD. А вот показать, да так, чтобы было понятно, сложная задача. В этом воркшопе участники смогут ощутить реальную пользу от написания тестов, на практике познакомиться с подходами TDD на примере Spring-приложений и даже обсудить со спикером тонкости и скользкие моменты.
Чем ценен спикер: У Алексея огромный опыт в разработке enterprise приложений на Java. Он разработчик в Spring Cloud Services в VMware, долгое время занимался консалтингом, и точно знает, как нужно писать и тестировать приложения на современных Java0технологиях. Алексей может быть известен широкой публике как один из голосов подкаста Радио-Т.




GraalVM, Thomas Wuerthinger / Олег Шелаев


Чем хороша тема: GraalVM один из самых интересных проектов в экосистеме, которая может повлиять на практически все проекты. От улучшения производительности до популяризации АОТ-компиляции, до открытия экосистем других языков программирования. Каждый должен знать хотя бы базовые вещи про GraalVM. Поэтому воркшоп, где участники могут потрогать GraalVM сами и задать вопросы людям из команды GraalVM отличная возможность для этого.
Чем ценны спикеры: Томас оригинальный автор GraalVM-компилятора, основатель проекта и его лидер. А Олег, пожалуй, больше всех в мире рассказывает про GraalVM, поэтому знает, какие практические вопросы возникают у людей и какие объяснения оказываются самыми понятными. В общем, кто, если не они?




VM/runtime


Мы за то, чтобы разработчик понимал платформу, на которой работает, и на Joker всегда было что-то про кишочки. Но нам интересны не просто абстрактные знания что там внутри, а их влияние на реальную жизнь прикладного разработчика. Как известно, все абстракции протекают а доклады, объясняющие что там за абстракциями, помогают выйти сухим из воды.


Have you really taken the time to know me: A G1 GC saga, Monica Beckwith


Многие заинтересовались сборщиком мусора G1, когда в Java 9 он стал дефолтным. Но с тех пор легко было не следить за его развитием, а со времён девятки в нём появилось немало нового.


Моника Беквит (обладательница звания Java Champion, эксперт в области GC) поможет наверстать, рассказав всё. Тем, у кого в продакшне Java 11+, доклад может моментально помочь правильнее подкрутить ручки, а остальным даст полезную информацию на будущее.




Project Loom: Modern scalable concurrency for the Java platform, Alan Bateman


Чем интересна тема: Эффективное использование многочисленных ядер современных процессоров сложная, но всё более важная задача. Java была одним из первых языков программирования со встроенной поддержкой concurrency. Ее concurrency-модель, основанная на нативных тредах, хорошо масштабируется для тысяч параллельно выполняющихся стримов, но оказывается слишком тяжеловесной для современного реактивного программирования с сотнями тысяч параллельных потоков.


Ответ на эту проблему Project Loom. Он определяет и реализует в Java новые легковесные параллельные примитивы.


Чем ценен спикер: Алан Бейтман, руководитель проекта OpenJDK Core Libraries Project, потратил большую часть последних лет на проектирование Loom таким образом, чтобы он естественно и органично вписывался в богатый набор существующих библиотек Java и парадигм программирования.




Thread Safety with Phaser, StampedLock and VarHandle, Heinz Kabutz / John Green


Чем хороша тема: Компьютер многое умеет делать параллельно, а программистам интересно выжимать из компьютеров максимальные возможности.
Чем ценны спикеры: Хайнц известен многим любителям Java как автор популярного блога javaspecialists.eu, его доклады всегда в топе мировых Java-конференций. С докладом выступает совместно со своим коллегой Джоном Грином.
Кому будет полезно: Программистам, заинтересованным в многопоточном программировании на JVM.




Coordinated Restore at Checkpoint: Быстрый старт OpenJDK, Антон Козлов


Цель проекта Coordinated Restore at Checkpoint запускать Java-приложения за десятки миллисекунд. Проект не связан с GraalVM Native Image, поэтому не имеет свойственных ему проблем для использования, зато приносит новые. Сейчас он в активной разработке.


Доклад может быть полезен интересующимся экспериментальными технологиями в Java, а также разработчикам фреймворков и приложений, для которых важно время запуска и разогрева.


Чем интересна тема: Тема быстрого старта Java-процесса проходит красной нитью по всем докладам 2020 года. То Micronaut, то Spring все как один говорят, что они легковесные, быстрозапускаемые и т.п.
Чем ценен спикер: Антон является автором/коммитером технологии, про которую говорит.




JVM-профайлер, который смог (стать кроссплатформенным), Кирилл Тимофеев


В JetBrains пару лет назад добавили поддержку async-profiler для Mac и Linux. Начали им пользоваться и поняли, что нужен async-profiler, работающий на Windows. На Linux и Mac async-profiler использует механизм POSIX-сигналов и нативную раскрутку стеков. Команде нужно было разобраться, как конкретно работает AsyncGetCallTraces, сравнить его внутреннее устройство с JFR. А если окажется, что их устраивает работа AsyncGetCallTraces, то нужно научиться эмулировать механизм сигналов и раскручивать нативные стеки. Кроме этого нужно решить разные ОС-специфичные проблемы, которые возникнут по пути.


Доклад будет интересен людям, которым интересна нативная и низкоуровневая разработка и всякие приколы уровня ОС. Слушатели узнают, что на самом деле можно решить любую задачу, если выбрать достаточно низкий уровень абстракции.




Docker Who: Маленькие контейнеры сквозь время и пространство, Дмитрий Чуйко


Ваш проект недавно перешел на микросервисную архитектуру? Деплоймент значительно ускорился, но и затраты от передачи данных выросли? Размер самих контейнеров здесь важнее всего. Уменьшить их значит сильно сэкономить на трафике.


Инженеры BellSoft разработали решение полной поддержки Alpine Linux в OpenJDK. А вместе с этим и настоящий ТАРДИС: контейнеры, которые занимают на диске несколько мегабайт, но внутри несут огромный потенциал. С выходом JDK 16, в рамках JEP 386 проект Portola интегрируется в основную ветку OpenJDK. Необходимость в костыльном слое glibc отпадет, все процессы встанут на свои места. Ваша компания сможет пользоваться крошечными образами контейнеров вне зависимости от поставщика дистрибутива. Они доступны уже давно, но официальный статус порта HotSpot для библиотеки musl расширит область его применения и упростит разработки.


В своем докладе Дмитрий (BellSoft) расскажет, какие преимущества принесет поддержка Alpine Linux сообществу OpenJDK и объяснит, как бесплатно оптимизировать Docker образы, поменяв всего пару строк кода. А в конце предложит инструмент для выбора оптимального контейнера под нужды вашего проекта.




Тулинг и фреймворки


Тут, в отличие от блока VM/runtime, никаких вопросов о применимости сразу не возникает: это о том, чем Java-разработчики непосредственно пользуются. Кто-то из спикеров лично создал технологию, о которой будет рассказывать, а кто-то не имеет к ней личного отношения, зато отлично умеет ей пользоваться.


Hidden pearls for high-performance-persistence in Java, Sven Ruppert


В этом выступлении Свен покажет несколько технологических стеков, помогающих справляться с персистентными данными, не заставляя иметь дело с классическими технологическими монстрами горизонтального масштабирования, такими как Kubernetes, Hadoop и многими другими.


Чем интересна тема: Вопрос о том, как разместить данные из памяти JVM в более персистентное хранилище, всегда актуален.
Чем ценен спикер: Свен опытный специалист: говорит чётко, понятно и по теме. А ещё у него очень красивые предзаписи скоро сами увидите!
Кому будет полезно: Будет полезно большинству практикующих инженеров доклад расширит кругозор о доступных решениях для persistence.




Keeping growing software projects under control with Gradle, Jendrik Johannes


Доклад рассмотрит на практическом примере, как Gradle могает справляться со сложностями, возникающими при росте проекта.


Чем интересна тема: Чем больше проект, тем сложнее скрипты сборки. Бытует миф, что Gradle это всегда императивные скрипты, и что разобраться в них невозможно. Мифы нужно развенчивать. Spring Framework, Spring Boot, Hibernate ORM, Micronaut Core, Kotlin что объединяет все эти проекты? Правильно: они собираются Gradle-скриптами.
Чем хорош спикер: Работает в Gradle, видел много разных Gradle-скриптов, и он автор проекта Idiomatic Gradle, где показаны подходы по разделению скрипта сборки на независимые части.
Почему здесь и сейчас: Это новый доклад. В очередной версии Gradle 6.7 как раз идут улучшения и в отношении возможностей, и в отношении документации для многомодульных проектов, поэтому самое время узнать из первых уст и попробовать на практике.




Аерон. High performance-транспорт для low latency-микросервисов, Иван Землянский


Aeron новый транспорт от Real Logic, в состав которого входит небезызвестный автор disruptor Мартин Томпсон. После многих лет работы в сфере HFT он собрал команду и сделал новый транспорт с минимальными накладными расходами.


В докладе Иван хочет раскрыть границы применения этой технологии, основные моменты использования. Вместе мы постараемся понять, какие именно аспекты реализации дают такой хороший перфоманс.




Kafka streams testing: A deep dive, John Roesler / Иван Пономарёв


Хотя Kafka Streams поставляется в комплекте с TopologyTestDriver, что делает юнит-тестирование стриминговых приложений весьма приятным, все не так просто: есть ограничения и определенные классы дефектов, которые данная технология игнорирует. С помощью интеграционных тестов можно проверить поведение реального кластера, но это еще менее просто: мы вступаем на скользкий путь асинхронных тестов с таймаутами, ненадежностью и неразрешимыми вопросами.


Вывод: необходимо использовать оба подхода и голову.


Чем ценен спикер: Кто лучше может рассказать о правильном использовании технологии, чем один из коренных ее разработчиков John Roesler и инженер со шрамами от ее использования Иван Пономарёв?
Чем интересна тема: Ложное чувство уверенности, что твой код протестирован и готов для выкладки на бой, может привести к катастрофическим последствиям, если не знать, как правильно писать тесты для нетривиальной технологии. Этот доклад как раз об этом.
Кому будет полезно: Всем, кто использует Kafka Streams и любит себя достаточно, чтобы писать тесты на свой код.




Change data capture pipelines with Debezium and Kafka streams, Gunnar Morling


В докладе вместе с Гуннаром мы выведем CDC на новый уровень, изучая преимущества интеграции Debezium с потоковыми запросами через Kafka Streams.


Чем интересна тема: Комбинацией Kafka Streams, Debezium, Quarkus
Чем ценен спикер: Доклад от создателя Debezium
Кому будет полезно: Всем энтерпрайз-разработчикам.




Как мы делали SQL в Hazelcast, Владимир Озеров


В этом докладе Владимир расскажет, как он и его команда создавали Hazelcast Mustang новый распределенный SQL-движок, который появился в последней версии Hazelcast IMDG. Будут подробно рассмотрены ключевые технические решения, принятые командой, затрагивающие оптимизатор, сетевой протокол и параллельное выполнение запросов.


Чем интересна тема: Задача подключать SQL к своему приложению довольно актуальна. За недавнее время SQL-запросы появились (или существенно доработались) у очень многих продуктов: Hazelcast, Apache Ignite, Kafka, и т.п. В Apache Calcite сейчас довольно бурно идёт работа от разных вендоров.
Чем ценен спикер: Владимир принимал непосредственное участие в реализации SQL в Hazelcast.
Кому будет полезно: Тем, кто интересуется, как прикручивать SQL-движки к своим хранилищам, особенно на базе Apache Calcite.




Writing test driven apps with http4k, David Denton & Ivan Sanchez


Чем интересна тема: Тема микрофреймворков популярна, и зачастую возиникает вопрос: А нужно ли тащить Spring Boot / Micronaut / далее по списку ради простейшего сервиса? И, правильно, нужно это не всегда. Библиотека http4k интересна по множеству факторов: легковесность, Kotlin, тестируемость.
Чем ценны спикеры David Denton и Ivan Sanchez это два ключевых разработчика в проекте http4k. Они могут и хорошо рассказать, и на вопросы про свой опыт ответить.
Кому будет полезно: На доклад стоит идти тем, кто видел Kotlin и ещё не использовал http4k. Те, кто уже использовал http4k не факт, что узнают много нового именно на самом докладе, но им, безусловно, стоит заглянуть, т.к. задать вопросы авторам и решить свою проблему это дорогого стоит.




Spring


Доклады, так или иначе связанные со Spring, можно было бы включить в блок тулинг/фреймворки. Но в этот раз их набралось столько, что это тянет на отдельный блок!


Spring Patterns для взрослых, Евгений Борисов


Тем, кто работает со Spring, представлять Евгения Борисова не требуется его майский доклад Spring-построитель набрал уже больше 40 000 просмотров. Распотрошив Spring и собрав его заново, теперь он наконец научит нас правильно им пользоваться. На фестивале TechTrain была лайтовая версия этого доклада, а теперь будет для взрослых.


Сколько дизайн-паттернов вы знаете? 24? 36? 100? А сколько из них вы применяете в реальной жизни? 3? 5? 10?


Евгений покажет, как при помощи Spring можно легко и просто реализовывать наиболее популярные паттерны, с которыми мы сталкиваемся в повседневной жизни. Chain of responsibility, strategy, command, lazy initialization, scala traits, AOP, proxy, decorator, и прочие паттерны и концепции, внедренные при помощи Spring, сделают ваш код мягким и шелковистым. А перхоть вашего boilerplate в виде switch-ей, статических методов, наследования, и прочей устаревшей шелухи, посыпется с вашего проекта под радостные крики сонара. Код станет более читабельным, гибким и поддерживаемым. Такой код проще обкладывать тестами и, наконец, это просто красиво.




The path towards Spring Boot native applications, Sbastien Deleuze


Чем интересна тема: GraalVM native image очень модный способ для улучшения производительности Java в serverless или маленьких эфемерных контейнерах. Об этом все говорят, но так как все используют Spring, который изначально сталкивался с некоторыми трудностями конфигурации динамических частей для работы в native image, широко технология ещё не применяется. Этот доклад рассказывает про текущую разработку поддержки GraalVM native image в Spring-приложениях, важных моментах в этой интеграции, как подходить к запуску Spring на native image, что сейчас работает и когда будет работать остальное.
Чем ценен спикер: Кто, если не Себастьян? Лид проекта Spring GraalVM native, коммитер Спринг и один из двоих людей (второй Энди Клемент), лучше всего понимающих, как и почему работает (или ещё не работает) эта комбинация.
Кому будет полезно: Если вы используете Spring и деплоите приложения в облака вам стоит посетить этот доклад. Если вы когда-нибудь думали, а не бросить ли Spring и переписать всё на Quarkus, Micronaut и так далее, вам сюда. И, на самом деле, этот доклад очень хорошо помогает понять некоторые детали GraalVM native image, которые помогут вам разобраться с ним даже без Spring.
Почему здесь и сейчас: Джокер в конце ноября, релиз GraalVM 20.3 релиз 18-го, следующий 0.х релиз Spring GraalVM native скорее всего, через пару дней после. То есть новости про это всё будут самыми свежими. Задать вопросы Себастьяну многого стоит! Спринг и native image может вполне когда-нибудь стать каждодневной реальностью к этому надо быть готовым заранее.




Spring: Your next Java micro-framework, Алексей Нестеров


Часто люди видят Spring Boot как что-то противоположное микро фреймворкам на Java, хотя даже не всегда могут определить что значит микро. Для разных людей это может означать что-то совершенно разное, но чаще всего под этим имеют в виду производительность в рантайме и продуктивность разработки, в сочетании с простотой кода.


Алексей покажет, что вовсе не обязательно бросать горячо любимый Spring Boot, чтобы получить многие фичи, которые предлагают микрофреймворки! Быстрый запуск и перезапуск, LiveReload, запуск и удаленная разработка прямо в контейнере, компиляция в нативный код, конфигурация приложения без аннотаций и многое другое, что вы ожидаете от микрофреймворка.




Rsocket + Spring: A full throttle introduction, Mark Heckler / Олег Докука


Чем интересна тема: Реактивное программирование новый тренд, ну а Спринг всегда в моде! Марк держит руку на пульсе первого и является экспертом второго. Он поделится инсайдами в работе свеженького реактивного протокола RSocket в Спринге.
Чем ценны спикеры: Марк Developer Advocate в Spring, и его задача разбираться во всем, что так или иначе связано с данным фреймворком. А у Олега на наших конференциях был уже целый ряд успешных докладов, связанных с реактивным программированием. Раз тут тема одновременно про Spring и реактивщину, тут они явно нашли друг друга!




Spring Boot fat JAR: Тонкие части толстого артефакта, Владимир Плизга


Одна из известнейших фич Spring Boot упаковка целого приложения в т.н. толстый JAR, который потом just runs. Это реально работает, и для многих ситуаций этого достаточно. Но если вы не доверяете магии и/или столкнулись с проблемами при развертывании толстого JAR, то вам пора вникнуть в устройство этого механизма.


И тут выясняется, что just runs обходится далеко не бесплатно: есть ограничения по загрузке классов, вопросы к скорости запуска, конфликты со встроенными утилитами JDK, отличия в режимах dev/test/prod, а в некоторых случаях применение этой фичи и вовсе излишне.


В этих и других тонкостях толстого JAR мы и разберемся в докладе. Заглянем в его устройство и поймём, в каких случаях он хорош, а в каких лучше обойтись без него (и что тогда выбрать вместо). Особое внимание уделим развертыванию в контейнерах.


Доклад рассчитан на практикующих инженеров, поставляющих приложения на Spring Boot в production.




Работа с шардированными данными в памяти со вкусом Spring Data, Алексей Кузин


Spring Data мощная и широко используемая часть фреймворка Spring, которая предоставляет абстракции поверх работы с разными хранилищами данных. В сети есть масса информации по использованию готовых модулей Spring Data, но для внесения изменений или разработки своего модуля приходится глубоко залезать в исходники. На примере коннектора для Tarantool Алексей покажет, как разработать свою реализацию коннектора для распределённого хранилища данных в памяти, какие проблемы с производительностью могут возникнуть, и как их решать.


Доклад предназначен для тех, кто интересуется деталями реализации фреймворка Spring и хочет узнать больше о деталях работы с NoSQL БД.


Чем ценен спикер: У Алексея огромный опыт в Java, и огромный опыт с базой Tarantool. Он разработчик интеграции SpringData Tarantool, и получается рассказ из первых уст.




JVM-языки


Может ли Java-конференция обойтись без холивара за каким JVM-языком будущее? Если серьёзно, то мы не за пустые холивары, а за обоснованный конструктив и за то, чтобы уделять внимание всей экосистеме.


Интервью и Q&A: Эволюция Java и Kotlin. Что нас ждет?, Роман Елизаров


Java эволюционирует. Каждые полгода мы видим какие-то новые фишки, как например: text blocks, sealed classes, records, switch instanceof все те удобства, которые раньше были доступны только пользователям других, более современных языков на JVM, например, Kotlin.


Что же будет делать Kotlin? Сидеть и ждать, надеясь на те удобства, где Java не сможет его никогда догнать, или же будет продолжать двигаться вперед? Что можно еще улучшать в языке, который вырос благодаря массивному упрощению количества воды, которую приходится писать в Java-коде? Есть ли запас? От чего вообще страдают программисты и где язык програмирования может улучшать их жизнь?


Об этом всём мы расспросим Романа Елизарова, который отвечал и за дизайн корутин в Kotlin, и за доклады о них: например, его доклад с JPoint набрал больше 20 000 просмотров.




Back from the 70s the Concurnas concurrency model!, Jason Tatton


Concurrency это трудно, а справляться с concurrency в гетерогенных средах CPU/GPU еще сложнее! Это относится и к Java со ее встроенной поддержкой concurrency-программирования. Concurnas это новый и свежий подход к решению этой проблемы на JVM.


Джейсон Таттон много лет работал над высокочастотными трейдинговыми системами для различных известных банков, прежде чем он решил потратить несколько лет на разработку и внедрение этого нового JVM-языка.


Полезно будет всем, кто интересуется новыми языковыми трендами или ищет новые идеи для построения надежных высокопроизводительных конкуррентных, распределенных и параллельных систем.




и не только


А кроме всего перечисленного, есть ещё и такие доклады:


  • Ещё не анонсированные: сейчас остаются несколько последних слотов. Чтобы узнать их судьбу, можно заглядывать на сайт Joker или подписаться на конференцию в соцсетях (Telegram, ВК, FB, Twitter).


  • С соседних конференций. Тут такая история. Мы проводим целый сезон из 8 IT-конференций по разным темам (от тестирования до DevOps). И видим, что многим интересно разное: С Java-конференции хочу многое послушать, с девопсовой кое-что тоже, а с .NET-конференции послушал бы про Domain-Driven Design. Поэтому мы сделали билет-абонемент Full Pass, дающий доступ ко всем конференциям сезона сразу: конечно, никто не станет смотреть все восемь от и до, но вот выборочно подключаться к интересным докладам можно.



Так что, если вам интересны смежные темы и мир вокруг, заходите на сайт всего сезона и смело изучайте там всё. А если интересен именно Joker и ничего больше тогда идите сразу на его сайт.

Подробнее..

Мой конспект с Joker 2020

14.12.2020 02:16:30 | Автор: admin

Вот и прошла конференция Joker 2020 для Java senior-ов. Для меня эта конференция стала особенной сразу по нескольким причинам это первая "серьёзная" техническая конференция на которую я попал (в качестве зрителя), это моя первая онлайн-конференция, и это первая конференция, билет на которую я купил сам, а не за счёт работодателя.


Потраченные деньги, плюс возможность пересматривать любую трансляцию мотивировали меня просмотреть как можно больше материала, в результате даже через неделю после завершения конференции, я всё ещё продолжал сидеть и конспектировать выступление за выступлением. Совершенно нормальное поведение, хватит всем на меня так пялиться. Нет, я не пойду с добрым дядей доктором на обследование, спасибо.


Сразу предупреждаю, что даже так я не сумел просмотреть все трансляции, но если кому-то интересно, что же из этого получилось добро пожаловать под кат.


Spring: Your next Java microframework


Презентация от Алексея Нестерова, в которой он доказывает, что Spring Boot может выглядеть как микрофреймворк, вести себя как микрофреймворк и даже крякать как микрофреймвок, а если так то что же нам ещё нужно?


От микрофрейморках люди как правило ожидают несколько качеств: простоты разработки, "понятности" работы (simple vs easy), скорости работы, и готовности к работе в "облаке" (cloud-readiness, cloud-native). Как ни странно, Спринг может соответствовать всем этим критериям, и Алексей готов это доказать.


Лёгкость разработки


У Spring есть Boot Devtools, позволяющий, помимо всего прочего:


  • получить LiveReload в браузере
  • отключить кэширование шаблонов
  • перезагружать сервис при обновлении файлов в classpath как локально, так и удалённо (но только не делайте так на продакшене, пожалуйста)

Скорость запуска


Спринг может быть быстр для запуска, но надо понимать что вообще делает ваш код. Если вы грузите сторонние сервисы, или лезите в БД при запуске нечего пенять на Спринг! Помимо этого оптимизировать старт могут следующие советы:


  • распакуйте executable JAR и укажите Main класс
  • используйте spring-context-indexer
  • используйте функциональные бины
  • уберите Actuator
  • используйте реактивный стек

Боттлнеком всегда может стать ваш CPU, может быть проблема ещё в JVM попробуйте разные, например J9, попробуйте CDS, или скомпилируйте в нативный файл с GraalVM.


Если совсем ничего не остаётся (или если вам платят только за оптимизацию времени старта) переделайте все бины на ленивые, и используйте ленивую загрузку для репозиториев. И пусть кто-то другой разбирается с проблемой тормозящего первого запроса.


Примечания в курсиве от меня, это не слова презентатора.


Простота (понятность) в разработке


Тут презентатор потратил время на объяснение о том, чем в его представлении "easy" отличается от "simple". Очень надеюсь, что я понял правильно, что "easy" это та "магия" Спринга, при которой ты просто вешаешь пачку аннотаций по коду и всё начинает работать "само собой" на механизмах, зашитых в сам Спринг. В противовес этому есть "simple" когда вы явно прописываете что идёт за чем, имеете полный контроль над кодом, но добавление новых компонент будет сопровождаться дополнительной работой с вашей стороны. Здесь не будет идеального решения, каждому разработчику/команде надо решать для себя, что им конкретно сейчас важнее.


Для обеспечения "понятности" разработки, в новых версиях Спринга появились такие альтернативы уже существующим механизмам:


  • Functional beans вместо Component Scanning
  • Functional routing вместо Route mapping
  • Использование @Query или миграция с JPA вместо использования Generated Queries
  • Manual import вместо Autoconfigurations

Оказывается, пока я учился мигрировать конфигурацию сервисов с XML на аннотации спринга, умные люди сделали ещё и Functional beans с Functional routing на лямбдах. Все три метода поддерживаются и могут работать дополняя друг друга, но новая функциональная конфигурация должна быть чуть-чуть быстрее, потому что не использует рефлексию.


С помощью новых механизмов, весь (микро-)сервис можно описать исключительно из Main-а, не используя никаких других методов конфигурации.


Все четыре тезиса были подкреплены демонстрацией примеров, в этом случае на использование applicationContext.registerBean(...) и RouterFunction, route().GET("/foo", request -> { ... }).


Cloud-ready


Напоследок, cloud-ready, но тут даже и обсуждать нечего это движение по-сути, со спринга и началось, Spring Cloud содержит готовые механизмы для Circuit Breakers, конфигурации, Service registry, балансировка нагрузки, API gateways, даже Serverless с Spring Cloud Function.


Сприг поддерживает такие платформы как Kubernetes, Cloud Foundry, AWS, Alibaba и другие.


Презентатор так же посоветовал посмотреть на Java Memory Calculator проект для тех, кто редактирует Dockerfile руками.


Из диалога с экспертами и ответов на вопросы стало понятно, что Spring DevTools перезагружают весь сервис если у вас какие-то свои сессии на Spring Security они будут пропадать. Функциональные бины работают так же, как и обычные. Пост процессоры бинов могут быть зарегестрированны точно так же.


How we did SQL in Hazelcast


Презентация от Владимира Озерова, в которой он показал основные принципы проектирования своего распределенного SQL хранилища, основываясь на опыте своей компании.


Изначально у них было предикатное API для хранения in-memory индексов, но этого было не достаточно, так как не давало нужной гибкости. В первых версиях они перешли на простые запросы вида select ... from ... where с использованием индексов. Оптимизация SQL запросов это очень сложные задачи, к счастью в мире есть несколько решений, и одно из которых они решили использовать это Apache Calcite.


Процесс оптимизации запроса "по верхам" состоит из трёх шагов: анализ синтаксиса, анализ семантики, и оптимизация. По теме оптимизации есть множество исследовательских работ, например, Access Path Selection in a Relational Database Management System, The Cascades Framework for Query Optimization.


Ремарка от меня. До сих пор мне приходилось работать с SQL, например, с такими задачами как поддержка вызовов хранимых процедур на легаси системах, или использование больших и сложных SQL запросов, предоставленных нам от DBA. Так что название презентации меня очень заинтересовало, и я с интересом был готов послушать что-то новое. Однако, в этот момент даже до меня дошло, что что-то здесь не так, и тема как-то не похожа на ту, что я ожидал услышать, так что я решил "откланяться" и пойти слушать другой доклад. Тем не менее, тема должна быть интересна, и кто хочет может досмотреть её самостоятельно.


Spring Boot fat JAR: Thin parts of a thick artifact


Здесь презентатор по имени Владимир Плизга, вместе с экспертами Андреем Беляевым и Андреем Когуном разобрал устройство "fat" JAR-а.


Вообще, технология "fat" JAR не нова, и первые образцы технологии были представлены ещё в 1890 году Василием Звёздочкиным. В спринге же существует с первой версии.


При запуске такого архива происходит следующая цепочка вызовов:


Внешний архив размечается так:


А вот так классы грузятся из архива:


Все слайды из презентации Владимира, он поделился ими по следующей ссылке


Несколько замечаний презентатора: внутренние архивы не сжаты;
Spring вешает собственный наследник URLClassLoader-а на главный поток;
По-сути чтение классов работает как чтение из внешнего архива с правильным отступом с использованием RandomAccessFile.


Если что-то пошло не так, то загрузку "fat" JAR-а можно отдебажить следующей последовательностью действий:


  1. Скачать нужную версию Spring Boot-а
  2. Поставить брейкпойнт на org.springframework.boot.loader.JarLauncher#main
  3. Запустить джарку с параметром -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005
  4. Подключиться дебагером из проекта

Тут завязалась дискуссия с экспертами, из которой прояснили ещё несколько моментов:


  • Загрузка может поломаться: например может появиться Class/MethodNotFoundException если порядок JAR-ок в "fat" JAR-е различается
  • Запуск проекта из Идеи отличается от запуска самой джарки
    Мораль тестируйте fat JAR ещё на этапе разработки, что бы избежать проблем на продакшене

Использование "fat" JAR-а может потенциально поломать такие утилиты как jshell, jdeps, jmint, а так же пакет java.util.logging со всеми наследниками. Что бы это починить, постарайтесь не использовать ClassLoader.getSystemClassLoader(), или просто распаковывайте "fat" JAR перед использованием. Однако, даже со всеми этими недостатками fat "JAR" может помочь в миграции с application server'а на Спринг бут.


Поддержка докера с версии Spring Boot 2.3 (опционально и с 2.4 по умолчанию) в fat JAR добавился новый режим -Djarmode=layertools, позволяющий собирать артефакт по слоям, и это работает как с Maven так и с Gradle плагинами. Посмотреть слои можно командой


java -Djarmode=layertools -jar fat.jar list

По умолчанию идут в таком порядке: зависимости, загрузчик спринг бута, snapshot зависимости, сгенерированный код, код приложения. Что именно попадёт в какой слой можно менять и настраивать. Далее, распакованный по слоям артефакт можно упаковать в докер вручную, с помощью докерфайла как-то так:


FROM .../openjdk-alpine:11 as builderWORKDIR applicationCOPY fat.jar fat.jarRUN java -Djarmode=layertools -jar fat.jar extract...FROM ...openjdk-alpine:11WORKDIR applicationCOPY --from=builder application/dependencies/ ./COPY --from=builder application/spring-boot-loader/ ./...ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

Использование спрнгового JarLauncher'а даже на распакованном артефакте позволяет нам сохранить "магию" Спринга, и, например, читать версию артефакта из манифеста.


Из презентации я так же узнал об утилите "dive", которую презентатор использовал для просмотра слоёв в контейнере.


Разобравшись с ручной упаковкой докерфайла у экспертов возник закономерный вопрос: "А где тут кнопка <сделать хорошо>"?


Оказывается, есть и такое разные инструменты, вроде Buildpacs, или Google Jib.


Разница между ними такая если нужен полный контроль, то используйте Layertools, если нужна "магия" и размеры полученного артефакта не заботят то Buildpacs, если нет возможности использовать докер, или невозможно обновить Спринг Бут до версии 2.3 берите Jib.


Общие рекомендации с презентации:


  • Проверяйте что идёт в class-path в IDE
  • Обновляйте Spring Boot до последней версии
  • Распаковывайте fat JAR в целевом окружении
  • Запускайте проект через JarLauncher, не Main-Class манифеста
  • Подумайте об удобстве использования с Buildpacs

Дополнительные ссылки:



Hidden pearls for high-performance-persistence in Java


Презентация от Свена Рупперта. Свен по максимуму воспользовался форматом онлайн презентации, и записал свою речь во время неторопливой прогулки по осеннему лесу с чашкой кофе. Несмотря на умиротворяющую атмосферу, сама презентация прошла в очень бодром темпе, а Свен успел перечислить и рассказать особенности множества интересных библиотек из мира Джавы.


JOOQ: кодогенератор для вызовов БД. Вот только я подумал, что у меня наконец-то появилась идея своего проекта, которой ещё ни у кого не было...



Позволяет генерировать DSL в зависимости от БД, со всеми таблицами и колонками, и использовать дальше в своих проектах. В бесплатной версии не поддерживает Oracle, SQL Server и MS Access.


Speedment. хотел дать ссылку на их сайт, но там ошибка 500 по злой иронии не может подключиться к БД и так лежит уже неделю


Позволяет генерировать DSL под БД, но на потоках Java 8. Все фильтры и выборки задаются в лямбдах, выглядит интересно. Сюда же можно отнести и JPA Streamer библиотеку, которая добавляет Java 8 streams поверх Hibernate.


Chronicle Bytes: даёт два класса Bytes для создания массивов байтов и MappedBytes -для привязки буфера к файлу. Написал в стиле С/С++ записывать можешь что угодно в каком порядке, доставать обратно тоже. Описания полей/классов не сохраняются, если при чтении перепутаешь порядок или попытаешься прочитать лишнее сам виноват.


Chronicle Map быстрое key-value хранилище разработанное для высоконагруженных многопоточных приложений, не ограничено размерами RAM-а, и может сохранять данные на диск.


XODUS транзакционная schema-less встроенная БД, разработанная в JetBrains. Все изменения пишутся в иммутабельный лог.


MapDB совмещает движок БД и коллекции Java. Позволяет использовать словари, списки, для хранения данных либо вне сборщика мусора, либо на диске.


DB db = DBMaker.fileDB("/some/file").encryptionEnable("password").make();ConcurrentNavigatableMap<Integer, String> map = db.treeMap(...); 

Можно использовать для получения многоуровнего кеша с истечением срока хранения, для хранения не влезающих в RAM данных диске, для последовательных бекапов, для фильтрации и обработки данных. Всё это достигается за счёт того, что типы хранилиш можно совмещать: например завести словарь вне GC, пишущий часть данных на диск.


Microstream проект, реализовавший собственную сериализацию для объектов, и хорошо умеющий работать с графами. В бесплатной версии не работает с Oracle БД, и не даёт параллельное чтение/запись. Стартовый класс EmbeddedStorageManager, в нём можно задать корень графа, сохранить на диск. Позволяет хранить модели как есть, или в виде коллекций. Позволяет работать только с частями графов, но даже зацикленные графы для них не проблема. Могут быть проблемы с наследованиями.


Помимо этого Mictorstream устраивают хакатон с призовым фондом в 20к$, на котором Свен будет одним из членов жюри. До февраля есть возможность придумать какое-то интересное использование для этой библиотеки, выложить под лицензией Apache 2 и попробовать получить 5к$ на первом месте (всем участникам гарантируют майку).


Spring Patterns for adults


Последний крупный доклад, о котором я хотел бы здесь написать это работа Евгения Борисова, которую он презентовал с приглашенными экспертами Андреем и Кириллом. Говорили много и интересно по докладу видно, что Евгений отлично разбирается в теме и очень живо делится своими знаниями, я попробую передать лишь основное.


При запуске @ComponentScan, Спринг начинает сканировать все компоненты, включая унаследованные @Service/@Repository/@Controller/@RestController и даже @Configuration это тоже компонента. Работает это потому, что Спринг не ищет конкретные аннотации, а проверяет каждую найденную и перебирает всех её предков. Таким образом можно писать собственные аннотации (как @MyCompanyController), наследующие, или аннотированные аннотациями Спринга, и они будут работать точно так же с остальными контроллерами.


Довольно распространённая ошибка кто-то пишет @Lazy компонент (@Lazy Component, @Lazy @Service, ...) и не понимает, почему этот компонент стартует вместе со всеми, даже когда им никто не пользуется. Проблема в том, что любой @Autowire для компоненты автоматически означает, что компонента нужна, и заставляет Спринг её создать. Решение простое с версии 4.3 можно сделать @Autowire @Lazy и вместо компоненты будет прокси-объект, который создаст реальную компоненту лишь тогда, когда кто-то начнёт ею пользоваться.


При тестировании приложений всегда есть проблема контекста, который надо разворачивать для тестирования. Разворачивать всё и всегда долго, разворачивать только часть контекста в зависимости от теста всегда есть риск, что что-то где-то будет падать из-за какой-то части проекта, в результате всё будет скатываться в первую ситуацию когда для каждого теста разворачивается весь контекст. Для решения этой проблемы на тестах можно использовать @ComponentScan(lazyInit = true) (либо spring.main.lazy-initialization=true в файле настроек).


Была интересная дискуссия о том, так ли полезна иньекция параметров конструктора, которая, в отличии от иньекции по полям не должна в теории позволить растянуться коду в классе и должна помочь избежать создание "божественных объектов", которые делают слишком много всего сразу. На практике же программист просто лепит @RequiredArgsConstructor и классы продолжают расползаться.


Была ещё более интересная дискуссия о том, как использовать квалификаторы. К сожалению, текстом и в виде конспекта её не пересказать, я могу лишь показать картинку "Айтишники на троих разбирают запутанный случай Spring Boot'а".



Далее, по паттернам. Для использования паттерна Chain of Responsibility в спринге можно инжектить списки. @Autowired List<Handler> handlers;заинжектит все компоненты, имплементирующие интерфейс Hangler таким образом не надо будет их биндить по одному. Порядок будет произвольный, если нужен порядок, или какой-то особый список то надо будет использовать BeanPostProcessor и собирать список самостоятельно из ApplicationContext.


Можно использовать Intrpspector.decapitalize() для получения имени бинов из имени класса.


Интересный пример того, как можно взять какой-либо старый фреймворк (например, из либы, которую нам нельзя менять) и заставить работать все старые легаси-компоненты в спринге. Делается это так с использованием ImportBeanDefinitionRegistrar


class LegacyBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {// ...registerBeanDefinition() {      Reflections scanner = new Reflections("com.legacy.package");      Set<Class<?>> classes = scanner.getTypesAnnotatedWith(LegacySingleton.class);      for(Class<?> aClass : classes) {        GenericBeanDefinition bd = new GenericBeanDefinition();        bd.setBeanClass(aClass);        // bd.addQualifier(new AutowireCandidateQualifier(Legacy.class)); // можно добавлять свои квалифаеры        beanDefinition.setScope(beanDefinition.SCOPE_SINGLETON); // например        registry.registerBeanDefinition(Introspector.decapitalize(aClass.getSimpleName()), bd);      }}}

Начать использовать этот регистрар можно в классе с аннотацией @Configuration @Import(LegacyBeanDefinitionRegistrar.class).


Далее, разобрали несколько вариантов того, как работать с паттерном Strategy & Command. Например, если мы хотим, что бы от клиента приходил запрос о том, как именно обрабатывать его запрос. Тут возникает соблазн начать использовать switch, но это опасный путь сперва у тебя 5 кейсов, потом 6, там и 7-ой добавить вроде не страшно, потом вдруг 10 но рефакторить уже сложно и какая разница, почему бы не добавить 11? После чего всё превращается в "ну да, у нас 234 кейсов, но рефакторить сложно, так что какая разница, что 235 добавим?". Чтоб избежать этой порочной практики, лучше сразу начинать писать как профессионалы.


Спринг позволяет сделать код, который вызывает нужный обработчик в зависимости от какой-нибудь строки несколькими методами.


 @Autowired private Map<String, Handler> map; // key = bean id, Handler - @Bean

Тут ключь это айди бина, имя класса может быть полезно, но не всегда применимо. Обойти это можно добавив какой-нибудь myType() метод в общий интерфейс, и собирая словарь в консрукторе, как в следующем примере.


interface HandlerInterface { String myType(); void doWork(); }/// --public class Controller {  private Map<String, Handler> map;  public Controller()(List<HandlerInterface> somethings) {    map = somethings.stream.collect(toMap(SomethingInterface::myType), Function.identity());  }  // ...}

Ну и последний вариант создать словарь как @Bean, использовать тот же метод группировки, что и в предыдущем.


Далее был интересный вариант того, как сделать так, что бы бины регистрировались на лету. Было показано несколько деталей, мне самым интересным показалось вот что: @Autowired можно вешать на любой метод, не обязательно сеттеры. Таким образом можно писать компоненты, которые при создании будут идти и регистрироваться у контроллера (например, из прошлого примера), добавив всего лишь один метод в общий интерфейс:


@Autowired default void regMe(Controller c) {  c.register(this.getType, this); }

Под конец было упомянуто, что AspectJ лучше не использовать на бизнес-логике вас все будут ненавидеть. Но это не означает, что AspectJ бесполезен! С его помощью можно отлавливать, например, когда бросаются исключения определенного типа и либо логгировать их особым способом, либо высылать емейл админу "эта штука опять сломалась".


Презентация длилась два с половиной часа, но смотрелась на одном дыхании настолько живо и интересно её подавали, так что кто ещё не смотрел настоятельно рекомендую.


И ещё...


Java Licensing Tips


От Юрия. Разобрал тонкости в обновлении с JDK_8_202 на 203 начиная с этой версии надо платить деньги в Оракл. Лучший совет здесь советуйтесь с юристами, как именно это работает для вас, но вообще есть три варианта:


  1. Не обновляться, остаться на версии 202
  2. Мигрировать на OpenJDK со свободной лицензией
  3. Провести внутренний аудит, разобраться где что нужно, попробовать уменьшить количество лицензий, начать платить

С точки зрения Оракл "использование факт уустановки JDK/JRE на ваш сервер продукции". Да, даже если вы ею не пользуетесь. Лицензии надо покупать на ядра процессора.


Например, если у вас есть сервер с двумя процессорами Intel Xenon E3 2680 v4, и у каждого процессора 14 физических ядер работает и Hyper Threading на каждом из ядер по 2 логических ядра. В этом случае нужно купить 28 (логических ядер) * 0.5 (коэффициент процессора из таблицы) = 14 лицензий.


Всякие облака или кубернетес всё-равно плати. Если JDK установлено для какого-то продукта Oracle (например, DB/WebLogic) то платить не надо, но и другим приложениям нельзя использовать этот JDK.


На обычных пользователей платить надо по пользователю. Один пользователь сидит на 5 компьютерах одна лицензия, пять пользователей сидят на одном компьютере 5 лицензий.


How to tell "no" to an architect? Tips for sizing a microservice


Андрей довольно адекватно высказался по поводу микросервисов, что процесс их проектирования не должен быть безумным процессом рисование стреловек и коробочек, где каждая коробочка свой микросервис. Если какие-то части продукта связаны, и одна часть не может быть изменена без другой надо ли разбивать их на два микросервиса, когда можно оставить всё в одном? В конце концов, разбить один сервис в несколько вы всегда успеете.


Will robots replace programmers?


Довольно интересный рассказ Тагира, где он анализирует тренды развития инструментов программирования. На мой взгляд, доклад скорее оптимистичный да, тупой рутинной работы становится меньше, но и робот никогда не сможет точно отловить все нюансы. Скорее всего будущее в тандеме между разработчиком и вспомогательными инструментами, часть из которых будет разработана с использованием техник машинного обучения.


Заключение


Теперь, спустя три, кажется, недели могу сказать, что конференция была просто отличной. Для себя я узнал много нового, добавил всех презентаторов, кого нашел, в твиттере, успел даже попробовать кое-что у себя на проектах. Жаль, не было времени походить по залам в игровом виде, но думаю, это уже на другой раз можно будет отложить.


Этот конспект я делал на английском, слушая оригинальные трансляции. Не был уверен в том, нужны ли они кому-то, но оказалось, что интерес был поэтому перевёл обратно на русский и получил эту статью. Сам я синьер не настоящий, опыта маловато, и я допускаю, что допустил неточности в некоторых темах. Тем более при переводе терминов на русский сам я всю жизнь работаю на английском, переводить не привык. Тем не менее, я очень надеюсь, что я не исказил смысла оригинальных презентаций, и не внёс никаких ошибок от себя. Но если что пишите, всё исправлю!

Подробнее..
Категории: Java , Spring , Joker , Licensing

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru