es
Feedback
Java: fill the gaps

Java: fill the gaps

Ir al canal en Telegram

Привет! Меня зовут Диана, и я занимаюсь разработкой с 2013. Здесь пишу просто и понятно про джава бэк 🔥Тот самый курс по многопочке🔥 https://fillthegaps.ru/mt Комплименты, вопросы, предложения: @utki_letyat

Mostrar más

📈 Análisis del canal de Telegram Java: fill the gaps

El canal Java: fill the gaps (@java_fillthegaps) en el segmento lingüístico de Ruso es un actor destacado. Actualmente la comunidad reúne a 12 552 suscriptores, ocupando la posición 10 101 en la categoría Tecnologías y Aplicaciones y el puesto 52 755 en la región Rusia.

📊 Métricas de audiencia y dinámica

Desde su creación el невідомо, el proyecto ha mostrado un crecimiento acelerado, reuniendo a 12 552 suscriptores.

Según los últimos datos del 05 junio, 2026, el canal mantiene una actividad estable. En los últimos 30 días la variación de miembros fue de -49, y en las últimas 24 horas de -4, conservando un alto alcance.

  • Estado de verificación: No verificado
  • Tasa de interacción (ER): El promedio de interacción de la audiencia es 34.71%. Durante las primeras 24 horas tras publicar, el contenido suele obtener N/A% de reacciones respecto al total de suscriptores.
  • Alcance de las publicaciones: Cada publicación recibe en promedio 0 visualizaciones. En el primer día suele acumular 0 visualizaciones.
  • Reacciones e interacción: La audiencia responde de forma activa: el promedio de reacciones por publicación es 0.
  • Intereses temáticos: El contenido se centra en temas clave como redis, hashmap, linkedhashmap, индекс, фича.

📝 Descripción y política de contenido

El autor describe el recurso como un espacio para expresar opiniones subjetivas:
Привет! Меня зовут Диана, и я занимаюсь разработкой с 2013. Здесь пишу просто и понятно про джава бэк 🔥Тот самый курс по многопочке🔥 https://fillthegaps.ru/mt Комплименты, вопросы, предложения: @utki_letyat

Gracias a la alta frecuencia de actualizaciones (últimos datos recibidos el 07 junio, 2026), el canal mantiene la vigencia y un amplio alcance. La analítica demuestra que la audiencia interactúa activamente con el contenido, lo que lo convierte en un punto de referencia dentro de la categoría Tecnologías y Aplicaciones.

12 552
Suscriptores
-424 horas
-257 días
-4930 días
Archivo de publicaciones
Курс по многопоточке Привет! И вновь открывается набор на курс по многопоточному программированию. Кто давно ждал и уже готов → вам сюда Что будет? Курс строится вокруг java.util.concurrent — боевой лошадки каждого нагруженного сервиса. В деталях изучим все классы, концепты и практическое применение. Разберём огромное количество кейсов, лучших практик и возможных ошибок. Немного затронем смежные темы: тестирование, виртуальные потоки и реактивное программирование. Уровень: middle/senior Старт: 3 октября Длительность: 8 недель Полная программа, ОТЗЫВЫ и запись тут: http://fillthegaps.ru/mt6 Зачем идти? ✅ Закрыть пробелы в базе. java.util.concurrent — важная часть java core ✅ Работать на любых проектах. Многопоточка есть не только в хайлоад сервисах, а вообще везде, хоть и прячется под слоем абстракций ✅ Выбирать оптимальное решение для многопоточных задач. На курсе мы часто будем измерять производительность и стараться её поднять ✅ Круто выглядеть на собеседовании. Есть случаи, когда кандидат на собесе знал многопоточку лучше лидов и получил оффер на 30% выше озвученного Сколько стоит? До 14 сентября действует скидос: 🔸Тариф без обратной связи: 29900 23900 🔸Тариф с обратной связью: 59900 44900 Курс можно оплатить за счёт компании! Пусть ваши коллеги напишут на diana@fillthegaps.ru. Также доступна оплата НЕ российскими картами Аналогов у курса нет. С каждым потоком программа становится лучше, задания интереснее, а учёба приятнее. Если хотите разобраться с многопоточкой, и вам близок мой стиль изложения — записывайтесь, будет полезно!

