Java Digest #32

Всем привет! 👋👋👋👋👋
Мы — Java-разработчики Т-Банка: Андрей, Арсений, Роман, Константин и Константин. Собираем интересные новости, статьи, туториалы и другие материалы из мира Java-разработки и делимся этим со всем сообществом.

Объектно-ориентированный язык программирования

Всем привет! 👋👋👋👋👋
Мы — Java-разработчики Т-Банка: Андрей, Арсений, Роман, Константин и Константин. Собираем интересные новости, статьи, туториалы и другие материалы из мира Java-разработки и делимся этим со всем сообществом.

В начале 2000-х на сцену вышел Spring Framework — сначала как скромная альтернатива, а затем как настоящая революция в Java-мире. Он предложил радикально иной подход: простоту, ориентированность на бизнес-логику и свободу от излишней инфраструктурной навязчивости.
Цель статьи — рассмотреть Spring как эволюционирующий инструмент. Мы проследим, как менялись его идеи, подходы и архитектурные парадигмы: от борьбы с J2EE до микросервисов, реактивности и cloud-native-приложений. Каждая эпоха диктовала свои вызовы — и Spring неоднократно перерождался, чтобы оставаться актуальным.

Всем привет! На связи команда Explyt Spring. Недавно у нас вышел очередной релиз, который включает поддержку MCP Server plugin. Мы добавили “тулы”, облегчающие работу со Spring проектами для LLM. Ранее у нас уже была статья, в которой мы рассказывали об интеграции с Explyt AI плагином. Это были простые промпты для генерации: DTO, Entity, SQL скриптов и прочего. Несмотря на свою простоту, они добавляли в промпт необходимую информацию для выполнения конкретного действия: необходимый файл, тип БД - который подключен к проекту, библиотека для работы с Entity - javax или jakarta и прочее. Теперь пришло время добавить полноценные агентские Spring "тулы" для LLM, чтобы более точно понимать контекст Spring приложения.

О проблемах найма я узнал не из аналитических отчётов — а потому что сам оказался внутри рынка труда. С одной стороны — как кандидат, с другой — как человек, работавший с HR и процессами найма.
Так же читая новости и статьи, в том числе на Хабре, как стремительно развивается AI в разработке, решил реализовать инженерный эксперимент и создать MVP рекомендательной системы для HR.
В этой статье делаю разбор того что получилось в итоге:
• как архитектура и BDD стали “ограничителями” для агента
• как я формировал и тестировал требования с помощью AI
• как сформировал RAG/контекст для AI агента
• с какими проблемами столкнулся и что сработало
• где мое место в процессе разработки
• какие skills потребовались мне и какие в итоге сформировал для AI агента
Изучая Java и подойдя к теме дженериков осознал необходимость вернуться к некоторым азам, постепенно наматывая на ус новые знания. Для этого сформулировал для себя поэтапное рассуждение, которое помогло мне закрепить знания. Надеюсь поможет и еще кому-то. Это не всеобъемлющее представление о дженериках, а лишь некоторые аспекты, которые помогают понять часть проблематики, из-за которой они появились.
Итак. Есть такой простейший код:

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

Начиная с этого месяца мы ежемесячно будем знакомить вас с доработками в плагинах GigaIDE — как в Community-версии, так и в PRO. Если кто-то пропустил, в декабре мы уже делали краткий обзор текущей линейки функциональности, когда рассказывали про наш маркетплейс.
Итак, начнём!

В прошлой статье мы запустили эмулятор и убедились, что Android Automotive OS (AAOS) — это не просто зеркало вашего телефона. Это самостоятельная экосистема. Но пока мы запускали только стандартные медиа-плееры, мы скользили по поверхности.
Настоящая магия начинается там, где софт встречается с «железом».
В телефоне у вас есть стандартный набор датчиков: GPS, акселерометр, гироскоп. В современном автомобиле таких датчиков тысячи: от давления в шинах и температуры масла до угла поворота руля и статуса каждой двери. Как Android-разработчику получить доступ к этому океану данных? Не будем же мы тянуть провода к OBDII разъему?
Конечно, нет. Для этого Google построила мощный мост, по которому мы сегодня и пройдемся. Добро пожаловать в мир Car API и VHAL.

