Получи случайную криптовалюту за регистрацию!

Java: fill the gaps

Логотип телеграм канала @java_fillthegaps — Java: fill the gaps J
Логотип телеграм канала @java_fillthegaps — Java: fill the gaps
Адрес канала: @java_fillthegaps
Категории: Технологии
Язык: Русский
Количество подписчиков: 10.33K
Описание канала:

Привет! Меня зовут Диана, и я занимаюсь java разработкой с 2013г.
Делюсь опытом/знаниями по темам:
- Java Core
- Вопросы с собеседований
- Best practices
Комплименты, вопросы, предложения: @utki_letyat

Рейтинги и Отзывы

4.50

2 отзыва

Оценить канал java_fillthegaps и оставить отзыв — могут только зарегестрированные пользователи. Все отзывы проходят модерацию.

5 звезд

1

4 звезд

1

3 звезд

0

2 звезд

0

1 звезд

0


Последние сообщения 19

2021-04-12 09:00:32 ​В системе два микросервиса: А и Б.

У сервиса А есть метод GET /stat, который считает статистику. Для подсчёта используется внутренняя информация сервиса А и делается HTTP запрос GET /data в сервис Б.

Проект перевели на Java 11, и для доступа к сервису Б теперь используется асинхронный HTTP клиент. Стало значительно лучше, и менеджер проекта раздал всем премии.

Вопрос: Какая метрика улучшилась?
1.4K views06:00
Открыть/Комментировать
2021-04-09 10:01:13 Программа курса

Напоминаю, что 19 апреля начинается курс многопоточки на Java. Часто получаю по нему такие вопросы:

Я прошёл курс Х и там была тема многопоточки. Для меня будет что-то новое?
Я сеньор, будут продвинутые темы? или всё только для джуниоров?

В этом посте отвечу на эти вопросы подробно.

Для кого?

Курс для тех, кто уже работает java разработчиком. Все проекты разные, поэтому ориентироваться на грейд не стоит. Кому подойдёт?
У вас есть начальные знания многопоточности, но вы редко решали задачи по этой теме
Отвечаете на собеседованиях про Thread, Executors, volatile и synchronized, но не сможете сходу рассказать про многопоточные коллекции и разницу между ними
Хотите на высоконагруженные проекты, и понимаете, что многопоточка там важна и нужна

Необходимые знания:
Умеете писать веб-сервисы на Spring, делать запросы в БД и писать юнит-тесты
Знаете паттерны GoF

Что будет?

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

Вводный модуль

Что происходит с потоком в JVM и как на это влиять через флажки. Зачем нужна модель памяти, как она учитывается в коде. Как это всё мониторить и тестировать.

Затем углубимся в типовые задачи:

Запустить асинхронно независимые задачи

Что использовать и как подобрать параметры, чтобы выигрыш от параллельности превысил оверхед на организацию. Рассмотрим Executors со всех сторон. Посмотрим, когда пригодится CompletableFuture. Оценим перспективы легковесных потоков.

Взаимодействие потоков

Общие переменные или влияние одного потока на другой - узкое место любой реализации. JDK предлагает огромное количество инструментов. Разберёмся, что для какой ситуации подойдёт, возможные ошибки и лучшие практики.

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

Обработка большого количества данных

Здесь инструмент один - ForkJoinPool. Начнём с принципа работы, закончим разбором кейсов. Посмотрим, как ForkJoinPool адаптирован для Stream API.

Потоки данных

Чем "много запросов" отличается от потока данных? Для каких случаев подойдёт и не подойдёт такой способ коммуникации? В этом модуле сосредоточимся на очередях и затронем тему реактивного программирования.

Детали реализации

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

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

Что ещё

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

Записаться можно тут: fillthegaps.getcourse.ru/mt
899 views07:01
Открыть/Комментировать
2021-04-07 09:30:24 Как развиваться и строить карьеру. Часть 2: самообразование

Продолжаю делиться карьерными наблюдениями.

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

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