Зарплаты в Европе Нашла недавно отчёт компании talent.io про зарплаты разработчиков в Европе. Статистика собрана на основе 100 тысяч офферов, и выглядит правдоподобно. Сам доклад называется Tech Salary Report 2022, его можно взять тут в обмен на почту. Расскажу самое важное. Специализация Java — не самый популярный язык для бэкенда, по частоте вакансий с ним соперничают JS (Node.js) и Python (Django). Ещё очень популярен Go, а во Франции в спину дышит PHP (Symphony). Вакансий на бэкенд и фуллстэк примерно поровну. Специализация на уровень зарплаты влияет мало: frontend, backend, mobile и fullstack разработчики зарабатывают почти одинаково. Зарплаты В табличке показаны средние по городам. Сверху — годы опыта, в ячейках — зп в тысячах евро. Указаны до вычета налогов, так что смело отбрасывайте 20-50% | 0-1 | 2-3 | 4-6 | 7+ Paris | 40 | 45 | 50 | 58 Berlin | 50 | 55 | 63 | 69 London | 41 | 58 | 70 | 76 Amsterdam | 40 | 45 | 55 | 64 Brussels | 36 | 40 | 49 | 59 Munich | 48 | 58 | 62 | 70 Hamburg | 45 | 55 | 60 | 70 Lille | 33 | 35 | 42 | 45 Lyon | 35 | 39 | 43 | 47 Bordeaux | 34 | 40 | 43 | 52 Toulouse | 35 | 37 | 41 | 45 (великолепная ascii-табличка заслужила огонёк!) Фрилансеры Средняя дневная ставка бэкендера с опытом 3-6 лет — €480, с опытом больше 7 лет — €590. Удалёнка 9% компаний требуют обязательного присутствия в офисе. 14% практикуют full remote, остальные работают в гибридном режиме. Сотрудники часто разбросаны по всей Европе. Например, 58% сотрудников-удалёнщиков в Берлине живут не в Германии. Франция идёт отдельным пунктом, потому что статистика сильно отличается от других стран ▫️ Вакансий с Full-stack в 2.5 раза больше, чем просто на бэкенд ▫️ Очень большой спрос на DevOps ▫️ Французы любят работать с французами даже в условиях удалёнки. 84% сотрудников живут во Франции.

IDEA: шорткаты для сверхзвуковой навигации по коду 🚀 Посмотреть список методов:
Ctrl + F12

Быстро найти нужный метод или узнать, что вообще умеет класс 🚀 Найти класс или файл в проекте: Shift-Shift Откроется строка поиска, можно ввести начало имени или аббревиатуру класса 🚀 Перейти к определению: Ctrl + B Для переменных — переходит к месту, где она была объявлена, для методов — к их реализации 🚀 Вернуться в предыдущий класс:
Ctrl + Alt + ⬅️
Ctrl + Alt + ➡️

IDEA хранит небольшую историю перемещений, по которой можно перемещаться стрелками. Так очень удобно править несколько связанных файлов 🚀 Найти строку по номеру: Ctrl + G Когда коллега пишет: "проверь условие в строке 850", можно не проматывать огромный класс, а быстро перейти на нужную строку Очень удобно, обязательно попробуйте👌

Как скопировать коллекцию? Вопрос хоть и звучит просто, но однозначно ответить на него нельзя. У внимательного разработчика сразу возникнут вопросы по ТЗ: 🤔 Как связаны исходник и копия? Если исходная коллекция поменяется, отразится ли это на копии? 🤔 Нужна изменяемая или неизменяемая копия? Для любой комбинации ответов у джавы есть решение: 1️⃣ Изменяемый прокси Прокси означает, что новый объект работает с теми же ссылками, что и старый. Изменяемый — что манипуляции с новым списком разрешены и приведут к изменениям в исходнике. Реализация простейшая:
refList = list

2️⃣ Неизменяемый прокси
ummodifiable = Collections.unmodifiableList(list)

Методы add, remove и replace у нового списка выбрасывают исключение. Менять исходную коллекцию никто не запрещает. Все изменения отобразятся во всех прокси. Теперь перейдём к группе "копии" (collectedList и copy). Сейчас объясню, чем они отличаются от предыдущих вариантов Каждый список — это набор ссылок. Исходный лист можно представить так: ▫️ ref1 → Order1 ▫️ ref2 → Order2 ▫️ list → структура данных, которая работает со ссылками ref1 и ref2 В прокси вариантах мы работаем с тем же list и с тем же набором [ref1, ref2]. В команде "копий" создаётся новый набор ссылок на те же объекты: ▫️ ref3 → Order1 ▫️ ref4 → Order2 "Копии" работают с другим набором ссылок: [ref3, ref4]. Изменение исходного набора никак не влияет на набор ссылок в "копиях". Ну и реализации: 3️⃣ Изменяемая копия
collectedList = list.stream().collect(toList())