Сегодня проведём полный экономический анализ для каждого языка программирования, основанный на реальных данных и кейсах и покажем, как количественно оценить trade-off между скоростью разработки и производительностью, учесть долгосрочные затраты на поддержку кода.
В меню — исследования скорости разработки, стоимость изменений, скорость обновления кода для разных отраслей, стоимость инфры. Учитывая эти факторы, посчитаю для скольких RPS экономически оправдано использовать тот или иной язык разработки.
В конце вы получите ссылку на экономическую модель, которую сможете забрать и использовать у себя, подкрутив разные параметры для своего кейса.

Всем привет!
Сегодня хочу затронуть тему виртуальных потоков и выяснить на сколько они лучше (быстрее) и в каких случаях, чем обычные потоки операционной системы (или как еще их называют платформенные потоки).
Долгое время java полагалась только на потоки операционной системы для обработки параллельных операций. Это выглядело следующим образом, когда веб-сервер получал запрос, он обычно выделял один поток операционной системы для его обработки. Эта модель называется «поток на запрос». Она очень проста — мы просто пишем блокирующий код так, как если бы он был синхронный, а операционная система обрабатывает переключение контекста между потоками в рамках какого-то процесса.
Несмотря на свою простоту, эта модель имеет существенный недостаток: потоки операционной системы обходятся дорого. Каждый поток потребляет от 1 до 2 МБ памяти только на свой стек, а переключение между ними включает в себя переключение контекста на уровне операционной системы, что также является ресурсоемкой операцией.
Представьте, что есть задача по обработке 100 000 одновременных запросов с помощью этой модели. Это приведёт к потреблению десятков гигабайт памяти только под стеки потоков и, скорее всего, к аварийному завершению JVM задолго до достижения такого количества потоков, также будет тратиться время на переключение контекста между потоками. Пропускная способность системы резко упадет из-за накладных расходов.
Для решения этой проблемы разработчики прибегают к сложным асинхронным моделям программирования, к реактивному программированию, к управлению событиями. Хотя эти подходы и являются мощным инструментом, но они вносят значительную сложность, затрудняя чтение, отладку и сопровождение кода. Мы меняем простоту блокирующего кода на сложности, связанные с неблокирующими коллбэками и реактивными потоками.

Всех приветствую!
В прошлый раз я не указал важный аспект: на данном этапе проект - это монолит. Однако архитектура закладывается с учетом того, что в будущем систему можно будет разнести на разные серверы.
Хочу поблагодарить пользователей за конструктивную критику в комментариях. В частности, @aleksandy верно подметил использование LocalDateTime вместо Instant. Повторюсь: на этапе прототипирования это осознанный выбор для удобства отладки и прямого контроля данных в БД "глазами", без конвертации часовых поясов в уме. Переход на Instant - это стандарт для продакшена, и он заложен в план развития.
Также коснулись темы equals() и hashCode(). В текущей реализации я использую getClass(). Знаю, что это не учитывает работу Hibernate Proxy (когда вместо реального объекта мы получаем его обертку‑пустышку для ленивой загрузки). На текущей «плоской» структуре данных это не критично, но как только мы перейдем к сложным связям, будет рефакторинг этих методов через instanceof, чтобы избежать ошибок сравнения.