Баннер с громким обещанием

"Сбрось 10 кг за неделю"
"Пробеги марафон через месяц"
"Стань топовым java разработчиком через 2 месяца"

Без комментариев

Самостоятельное изучение

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

Так же и в IT. Есть мнение, что разработчику для самообучения хватает документации и гугла.

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

Да, не хочется тратить выходные на 10 лонгридов и 20 часовых докладов. Но, к сожалению, приходится.

Мотивация быстро падает
Сколько статей пылится в закладках? Сколько книг скачано и ждут своего часа? У меня для них отдельная папка

В целом вариант рабочий, но требует времени и дисциплины

Заниматься с тренером

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

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

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

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

Резюме
Без обучения никак. Обычно знания приходится добывать самому и не самым простым путём. Это требует дисциплины и временных затрат.

Авторские курсы и мастер-классы - самый недооценённый и комфортный способ учиться. Расскажут всё от простого к сложному и за ручку приведут к результату. Я говорю не сколько про свой курс многопоточного программирования (он классный, ещё можно записаться!), но и про платные предложения вообще. Когда опытный разработчик готов поделиться с вами знаниями - это бесценный шанс, который нельзя упускать.
1.6K views06:30
Открыть/Комментировать
2021-04-05 10:01:36 Как развиваться и строить свою карьеру

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

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

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

Советы джуниору

Ты устроился на первую работу. Молодец, до этого этапа не доходят большинство начинающих!

Твоя задача - влиться в текущий проект и адаптироваться к его технологиям. Даже если это чудовищное легаси.
Закрывай пробелы по java core
Учись писать тесты, работать с CI и взаимодействовать с командой
Повторяй за другими, пиши код по аналогии
Если что-то непонятно - сначала поищи ответ пару часов, если не нашёл - спроси
Записывай ответы, не спрашивай одно и то же

Сейчас сложно, потом будет легче!

Советы мидлу

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

Но не задирай нос. Скорее всего большинство задач ты решаешь по аналогии с теми, что уже были. Чтобы развиваться, задай себе ряд вопросов:
Что будет, если я останусь на этом месте ещё год? А два?
Есть ли у меня пробелы в базе: java core, concurrency, паттерны GoF, SQL?
Что происходит на рынке? Актуальны ли мои знания?

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

Советы сеньору

У тебя есть опыт в определённых технологиях. Ты принимаешь много решений самостоятельно и несёшь за них ответственность. Здесь чётких рекомендаций нет, но пора подумать над вопросами:
Есть ли какие-то базовые знания, в которых я не уверен?
На этом этапе критически важно устранить все пробелы!
Что мне интересно? На каком проекте я хочу работать? Какие задачи решать? С какими людьми работать?
Что мне нужно, чтобы попасть на желаемый проект и комфортно там работать?

Твоя задача - не суета и страдания, а получать много денег и удовольствие от работы. Одновременно.
898 views07:01
Открыть/Комментировать
2021-04-02 09:30:06 Phaser: конференции и реальная жизнь

На конференции Joker 2020 было 3 доклада по теме многопоточности. Один из них - Thread Safety with Phaser, StampedLock and VarHandle. На примере Phaser хорошо виден разрыв между теорией и практикой. В этом посте расскажу, почему.

Паттерн Барьер помогает координировать потоки. Он блокирует один или несколько потоков, пока не наступит какое-то событие. JDK предлагает три реализации:
CountDownLatch
CyclicBarrier
Phaser

Последний - самый продвинутый:
Несколько сценариев работы
Методы мониторинга
Можно строить иерархичные структуры из нескольких Phaser
Иногда работает быстрее, чем CountDownLatch и CyclicBarrier
Обработка исключений

Класс Phaser часто встречается на воркшопах и advanced java курсах. Можно долго рассказывать про методы, рисовать схемы и многопоточно перемножать двумерные массивы.

Часто автор статьи или доклада держит фокус на инструменте:
Рассказываю про Phaser → Подбираю пример