4️⃣ Неизменяемая копия
copy = List.copyOf(list)

Правильный ответ на вопрос перед постом: refList, ummodifiable ❗️Важно: речь идёт только о ссылках и наборах ссылок. Объекты Order не копируются и остаются теми же. Если у объекта [order:1] id изменится на 100, то во всех списках будет [order:100] Для удобства свела все варианты в табличку:

В каком списке будет три элемента после выполнения кода выше?
Anonymous voting

В каком списке будет ТРИ элемента после выполнения кода?

Генерация ID в распределённой системе, часть 2: базы данных Коротенькое дополнение к предыдущему посту Каждая вторая статья про id пишет, что генерация через БД подойдёт только пет-проектам или MVP. И для нормальной работы нужен кластер сервисов, чья единственная задача — выдавать другим сервисам id. Отдельный кластер специальных сервисов, не меньше!!1 На большинстве моих проектов ID сущностей создавались через саму БД, и всё было хорошо. В посте покажу несложный приём, который часто используется. Начнём сначала. Когда в строке с ID пишется строка
ID SERIAL PRIMARY KEY

внутри БД создаётся счётчик, который увеличивается при каждой вставке Что не так: чтобы id не повторялись, запросы должны проходить через один экземпляр БД. Если сущности создаются часто и объём данных растёт, то такой подход усложняет масштабируемость. Непонятно, как добавить ещё один экземпляр БД Но если данных не очень много, то вариант отличный. Следующий шаг: вся последовательность равномерно делится между экземплярами БД. Например, для 3 экземпляров БД (шардов) шаг будет равен трём и формируются такие id: ▫️ В первом шарде: 1, 4, 7, 10, … ▫️ Во втором: 2, 5, 8, 11, … ▫️ В третьем: 3, 6, 9, 12, … Скрипт для второго шарда выглядит так:
CREATE SEQUENCE userIdGen INCREMENT BY 3 START WITH 2;  

✅ Нагрузка на БД ниже по сравнению с первым вариантом ✅ Несложно мигрировать с первого варианта на второй 😐 Не все БД поддерживают инкремент с шагом 😐 Для каждого экземпляра БД нужен свой скрипт 😐 Менять количество экземпляров БД — очень волнительный процесс Разумеется, подход с разделением ID не подходит для всех ситуаций. Но этот приём знают не все, поэтому он заслужил отдельный пост:)

Генерация ID в распределённой системе, часть 1 Задача считается сеньорной и входит в категорию system design. Вариантов решения много, и выбирать нужно с умом. Чтобы примерно сориентироваться, обозначу основные варианты и опорные точки. Над чем подумать в самом начале: 1️⃣ Насколько уникальным должен быть ID? 🔸 В рамках одного сервиса 🔸 Уникальным в пределах системы в течение какого-то времени 🔸 Глобально уникальным в течение всей жизни системы Два последних варианта влияют на длину id. Чем он короче, тем скорее наступит переполнение. Чем длиннее — тем больше памяти займёт id 2️⃣ Как часто нужно генерировать id? Влияет на размер и немного на реализацию 3️⃣ Если сущность отдаётся за пределы системы, что видит внешний пользователь? ▫️ id как есть: /user/123 ▫️ Декодированный id через Base64: /user/MTIz ▫️ Зашифрованный id: /user/67FA78 4️⃣ Формат 🔸 Возрастающая последовательность Глобальный счётчик, последовательность в БД или местный AtomicLong 🔸 Случайный набор цифр Глобально уникальный UUID или локальный Random ✅ Самый быстрый вариант 🔸 Вариации Snowflake Формат Snowflake придумали в Twitter. В оригинале id формируется как комбинация timestamp + machine_id + sequence_id (значения складываются как строки, а не как числа) ❄️ timestamp — количество миллисекунд ❄️ machine_id — id сервера ❄️ sequence_id — возрастающая последовательность ✅ id содержит что-то полезное ✅ Можно сортировать по полям, входящим в id ✅ Глобальная уникальность Machine id часто меняют на пару (id рабочей машины + id процесса) или (id датацентра + id сервера). Можно вдохновиться и составить свою комбинацию полей Технические моменты Snowflake Чтобы timestamp не получался слишком большим, отсчитывайте миллисекунды от какой-то даты отсчёта. Machine id извлекается в начале работы сервиса ▫️ из распределённого счётчика. Например, из Zookeeper ▫️ из конфига, если при развёртывании ведётся счётчик Для возрастающей последовательности подойдёт локальный AtomicLong или sequence в БД. Генерация ID в базе данных Часто говорят, что генерация id через БД — плохое решение. Все сущности должны проходить через один экземпляр БД, чтобы не было дубликатов, и это ограничивает масштабируемость. В следующем посте расскажу, как решить эту проблему:) Генерация через БД подходит, если объект и так сохраняется в базе данных. Если взаимодействий с БД нет (например, нужно id сообщения для кафки), конечно, нужны другие решения. ❓ Как формировать Snowflake id на основе sequence в БД? Шок контент: в хранимой процедуре. Формирование id — технический момент, а не бизнес-логика. Поэтому такое решение ок. ❓ Как формируется UUID, может ли он повторяться? Стандарт UUID описывает 5 стратегий генерации UUID. Метод UUID.randomUUID() использует Version 4, генерацию с помощью случайных чисел. Я тоже не доверяю случайным числам, но формулы обещают, что всё будет ок