Когда проект вырастает из простых задач, каждый повторный запрос к базе данных превращается в бесполезную нагрузку на диски и процессор. И вместо того чтобы заставлять систему раз за разом искать, фильтровать и считывать одни и те же данные, логичнее отдавать их напрямую из оперативной памяти.
В этой статье разберем, как эффективно внедрить слой кэширования на связке Redis + Spring Boot 3 / Java 21.
Пробежимся по базовым командам Redis, реализуем cache‑aside вручную и через аннотации Spring Cache, а затем разберем два полезных паттерна для микросервисов: Fixed‑Window Rate Limiter и распределенный лок. Не пугайтесь сложных терминов, все понятным языком рассказал под катом.

Всем привет! В данной статье будет описан один из возможных вариантов реализации паттерна outbox transactional.
План данной статьи такой: вначале немного теории, а потом на примере двух микросервисов будет показала реализация данного паттерна с помощью postgresql, debezium и kafka.
Данная статья будет полезна для разработчиков, которые не встречались с данным паттерном.
Вначале теория и самый главный вопрос: зачем нужен данный паттерн и какую он решает задачу?
Паттерн Transactional Outbox используется в распределенных транзакциях, то есть в транзакциях, которые проходят и затрагивают несколько микровервисов, для обеспечения гарантированной доставки сообщения от одного микросервиса до другого. Данный паттерн используется там, где очень критично, чтобы сообщение не потерялось, даже при сбоях в системе. Outbox паттерн получил распространение именно в микросервисной архитектуре, где нет возможности с помощью одной аннотации обеспечить транзакционность какого-то конкретного метода.

Привычные UI‑автотесты часто проверяют отдельные кнопки и формы, но не отвечают на главный вопрос: работает ли система целиком в реальном пользовательском сценарии. В этой статье я расскажу, как мы в TData строим интеграционные тесты для Web UI, которые проходят путь от создания провайдера и кластера до установки компонентов, настройки конфигурации и проверки, что всё действительно поднялось и работает.

За последние годы разработчики в распределённых системах почти решили инфраструктурные проблемы: масштабирование, деплой, отказоустойчивость. Ценой этого прогресса стал экспоненциальный рост сложности бизнес-логики, которая всё чаще выражается не в коде, а в порядке сервисных вызовов.
Современные команды научились разбивать монолиты на микросервисы, оркестрировать их в Kubernetes и наблюдать через распределённые трассировки. Инфраструктура стала управляемой, но сама бизнес-логика — нет. И чем больше сервисов создаётся, тем сложнее сохранять целостность данных, порядок действий и предсказуемость поведения.
Типичный сценарий: бизнес приходит с задачей "Если в корзине три товара категории "Электроника", положи в подарок чехол, но только если регион доставки не "Дальний Восток". Звучит как if-else на пять строк. Но в распределённой системе это превращается в такой себе квест: BasketService синхронно обращается к Catalog, затем к Warehouse, затем к GeoService. Где-то посередине случается таймаут, где-то - сетевой сбой, и в коде начинают появляться саги, компенсации и ретраи.
В результате бизнес-логика перестаёт быть просто кодом. Она превращается в топологию вызовов: тонкий слой условий, размазанный по HTTP-клиентам и контроллерам. И чем сложнее система, тем страшнее становится трогать эти цепочки.
Я приглашаю сегодня взглянуть на проблему под другим углом. Что если пересмотреть не инструменты, а саму парадигму управления состоянием?
Я активно использую на проекте Kafka Connect Framework и в частности Kafka JDBC Sink Connector для быстрого сохранения данных из Kafka Topic в БД PostgresSQL. Для большинства задач достаточно написать простую JSON-конфигурацию и все стабильно и быстро работает из коробки. Нет необходимости в написании собственного кода. Однако в нетиповых ситуациях расширяемость Kafka Connect тоже помогает - можно переопределить и написать один из компонентов.
В конфигурации JDBC Sink Connector Task существует настройка dialect.name, которая отвечает за выбор диалекта для работы с конкретной БД. Как правило, в 99% случаев используется один из уже реализованных для популярных БД диалектов, как например в моем случае PostgresSqlDatabaseDialect для PostgreSQL.
Может показаться, что вряд ли кому-то понадобится реализовывать свой диалект, если только не имеем дело с какой-то специфичной непопулярной БД. Однако на практике оказалось, что реализация своего диалекта даже для PostgreSQL может быть полезна для решения некоторых возникающих прикладных задач.
В данной статье я хочу показать идеи того, как реализация своего DatabaseDialect может помочь при имплементации нестандартных сценариев для вполне себе популярной БД Postgres, для которой существует PostgresSqlDatabaseDialect.