На практике последовательность другая:
Вижу проблему → Ищу варианты → Выбираю подходящий

В такой цепочке у Phaser нет шансов. За пределами конференций и статей этот класс не используется.

Зачем тогда о нём говорить?

Чётко понимать, почему что-то НЕ работает, так же полезно, как и знать лучшие практики. Причиной может быть:
Плохой дизайн и неудобные методы
Неудачная реализация и проблемы производительности
Более подходящие инструменты

Чем плох Phaser?

Все реализации паттерна Барьер блокируют потоки, поэтому редко используются в нагруженных системах. Есть всего пара ситуаций, когда барьер - лучшее решение, но для их реализации достаточно CountDownLatch или CyclicBarrier. Phaser неплохо спроектирован, но слишком оторван от практических задач, это наглядный пример over engineering.
1.6K views06:30
Открыть/Комментировать
2021-03-31 09:30:11 Анонс курса по многопоточному программированию

Привет!

Больше года я веду этот канал и делюсь знаниями по Java разработке и смежным темам. Люблю раскладывать информацию по полочкам и выделять самое важное.

Почти год я готовила курс по многопоточному программированию и, наконец, объявляю набор!

Почему именно эта тема?
Многопоточка активно используется на всех интересных проектах
Есть на всех проектах, даже если напрямую вы с ней не работаете
В этой теме важно понимание общей картины и знание нюансов
Курсов, которые дают актуальную и полную картину, нет
90% материалов в интернете устарели или слишком далеки от практики

В центре курса - пакет java.util.concurrent:
Плюсы, минусы и важные детали всех классов
Распространённые ошибки и лучшие практики
Примеры использования в популярных проектах
Сравнение альтернатив и бенчмарки

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

Разумеется, только java.util.concurrent дело не ограничивается. Разберём всё, что может пригодиться:
Флажки JVM, связанные с многопоточностью
Что и как мониторить
Что и как тестировать
Реактивные библиотеки
Легковесные потоки

Курс подойдёт тем, кто на базовом уровне знаком с многопоточкой. Если вы знаете, зачем нужны synchronized, volatile и Executors. Умеете писать приложения на Spring и делать запросы в базу данных.

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

Старт: 19 апреля
Длительность: 2 месяца

Формат:
Лекции 3 раза в неделю. Не дольше 30 минут, всё по делу
Практические задания
Общий чат, поддержка, ответы на вопросы

Мест всего 20, чтобы уделить каждому достаточно внимания.

Цена: 24900
Для самых решительных до конца дня работает промокод READY на скидку 15%. Промокод вводится на странице оплаты.

Программа целиком и запись тут: https://fillthegaps.getcourse.ru/mt
1.9K views06:30
Открыть/Комментировать
2021-03-26 09:00:28 Сериализация, часть 3: практика

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

Что говорят авторитетные источники:

Effective Java: нет никаких причин использовать java сериализацию в новых системах.

Brian Goetz, архитектор Java: когда меня спрашивают, о какой фиче я сожалею больше всего, то ответ прост - сериализация.

Java cериализация была отличным решением для условий 1996 года:
Медленный интернет
Небольшая память
Скудный набор языков и платформ

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

Данные передаются по сети в виде байтов, но используется стандартная структура сообщения, а не та, которую задаёт JVM. Такой подход снимает 90% проблем сериализации. Популярные форматы делятся на две группы:

Текстовые: JSON, CSV, XML

Легко читаются человеком
Библиотеки для любых платформ и языков
Избыточность. В JSON и XML названия полей занимают половину сообщения, а в CSV миллион запятых
Плохая поддержка типов. Поля классов, большие числа, даты - всё передаётся как строки

Бинарные

Данные пишутся максимально компактно. К этой группе относятся protobuf, Thrift, Avro, Parquet. Для каждого типа сообщений создаётся схема. В ней перечисляются поля, их размер, иногда порядковый номер. Для protobuf схема выглядит так:

message OrderRequest {
required int64 user_id = 1;
optional string address= 2;
repeated int64 item_id = 3;
}

Отправитель создаёт массив байтов опираясь на эту схему. Получатель считает данные по той же схеме.

Короткие сообщения. Вместо имён полей используются порядковые номера(protobuf, Thrift), либо данные просто идут подряд(Avro, Parquet).

Schema Registry

И для текстовых, и для бинарных форматов остаётся проблема прямой и обратной совместимости. Менять схему можно, но в ограниченных пределах. Если формат данных меняется часто, то поможет паттерн Schema Registry.

Это отдельный компонент, который хранит все версии схем данных и сопутствующую информацию:
ID схемы: id = 15
Название: subject = "orderRequest"
Версия: version = 3
Сама схема: schema = …

Отправитель формирует сообщение и передаёт его вместе с ID схемы. Получатель берёт схему из Schema registry и читает данные. 100% совместимости это не гарантирует, но заметно упрощает работу.

Резюме:

Сериализация в java была отличным решением в своё время. Я не стала подробно описывать методы и лучшие практики Serializable/Externalizable, т.к такая сериализация осталась только в дремучих легаси проектах. Даже на собеседованиях её редко спрашивают.

Сейчас чаще используются форматы, не привязанные к конкретному языку и платформе. Но проблемы совместимости не исчезают:
Backward compatibility: чтение старых данных на новых серверах
Forward compatibility: чтение новых данных на старых серверах

Эти проблемы решаются двумя способами:
Адаптировать лучшие практики из Serializable. Подход рабочий, но набор доступных изменений сильно ограничен.
Использовать схемы данных. Они доступны для JSON, XML, SOAP, protobuf, Avro и т.д. Для упрощения работы со схемами поможет паттерн Schema Registry.
1.4K views06:00
Открыть/Комментировать
2021-03-24 08:59:46 Сериализация, часть 2: serialVersionUID

При использовании сериализации в класс рекомендуют добавить такое поле:

private static final long serialVersionUID = 27507467L;

В этом посте разберёмся, зачем это нужно, когда прописывать serialVersionUID и когда менять. В конце поговорим про недостатки сериализации в java.

Итак, в процессе сериализации 2 участника: отправитель и получатель. У каждого из них есть код класса Х. Отправитель сериализует экземпляр Х и отправляет по сети.

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

Если совпадают - начинается десериализация
Если нет - выбрасывается InvalidClassException

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

Другой вариант - когда класс эволюционирует и передаёт другой набор данных. Сервисы не всегда обновляются одновременно, поэтому в переходный период возникают две проблемы:

Как новому коду читать данные, созданные старым кодом? (backward compatibility)
Как старому коду читать данные, созданные новым кодом? (forward compatibility)

Приходится мириться с наличием старых версий и писать код соответственно:

Задать в классе serialVersionUID. Никогда не менять
Добавить методы readObject и writeObject и прописать порядок записи и чтения полей
Писать тесты на совместимость версий

Набор изменений при этом весьма ограничен:
Можно добавлять новые поля в конец байтового стрима
Можно менять видимость полей и методов
Нельзя удалять поля
Нельзя менять тип полей

Пара "имя класса-serialVersionUID" работает как фильтр - можно десериализовать набор байтов или нет. Когда serialVersionUID не задан в классе, он генерируется JVM. Для прямой и обратной совместимости serialVersionUID может быть любым, но постоянным. Методы writeObject и readObject задают чёткий порядок чтения/записи, но сильно разгуляться не получится.

Уже отсюда понятно, что на практике с сериализацией море проблем:

Разработка усложняется: всегда нужно иметь в виду forward/backward совместимость, набор доступных изменений сильно ограничен.

Нарушается инкапсуляция, так как private поля передаются по сети.

Ограниченные сценарии использования. Получатель и отправитель должны быть на java.