IDEA: как не потерять важные места в коде В огромном проекте всегда есть места, которые хочется отметить или быстро находить. Раньше это делали так: 🔴 Ставили неактивный брейкпойнт в нужном месте. В принципе нормально, но иногда сложно вспомнить, что где находится ⭐️ Добавляли файл в favorites. Файл добавляется целиком, что не очень удобно Недавно в IDEA убрали favorites и добавили закладки. Супер удобно, ни одна важная строчка теперь не потеряется🥰 ▫️ Курсор на нужной строке → F11 → появляется закладка ▫️ Правый щёлк по закладке → Rename bookmark… → ввести что-то осмысленное ▫️ Посмотреть закладки: View → Tool Windows → Bookmarks

RegExp capturing groups В этом посте расскажу про группы в регулярках и покажу, как извлечь данные из текста без лишней суеты. Базовый синтаксис регулярных выражений можно почитать, например, в этой статье с кучей картинок. Группы — это уже уровень intermediate:) Допустим, есть строка src: Stack: Java 17, Spring Boot 2.7.1 Наша задача — вытащить отсюда версию джавы. Этап 1. Начнём с простого варианта:
String p = "Java\\s\\d+";
Matcher m = Pattern.compile(p).matcher(src);
if (m.find()) {
   res = m.group(); // Java 17
}
String version = res.substring(5); // 17

Этап 2: подключаем группы. В паттерн добавляются скобки
String p = "Java\\s(\\d+)";

После m.find() получаем следующее: ▫️ m.group() или m.group(0) → Java 17. В нулевой группе всегда содержится целиком найденное выражение ▫️ m.group(1) → 17 Получаем сразу версию, и substring нам больше не нужен😎 Пример посложнее. Из строки Stack: Java 17, Spring Boot 2.7 нужно извлечь версию java и spring boot. Сделаем паттерн по аналогии:
String p = "Java\\s(\\d+).+Boot\\s(\\d+\\.\\d+)";

Здесь два выражения в скобках и, соответственно, две группы (помимо нулевой):
if (m.find()) {
   javaVersion = m.group(1)); // 17
   bootVersion = m.group(2); // 2.7
}

Чтобы сделать код более читаемым, дадим группам имена. Вот так:
(?<name>X)
Где name — имя, X — регулярка. Теперь обновляем паттерн
String p = "Java\\s(?<java>\\d+).+Spring\\sBoot\\s(?<boot>\\d+\\.\\d+)";

Извлекаем версии
javaVersion = m.group("java");
bootVersion = m.group("boot");

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