Всем привет! Когда речь заходит о разработке высоконагруженных систем, многие предлагают: «python, сделать проще и быстрее». Но есть проблема: Скорость разработки != скорость и качество работы сервиса. Когда мы делаем любой продукт, важны: Масштабируемость, стабильность работы под большой нагрузкой, предсказуемость поведения системы — особенно когда речь идет о тысячах одновременных пользователей, лентах новостей в реальном времени, уведомлениях и сложных связях между разными сущностями.
Именно поэтому и выбрана Java и Spring Boot как основа. Банки, сервисы видео, они работают именно на Java и Spring.
Одна из особенностей: строгая типизация, качественные инструменты для многопоточности, мощная экосистема и предсказуемое потребление памяти делают Java идеальным выбором для систем, где падение = полная потеря пользователей.
Попробую сделать цикл статей по разработке соцсети, которая будет объединять в себе ВК, пикабу, и иже с ними. Не ради «создания продукта который затмит всех и вся», а ради самого программирования.
Итак, начну, среда разработки Intellij Idea. О, точно, весь проект будет доступен из gitLab. Нам необходимо создать файлы с конфигурацией. можно сказать что их обычно 3. Да, я про application.yml. один из них общий, который так и называется: application.yml, и еще два: application-dev.yml и application-prod.yml

Планируешь миграцию на Spring Boot 4.0? Вместе с Eddy Benchek в новом переводе от команды Java Insider разбираем пять неочевидных проблем, с которыми столкнулась реальная production-команда при миграции, и показываем, как их исправить, чтобы вы не потеряли дни на поиски неожиданных багов.
Здравствуйте, меня зовут tmaxx, и я алкоголик понял что такое монады. И, естественно, рассказываю об этом всем вокруг, в том числе и вам. Конечно, это Далеко Не Первая Статья О Монадах на Хабре, но ещё один альтернативный взгляд на проблему, думаю, не помешает.
«Монада», как известно, это «моноид в моноидальной категории эндофункторов», что дает примерно ноль информации несведущему человеку. В программировании, можно попробовать определить монаду как «штуку, реализующую вот такие методы»:
(>>=) :: forall a b. m a -> (a -> m b) -> m b return :: a -> m a
Не понятно на Хаскеле? Вот примерный эквивалент на Java:
<A, B> Monad<B> bind(Monad<A> ma, Function<A, Monad<B>> famb);
<A> Monad<A> ret(A a);
Все равно остались вопросы? Почему именно такая сигнатура? Что в ней такого особенного, что она используется абсолютно во всех реальных программах написанных на функциональных языках? Попробуем разобраться.

Как всегда, это история о политике, крови, грызне и скудоумных менеджерах.
Мне всегда казалось, что C# сильно лучше нашей Java (только LINQ expressions чего стоит — именно expressions, а не применения типа LINQ-to-objects). А в F# (тоже работает на .NET) есть нормальные провайдеры типов и другая функциональщина. И всё это работает чудесно, а не как Haskell, который несколько лет подряд сегфолтился на Windows, и никто это не чинил.
Но всё портит маниакальная борьба Microsoft с конкурентами и из-за этого отсутствие экосистемы вне продуктов Microsoft. Это отсутствие конкуренции и деградация. Какой дурак захочет связываться с технологией, из-за которой тебя может назавтра кинуть создатель этой технологии? Беда, C# нам тоже не подходит.