Небезопасно. Десериализация - сладкий пирожок для разных типов атак. В 2016 их было так много, что тот год на конференциях называли Java deserialization apocalypse year. В 2021 году уязвимости на основе сериализации встречаются даже в Intellij IDEA и Kubernetes.

Что с этим делать и как сериализация выглядит на практике - поговорим в третьей части.
1.3K views05:59
Открыть/Комментировать
2021-03-22 09:00:28 Сериализация, часть 1: обзор

Сервисы редко существуют сами по себе, они активно обмениваются данными с окружающим миром и другими сервисами.

Сериализация превращает Java объект в набор байтов, который можно передать по сети или куда-нибудь записать. Также встречается под именами marshalling или encoding.

Десериализация восстанавливает Java объект из полученных байтов. Где-то этот процесс называется unmarshalling или decoding.

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

Сериализация появилась в первой версии Java, и по сравнению с другими языками это была фантастика. JVM брала большую часть работы на себя. Байтовые сообщения получались компактными и быстро стали частью EJB, JMX, JMS и т.д

С тех пор механизм сериализации в java не менялся. Классы, экземпляры которых покидают JVM, должны реализовать интерфейс Serializable:

class UserRequest implements Serializable

У него нет обязательных методов, это интерфейс-маркер.

Интерфейс Externalizable даёт полный контроль над итоговым набором байтов. Хотите записать java объект в PDF или зашифровать данные - реализуйте методы Externalizable.

Как происходит сериализация Serializable классов:

Проверка полей
static и transient поля не участвуют в сериализации. Остальные поля должны быть либо Serializable, либо примитивами. Иначе разработчик получит NotSerializableException.

Объект превращается в байты
Для передачи данных обычно используется ObjectOutputStream, но часто он скрыт за фреймворком или библиотекой. Что туда пишет JVM:

Поля-заголовки
Информация о классе:
Имя класса
serialVersionUID
Количество полей
Информация по каждому полю:
Тип (имя класса или примитив)
Длина
Имя переменной
Информация про Serializable родительские классы в таком же формате
Значения переменных Serializable родительских классов
Значения переменных текущего класса. Если переменная - не примитив, то схема повторяется - записывается информация про класс и значения полей.

В примере перед постом класс Parent не реализует Serializable, поэтому parentValue не записывается в итоговый стрим, только childValue.

Набор байтов готов, можно отправлять.

Десериализация по шагам

Посмотрим на примере класса Parent и Child из примера выше.

Читаем из полученных байтов информацию о классе и о всех ближайших Serializable родителях.

Ищем ближайший НЕ Serializable родитель. В примере это класс Parent

Вызываем у класса Parent конструктор без параметров.
Тут проставляется parentValue = 2

Получаем экземпляр. Конструктор Child не используется, остальные поля проставляются внутренними механизмами JVM.

Чтение полей из потока байтов. В нашем примере передано только childValue. Записываем: childValue = 50;

Итого: в консоль выведется 2 и 50. Хотя изначально мы создавали объект с parentValue = 4, это поле не передаётся при сериализации, поэтому используется значение из конструктора Parent().

Как исправить ситуацию? Есть два варианта:
Добавить классу Parent интерфейс Serializable
Переопределить в классе Child методы writeObject и readObject. Они не определены в Serializable, но JVM найдёт их в процессе сериализации.

В writeObject задаётся, какие поля и в каком порядке запишутся в итоговый объект:

private void writeObject(…out) {
out.writeInt(parentValue);
out.writeInt(childValue);
}

В readObject указывается, какие поля и в каком порядке читать из байтового стрима:

private void readObject(…in){
int parentValue=in.readInt();
setParentValue(parentValue);
this.childValue=in.readInt();
}

В любом из вариантов десериализованный объект напечатает 4 и 50.

В следующем посте поговорим, зачем в сообщении нужен serialVersionUID, когда его задавать напрямую и менять, а также про недостатки Java сериализации.
1.4K views06:00
Открыть/Комментировать