Message brokers, часть 2: Kafka Если RabbitMQ — это 100% очередь, то Kafka больше похожа на список, потому что данные после чтения не удаляются. В принципе это основное отличие двух брокеров, остальное — просто следствие. Один список называется partition. Несколько partition можно объединить в группу, которая называется topic. Консьюмеры читают данные из партишена или топика. Для каждого консюмера хранится индекс последнего прочитанного сообщения (offset). Когда получатель прочитает сообщение, Kafka сдвинет его offset. И в следующий раз этот получатель прочитает другие сообщения. Если в partition 10 сообщений, то 🧔🏻 Один консьюмер прочитает сразу всё 👳🏻 Другой прочитает 5 и потом ещё 5 👩🏼‍🦰 Третий будет вычитывать по одному сообщению И никто никому не мешает☺️ В рамках одного partition все консюмеры читают сообщения в одном порядке. Иногда это очень важная фича. Для топика из нескольких partition такой гарантии нет. Поскольку данные не удаляются при чтении, получаются немного другие схемы работы: 🔸 Если сообщение должны прочитать несколько однотипных получателей, достаточно записать их в один partition 🔸 Если получатели разнотипные, то продюсер должен добавить данные в несколько партишенов. Пример: чтобы сообщение “A to C vip” прочитали C1 и C4, продюсер отправляет запись в топик orders и vip_orders. 🔸 Если нужно распределить сообщения по получателям, то консьюмеры объединяются в consumer group с общим оффсетом Резюме ▫️ В Kafka сообщения не пропадают при чтении, их можно читать несколько раз и пачками ▫️ Гарантия порядка сообщений в рамках одного partition ▫️ Kafka занимает горааааздо больше места на диске ▫️ Kafka использует pull модель — получатели сами решают, когда забрать сообщения. В RabbitMQ инициатива исходит от очереди, чтобы равномерно распределять сообщения ▫️ Разные схемы общения с продюсерами и консьюмерами. На картинке ниже я представила аналог схемы из предыдущего поста ▫️ Разные сценарии масштабирования и отказоустойчивости ▫️ Субъективное мнение — в рэббите проще распределять сообщения по получателям. Kafka подходит для накопления данных и более сложных сценариев ▫️Объективное — Kafka используется на бОльшем количестве проектов, пусть даже в качестве простой очереди😐 Общие черты двух брокеров: 🐰🐞 Отлично поддерживаются спрингом 🐰🐞 Можно настроить хранение сообщений на диске 🐰🐞 Нужно супер тщательно продумать схему работы и масштабирование PS Эти посты — самые основы месседж брокеров, прямо вот верхушечка. Для дальнейшего изучения подойдёт эта серия статей, книги "RabbitMQ in Action" и "Kafka in Action".

Message brokers, часть 1: RabbitMQ Оба брокера реализуют паттерн publish/subscribe. Его основные участники это 🔸 Producer — отправляет сообщения. Сообщение состоит из ключа, значения и хэдеров 🔸 Consumer — принимает сообщения 🔸 Message broker — компонент для обмена сообщениями, разворачивается отдельно Основная структура данных для распределения сообщений — очередь. Обычно в системе целое море продюсеров, очередей и консьюмеров. Чтобы упростить общение между ними, RabbitMQ использует промежуточный слой — exchangers. Принцип работы: Продюсеры просто отправляют сообщение в эксченджер. Оттуда оно распределяется в подходящие очереди в зависимости от ключа, хэдеров и настроек эксченджера. Сообщение копируется во все подходящие очереди. Консьюмер подсоединяется к интересным очередям и забирает оттуда сообщения. Чтобы было понятно, как это выглядит, посмотрите на картинку внизу поста👇 Сообщение удаляется из очереди после прочтения. Отсюда идут следующие схемы: ▫️ Если сообщение должны прочитать несколько получателей — у каждого должна быть своя очередь, куда это сообщение попадёт. Пример: сообщение order.from-A.to-C. vip попадает в две очереди — order.from-A.* и order.*.*.vip ▫️ Если нужно распределить сообщения между получателями, консьюмеры подключаются к одной очереди. RabbitMQ распределяет сообщения между ними равномерно по принципу round-robin. Пример: сообщение order.from-A.to-B и order.from-A.to-C распределяются между консюмерами С1 и С2 Рэббит использует push модель — каждое сообщение из очереди вызывает коллбэк на консьюмере. Это нужно, чтобы равномерно распределять сообщения между получателями. Очереди и связи задаются не в брокере, а в приложении. Роутинг сообщений получается супер гибким, и добавлять новых участников в систему легко. Из разных типов эксченджеров и очередей собирается огромное количество паттернов. Главное в RabbitMQ: ✔️ Основной компонент — exchanger и связанные с ним очереди ✔️ Сообщения удаляются после прочтения ✔️ Push-модель ✔️ Гибкий роутинг сообщений

Невозможно не рассказать — сейчас на Хабре идёт сезон джавы. Все статьи под этим тэгом дополнительно продвигаются хабром. Если есть чем поделиться, то сейчас идеальный момент! Для лучших статей заявлены призы, так что авторы стараются — есть много симпатичных статей с картинками и подробными примерами. Качество материала разное. Есть милая статья об AssertJ, некомпетентная про виртуальные потоки и обстоятельный справочник по Spring. Вот список статей, может найдёте что-то интересное для себя. Теперь обратно к этому каналу. На этой неделе расскажу принцип работы двух популярных брокеров сообщений: 🐰 Сегодня про RabbitMQ 🐞 В четверг про Kafka

Last call В понедельник стартует курс по многопоточному программированию 💛 Уровень: middle/senior Немного скринов отзывов на
+6
Last call В понедельник стартует курс по многопоточному программированию 💛 Уровень: middle/senior Немного скринов отзывов наверху, остальные на сайте ✅ Можно оплатить зарубежными картами. Напишите мне, расскажу как ✅ Можно посмотреть пробный урок про потоки https://fillthegaps.ru/mt5 Через недельку вернусь к постингу полезных постов☺️

Structured concurrency В java 19 войдёт новый JEP в стадии "инкубатор" — Structured concurrency. В этом посте расскажу, зачем он нужен и какую проблему решает. Многопоточка многих пугает своей сложностью. Но на самом деле java — очень дружелюбный язык, и новый JEP — отличный тому пример. Как выполнить большую задачу быстрее? Разбить на подзадачи, отправить в экзекьютор и объединить результаты:
Future f1=executor.submit(…);
Future f2=executor.submit(…);
…
return f1.get() + f2.get();

Что будет, если в задаче для f1 выбросится исключение? 👎 Мы узнаем об этом только при вызове f1.get() 👎 Задача в f2 продолжит работу, хотя это бессмысленно. В лучшем случае она просто потратит процессорное время Так как подзадачи логически не связаны между собой, программист должен добавить прерывания и механизмы отслеживания ошибок. Новый JEP берёт часть забот на себя:
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
 Future f1=scope.fork(…);
 Future f2=scope.fork(…);

 scope.join();    
 scope.throwIfFailed();

 return f1.resultNow()+f2.resultNow();
}

Что происходит: ▪️ scope.fork — задачи запускаются в едином логическом блоке ▪️ scope.join — ждём завершения подзадач ▪️ scope.throwIfFailed — пробрасываем исключение, если оно возникло в одной из подзадач. Другим методом можно получить экземпляр исключения и обработать его сразу ▪️Забираем результаты через resultNow и объединяем С первого взгляда всё то же самое. Но самое интересное происходит в первой строке, где определяются правила взаимодействия подзадач: 🔸 ShutdownOnFailure — если хотя бы одна подзадача выбросит исключение, остальные будут прерваны. Обработку прерывания всё ещё пишет разработчик, но java берёт на себя всю работу по отслеживанию и обновлению статусов 🔸 ShutdownOnSuccess — когда хотя бы одна задача завершится, остальные прерываются Бонус — JVM в курсе связей между задачами, поэтому в тред дампе подзадачи будут в древовидной структуре. ❓ Чем ShutdownOnSuccess отличается от методов anyOf в экзекьюторах и CompletableFuture? В текущих вариантах при ошибке другие задачи не прерываются, в лучшем случае задачи удаляются из очереди ❓ Что классного в этом JEP? Что по сути эта фича необязательна. Хоть кто-нибудь жаловался, что подзадачи в тред дампе не связаны? Что неудобно следить за исключениями в подзадачах? Нет, никто не жаловался. Но разработчики java изучают сценарии использования языка и стараются облегчить жизнь пользователям❤️ С многопоточкой то же самое, всё логично и продумано. Надо только знать, что для чего нужно и при каких условиях работает. Если хотите подробно в этом разобраться, вам сюда → fillthegaps.ru/mt5

Пет-проекты в резюме: основные ошибки Раньше пет-проект в резюме джуниора был редким явлением и сильно выделял кандидата среди других. Сейчас ссылки на гитхаб встречаются чаще, да и джуниоров стало больше. В этом посте кратко расскажу о 6 ошибках, которые портят впечатление и снижают вероятность приглашения на собес. 1️⃣ Нерабочий проект Видно, что код не работает и ни разу не запускался, много пустых файлов и TODO комментариев Как лучше: выкладывать готовые фичи, задачи в разработке описать в README 2️⃣ Устаревшие технологии и подходы XML конфигурация в Spring, сервлеты, JSP, Spring 3 и другие старые версии популярных библиотек и фреймворков Как лучше: учиться по туториалам не старше 5 лет 3️⃣ Слишком сложный код ▪️ Интерфейс и абстрактный класс для каждой сущности ▪️ Классы с одним полем и геттерами-сеттерами ▪️ Функциональные интерфейсы из функциональных интерфейсов 4️⃣ Тяжело читаемый код ▫️ Непонятные имена методов, классов и переменных ▫️ Методы с сайд-эффектами, там где их быть не должно ▫️ Длинные методы ▫️ DRY любой ценой ▫️ Методы возвращают комбинации из Map, List, Pair и примитивов ▫️ Процедуры вместо функций Что я имею в виду: ❌ filter(List input, List output); ✅ List filtered = filter(input); 5️⃣ Нет бизнес-логики Вариант 1: простейший CRUD для двух сущностей Как лучше: если не хватает идей, возьмите любое приложение или сайт и реализуйте 5 интересных фич оттуда Вариант 2: 300 классов с простейшими функциями. Яркий пример — игры со множеством персонажей и предметов. Непонятно, куда смотреть и что происходит Как лучше: сфокусировать бизнес-логику в нескольких классах, разбить код на пакеты, написать README 6️⃣ Неоднородный код Когда части проекта копируются из разных источников как есть. Смешивается xml, yaml и Java-based конфигурация, документированные и стильные блоки кода находятся рядом с неформатированным безумием Как лучше: не слепо копировать код, а понять решение и адаптировать под проект ⭐️ Бонусный пункт: не ориентироваться в проекте Когда на этапе собеседования человек отвечает на вопросы по собственному коду вот так: 😐 Я забыл, зачем это 😐 Тут надо переделать 😐 Сюда не смотрите 😐 Не знаю, зачем, но без этого не работает Как лучше: пусть в пет-проджекте будут не все технологии, но вы понимаете, что происходит, готовы обсудить решения и ответить на дополнительные вопросы.

Для самостоятельных Места на тарифе с обратной связью разлетаются как пирожки, поэтому сегодня расскажу о тарифе "Заполнить пробелы" и своих наработках. Основной педагогический челлендж любого курса — как организовать адекватную самостоятельную работу. В тарифе с обратной связью это вопросы с открытым ответом и код-ревью. Без обратной связи эти форматы меняются: 1️⃣ Задания с кодом Основа у всех тарифов одна: 🔸 Заготовки кода с пояснениями 🔸 Unit и нагрузочные тесты При отсутствии код-ревью добавляется пункт 🔸 Примеры реализаций Здесь велик соблазн сразу посмотреть решение, но я надеюсь на сознательность:) Где-то поменяла задание целиком — например, рефакторинг заменила на анализ кода и его вариаций. 2️⃣ Вопросы с открытым ответом Согласитесь, это совершенно разные вещи — сформулировать ответ самостоятельно или выбрать из готовых вариантов. Поэтому здесь формат сильно меняется. Пример задания: посмотреть код и найти возможные проблемы Тариф С обратной связью Открытый вопрос — ученик полностью формирует ответ. Тут либо хвалю, либо задаю наводящие вопросы и проясняю непонятные моменты Тариф БЕЗ обратной связи В арсенале только тесты, поэтому к тем же ответам идём мелкими шагами: ❓ Какие гарантии даёт метод А? ❓ У какого объекта захвачен монитор в методе Б? ❓ А в методе Ц? И только потом ❓ Какие проблемы возможны в этом коде? Путь к ответу длиннее, но более последовательный. По статистике ответов такой подход работает лучше! 🥰 Итого Обратная связь — это, конечно, люксус класс, но и без неё можно разобраться в большинстве вопросов. Учебные материалы для всех тарифов одинаковые. Путь к успеху — не забивать на непонятные моменты и стараться найти ответ в предложенных материалах. Если вы дисциплинированы, готовы разобраться в многопоточке и потратить меньше денег, то возьмите тариф без обратной связи, он тоже классный! Название у него не совсем удачное, по сути это "Покажите, куда смотреть, и я разберусь". И несколько напоминаний: 🔥 Курс можно пройти за счёт компании. Если процесс согласования долгий, напишите мне, я займу вам место 🔥 Можно оплатить НЕ российскими картами. Напишите мне, расскажу, как снизить комиссию 🔥 До завтра действует цена для early birds, успейте записаться со скидкой! https://fillthegaps.ru/mt5

Что происходит на курсе Начну с горячей новости🔥 Теперь можно оплатить курс НЕроссийскими картами! Если это ваш случай, напишите мне , расскажу как это сделать с комиссией всего 4%. Теперь к теме поста — расскажу про материалы на курсе. Теория Эта часть не сильно меняется от потока к потоку — лекции занимают 10-20 минут и максимально насыщены информацией. Периодически их перезаписываю. JEP про виртуальные потоки вышел совсем недавно — а лекция уже обновилась🙂 После лекции идут тесты на теорию и вопросы с собеседований. Не самая интересная часть, но необходимая. Практика Больших проектов на курсе нет. Тем и ситуаций много, а практика многопоточки в одном проекте ограничена. Это всё равно, что в одном сервисе применить 23 GoF паттерна — можно, но далеко от реальности. Задания небольшие и сфокусированные: 🔸 Анализ сниппетов Любимые задания учеников❤️ Найти ошибки, разобрать приёмчики, понять, что хотел сказать автор, предложить более изящное решение. Большинство сниппетов из реальных проектов! 🔸 Рефакторинг и написание кода 🔸 Лабораторные работы — новый тип заданий в 5 потоке! Приведу пример, как это выглядит и зачем нужно: На практике много ошибок связано с неудачным подбором параметров экзекьютора. ▫️ Что было раньше: в лекции про экзекьюторы рассказывала возможные формулы и подходы, были задания посчитать оптимальное количество потоков при разных условиях ▫️ Проблема: тема сдана, но пару недель спустя в других заданиях ошибки повторяются ▫️ Что сделала: добавила задание на исследование производительности в зависимости от параметров экзекьютора и вида нагрузки. Ученику даётся готовый код и нагрузочный тест, остаётся экспериментировать с параметрами и нагрузкой. Увидеть своими глазами, как параметры влияют на результат — бесценно👌 И таких примеров много. Всё понятно, последовательно и наглядно. Присоединяйтесь! https://fillthegaps.ru/mt5

Анонс курса по многопоточке Привет! Сегодня открывается набор на курс по многопоточному программированию. Кто давно ждал и уже готов → вам сюда Что будет? Курс строится вокруг java.util.concurrent — боевой лошадки каждого нагруженного сервиса. В деталях изучим все классы, концепты и практическое применение. Разберём огромное количество кейсов, лучших практик и возможных ошибок. Немного затронем смежные темы: тестирование, виртуальные потоки и реактивное программирование. Уровень: middle/senior Старт: 11 июля Длительность: 8 недель Полная программа, отзывы и запись тут: http://fillthegaps.ru/mt5 Зачем идти? ✅ Закрыть пробелы в базе. java.util.concurrent — важная часть java core ✅ Работать на любых проектах. Многопоточка есть не только в хайлоад сервисах, а вообще везде, хоть и прячется под слоем абстракций ✅ Выбирать оптимальное решение для многопоточных задач, а не первое работающее со StackOverflow ✅ Круто выглядеть на собеседовании. Кандидат, который внятно говорит про модель памяти и приводит жизненные примеры, сразу попадает в категорию "интересный"🙂 Сколько стоит? До 25 июня действует скидос: 🔸Тариф без обратной связи: 29900 23900 🔸Тариф с обратной связью: 59900 44900 Курс можно оплатить за счёт компании! Пусть ваши коллеги напишут на diana@fillthegaps.ru Аналогов у курса нет. С каждым потоком программа становится лучше, задания интереснее, а учёба приятнее. Обычно процесс улучшений остаётся за кадром, но на этой неделе расскажу обо всём подробно. Если хотите разобраться с многопоточкой, и вам близок мой стиль изложения — записывайтесь, будет очень полезно: http://fillthegaps.ru/mt5

Переключение между задачами Иногда во время работы над одной задачей нужно переключиться на другую: поправить пул реквест или сделать хотфикс. Если текущие изменения не готовы для полноценного коммита, можно использовать stash или shelve. Stash Изменения сохранятся в локальном git репозитории, а текущая ветка почистится. Можно спокойно переключаться на другую задачу.
git stash save "stash name"
В IDEA: VCS → Git → Stash Changes... Вернуть изменения на место: 🔸 git stash apply "stash name" и оставить stash в локальном репозитории 🔸 git stash pop "stash name" и удалить стэш 🔸 В IDEA: VCS → Git → Unstash Changes... Что важно: ✅ Сохраняются ВСЕ текущие изменения в ветке ✅ Обратно применяются ВСЕ изменения в стэше ✅ Изменения хранятся в локальном git репозитории Shelve Удобная фича IDEA для сохранения части изменений: VCS → Shelve Changes... Галочками отмечаем, что сохранить. Чтобы вернуть обратно: Вкладка Git (Alt + 9 или найдите внизу) → Shelve Отмечайте, какие изменения применить к коду ✅ Можно выбрать, что сохранять ✅ Можно указать, что восстановить ✅ Изменения хранятся в локальном IDEA проекте