Приглашаем на ЮMoneyDay — бесплатную онлайн-конференцию про финтех и IT 🔥
На протяжении двух дней будем общаться с разработчиками, инженерами, тестировщиками, продактами, дизайнерами и другими специалистами из ЮMoney. Они расскажут про свой опыт работы в большом финансовом продукте, поделятся лайфхаками и секретами.
Будут доклады по 16 направлениям:
🟣 Будущее финтеха
🟣 Бэкенд
🟣 Фронтенд
🟣 Тестирование
🟣 Python
🟣 Менеджмент проектов
🟣 Менеджмент продуктов
🟣 Системный анализ
🟣 SQL
🟣 UX
🟣 ИИ
🟣 Архитектура IT-решений
🟣 Внутренние системы
🟣 Мобильная разработка
🟣 Инфраструктура
🟣 О компании
Встречаемся онлайн 5 и 6 декабря в 11:00 мск. Чтобы участвовать, зарегистрируйтесь на сайте конференции✅
На протяжении двух дней будем общаться с разработчиками, инженерами, тестировщиками, продактами, дизайнерами и другими специалистами из ЮMoney. Они расскажут про свой опыт работы в большом финансовом продукте, поделятся лайфхаками и секретами.
Будут доклады по 16 направлениям:
Встречаемся онлайн 5 и 6 декабря в 11:00 мск. Чтобы участвовать, зарегистрируйтесь на сайте конференции
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1🔥1
Spring Modulith добавили поддержку Application-Module Aware миграций в Flyway.
Посмотреть, как это работает, можно тут👇
https://github.com/sivaprasadreddy/spring-modular-monolith
👉 Java Portal
Посмотреть, как это работает, можно тут
https://github.com/sivaprasadreddy/spring-modular-monolith
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🤔1
Совет по Spring Boot
Когда пишешь REST API на Spring Boot, обычно используют префикс
Чтобы не лепить
👉 Java Portal
Когда пишешь REST API на Spring Boot, обычно используют префикс
/apiЧтобы не лепить
@RequestMapping("/api") в каждом контроллере, можно настроить это один раз вот так:@Configuration
class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.addPathPrefix("/api",
aClass -> aClass.getPackage().getName().startsWith("com.sivalabs.bookstore"));
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤4😁1
Какой будет вывод и почему?
Если ты не можешь ответить на это, значит ты пока не готов к интервью.
👉 Java Portal
class Person {
String name;
}
public class Test {
static void modify(Person obj) {
obj.name = "Rahul";
obj = new Person();
obj.name = "Amit";
}
public static void main(String[] args) {
Person p = new Person();
p.name = "Sumit";
modify(p);
System.out.println(p.name);
}
}Если ты не можешь ответить на это, значит ты пока не готов к интервью.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍5
Можно использовать асинхронный логгинг в Spring Boot, настроив logback (logback-spring.xml).
Лог-сообщения отправляются в очередь и обрабатываются отдельным фоновым потоком.
Это уменьшает задержки, связанные с вводом-выводом.
Положи файл конфигурации logback в папку resources:
Вот пример:
👉 Java Portal
Лог-сообщения отправляются в очередь и обрабатываются отдельным фоновым потоком.
Это уменьшает задержки, связанные с вводом-выводом.
Положи файл конфигурации logback в папку resources:
src/main/resources/logback-spring.xml
Вот пример:
<configuration>
<!-- Console appender, обёрнутый в асинхронный -->
<appender name="ASYNC_CONSOLE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="CONSOLE" />
<queueSize>5000</queueSize>
<discardingThreshold>0</discardingThreshold>
<includeCallerData>false</includeCallerData>
</appender>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="ASYNC_CONSOLE" />
</root>
</configuration>
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤2
Media is too big
VIEW IN TELEGRAM
Разработчик выложил проект ShadowStream, систему отслеживания изменений в базе данных (CDC), построенную на PostgreSQL logical replication.
Цель проекта — ловить любые изменения в реальном времени и передавать их в потоковую инфраструктуру.
Как это работает:
- изменения в базе (INSERT, UPDATE, DELETE) сразу перехватываются через logical replication
- события сериализуются в Protobuf и отправляются в Redis Streams для быстрого доступа
- параллельно те же данные архивируются в Kafka для надежного хранения
- Kafka использует grouped consumer'ов: два обработчика работают параллельно, плюс резервная группа с отдельным offset
- поверх всего в Django Admin добавлена визуализация gRPC-вызовов
Исходники открыты на GitHub
Проект может пригодиться тем, кто работает с потоковой обработкой данных, аналитикой, репликацией или интеграцией микросервисов.🙂
👉 Java Portal
Цель проекта — ловить любые изменения в реальном времени и передавать их в потоковую инфраструктуру.
Как это работает:
- изменения в базе (INSERT, UPDATE, DELETE) сразу перехватываются через logical replication
- события сериализуются в Protobuf и отправляются в Redis Streams для быстрого доступа
- параллельно те же данные архивируются в Kafka для надежного хранения
- Kafka использует grouped consumer'ов: два обработчика работают параллельно, плюс резервная группа с отдельным offset
- поверх всего в Django Admin добавлена визуализация gRPC-вызовов
Исходники открыты на GitHub
Проект может пригодиться тем, кто работает с потоковой обработкой данных, аналитикой, репликацией или интеграцией микросервисов.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11❤4
Java даёт много вариантов по части синтаксиса, но функциональные интерфейсы — одна из самых аккуратных и приятных фишек языка ☕️
Сегодня разберём 4 штуки, которые встречаются чаще всего. Если поймёшь их, писать код станет современнее, местами чище
Идея простая👇
Функциональный интерфейс — это интерфейс с одним абстрактным методом. Благодаря этому его можно реализовать через лямбды.
В Java их много, но вот четыре, которые ты будешь видеть постоянно:
👉 Consumer — делает что-то
Consumer принимает значение и ничего не возвращает.
Отлично подходит для побочных эффектов: логирование, вывод в консоль, сохранение, отправка и так далее.
Проще говоря:
"получи это и сделай с этим что-то".
👉 Supplier — дай что-то
Supplier ничего не принимает и возвращает значение.
Часто используется для получения конфигураций, генерации ID, ленивого создания объектов и прочего.
То есть:
"выдай нужную штуку, когда я попрошу".
👉 Function<T, R> — преобразуй что-то
Принимает значение типа T и возвращает значение типа R.
На практике эта штука — самая распространённая.
По смыслу:
"получаю T, возвращаю R".
👉 Predicate — реши что-то (true/false)
Принимает значение и возвращает boolean.
Часто нужен для фильтрации списков, простых проверок, валидаций, правил.
То есть:
"подходит или не подходит под условие".
Важно:
Эти интерфейсы существуют не ради компактного кода.
Они нужны, чтобы ты думал через операции, а не через классы.
Они идеально заходят в Streams, в коллбеки, в валидации, в композицию логики — везде, где есть простая операция, для которой не нужна отдельная сущность.
Это не замена всему на свете. Речь не про то, чтобы переписать всю систему в функциональном стиле.
Но они реально помогают во множестве сценариев.
Если научишься читать Function, Consumer, Supplier и Predicate, то спокойно разберёшь и напишешь современный Java-код без лишних страданий. И это уже хороший шаг вперёд.😁
👉 Java Portal
Сегодня разберём 4 штуки, которые встречаются чаще всего. Если поймёшь их, писать код станет современнее, местами чище
Идея простая
Функциональный интерфейс — это интерфейс с одним абстрактным методом. Благодаря этому его можно реализовать через лямбды.
В Java их много, но вот четыре, которые ты будешь видеть постоянно:
Consumer принимает значение и ничего не возвращает.
Отлично подходит для побочных эффектов: логирование, вывод в консоль, сохранение, отправка и так далее.
Consumer<String> consumer = str -> System.out.println(str);
consumer.accept("Hola");
Проще говоря:
"получи это и сделай с этим что-то".
Supplier ничего не принимает и возвращает значение.
Часто используется для получения конфигураций, генерации ID, ленивого создания объектов и прочего.
Supplier<Double> supplier = () -> Math.random();
supplier.get();
То есть:
"выдай нужную штуку, когда я попрошу".
Принимает значение типа T и возвращает значение типа R.
На практике эта штука — самая распространённая.
Function<Integer, String> function = number -> "N° " + number;
function.apply(5);
По смыслу:
"получаю T, возвращаю R".
Принимает значение и возвращает boolean.
Часто нужен для фильтрации списков, простых проверок, валидаций, правил.
Predicate<String> predicate = s -> s.length() > 5;
predicate.test("Java");
То есть:
"подходит или не подходит под условие".
Важно:
Эти интерфейсы существуют не ради компактного кода.
Они нужны, чтобы ты думал через операции, а не через классы.
Они идеально заходят в Streams, в коллбеки, в валидации, в композицию логики — везде, где есть простая операция, для которой не нужна отдельная сущность.
Это не замена всему на свете. Речь не про то, чтобы переписать всю систему в функциональном стиле.
Но они реально помогают во множестве сценариев.
Если научишься читать Function, Consumer, Supplier и Predicate, то спокойно разберёшь и напишешь современный Java-код без лишних страданий. И это уже хороший шаг вперёд.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17❤4🔥2🤣1
Кандидаты часто путаются, когда спрашивают:
На самом деле всё очень просто.
* Rate limiting
Задаёт фиксированный максимум запросов.
Если превысил лимит — лишние запросы просто блокируются.
Пример: 100 запросов в минуту разрешено. 101-й — отклоняется.
* Throttling
Не блокирует. Он замедляет обработку запросов, когда ты начинаешь спамить.
Пример: после 100 запросов каждый следующий обрабатывается с задержкой, но всё равно проходит.
Запомнить легко:
Rate limiting — стоп сверхлимита.
Throttling — замедление сверхлимита.
👉 Java Portal
в чем разница между rate limiting и throttling?
На самом деле всё очень просто.
* Rate limiting
Задаёт фиксированный максимум запросов.
Если превысил лимит — лишние запросы просто блокируются.
Пример: 100 запросов в минуту разрешено. 101-й — отклоняется.
* Throttling
Не блокирует. Он замедляет обработку запросов, когда ты начинаешь спамить.
Пример: после 100 запросов каждый следующий обрабатывается с задержкой, но всё равно проходит.
Запомнить легко:
Rate limiting — стоп сверхлимита.
Throttling — замедление сверхлимита.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤3🤔1
Совет по Java: в JPA можно использовать native query не только для SELECT, но и для UPDATE, DELETE и INSERT. Учти, что в этом случае всё проходит мимо EntityManager и PersistenceContext.
👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🔥2
Одна из самых опасных проблем в распределенных системах это двойная запись:
сохранить что-то в своей базе и параллельно опубликовать событие в другой системе, рассчитывая что оба шага пройдут вместе.
А что если нет?
Представь классический поток:
1️⃣ Сохраняешь заказ в базе.
2️⃣ Отправляешь событие в Kafka или делаешь запрос в другую API, чтобы сообщить что заказ создан.
Где проблема?
👉 Если шаг 1 прошел, а шаг 2 упал:
База говорит заказ создан, но внешний сервис об этом не знает.
👉 Если шаг 2 прошел, а шаг 1 упал:
Ты опубликовал фантомное событие о том, чего нет.
Это и есть двойная запись.
И если думаешь что это тебя не коснется, просто подожди пока прод покажет тебе реальность.
Тут и появляется Transactional Outbox Pattern.
Что именно делает этот паттерн?🤔
Избавляет от необходимости писать в два места одновременно.
Превращает внешнюю запись в надежный процесс.
Идея простая, вот минимальный способ это реализовать:
1. Когда сохраняешь данные в базе (INSERT/UPDATE),
ты параллельно пишешь событие в отдельную таблицу, например outbox.
2. Оба INSERT выполняются в одной транзакции.
Если что-то падает, падает все.
Так достигается гарантированное консистентное состояние.
3. Затем отдельный процесс (poller или scheduler) читает эту таблицу и публикует реальное событие в Kafka, RabbitMQ или куда нужно.
4. Если публикация упала, ничего страшного.
Событие остается в таблице пока его не получится отправить.
С этим достаточно простым потоком ты получаешь консистентность без двойной записи.
Почему это так хорошо работает?
Потому что принимает неприятную правду:
Нельзя рассчитывать что два разных системы корректно обработают одну и ту же транзакцию.
❌ База умеет в транзакции.
❌ Kafka — нет.
❌ Rabbit — нет.
❌ Webhook тем более.
Поэтому решение не в том чтобы это «продавить», а в том чтобы адаптировать архитектуру к реальности:
Единственная запись, которой реально можно доверять — запись в твою базу.
Все внешнее (то что не хранится в твоей базе) должно выполняться позже, с ретраями, логами и прочим.
Но да, это не бесплатно.
Нужно:
—> Создать таблицу outbox.
—> Настроить ретраи.
—> Удалять обработанные события.
—> Мониторить poller (или любую другую реализацию).
—> Не допустить двойные вставки в outbox чтобы избежать дублей.
И ключевая мысль:
Цена Transactional Outbox намного ниже цены ручной починки рассинхрона между сервисами и системами.
А это в проде дороже золота.
👉 Java Portal
сохранить что-то в своей базе и параллельно опубликовать событие в другой системе, рассчитывая что оба шага пройдут вместе.
А что если нет?
Представь классический поток:
Где проблема?
База говорит заказ создан, но внешний сервис об этом не знает.
Ты опубликовал фантомное событие о том, чего нет.
Это и есть двойная запись.
И если думаешь что это тебя не коснется, просто подожди пока прод покажет тебе реальность.
Тут и появляется Transactional Outbox Pattern.
Что именно делает этот паттерн?
Избавляет от необходимости писать в два места одновременно.
Превращает внешнюю запись в надежный процесс.
Идея простая, вот минимальный способ это реализовать:
1. Когда сохраняешь данные в базе (INSERT/UPDATE),
ты параллельно пишешь событие в отдельную таблицу, например outbox.
2. Оба INSERT выполняются в одной транзакции.
Если что-то падает, падает все.
Так достигается гарантированное консистентное состояние.
3. Затем отдельный процесс (poller или scheduler) читает эту таблицу и публикует реальное событие в Kafka, RabbitMQ или куда нужно.
4. Если публикация упала, ничего страшного.
Событие остается в таблице пока его не получится отправить.
С этим достаточно простым потоком ты получаешь консистентность без двойной записи.
Почему это так хорошо работает?
Потому что принимает неприятную правду:
Нельзя рассчитывать что два разных системы корректно обработают одну и ту же транзакцию.
Поэтому решение не в том чтобы это «продавить», а в том чтобы адаптировать архитектуру к реальности:
Единственная запись, которой реально можно доверять — запись в твою базу.
Все внешнее (то что не хранится в твоей базе) должно выполняться позже, с ретраями, логами и прочим.
Но да, это не бесплатно.
Нужно:
—> Создать таблицу outbox.
—> Настроить ретраи.
—> Удалять обработанные события.
—> Мониторить poller (или любую другую реализацию).
—> Не допустить двойные вставки в outbox чтобы избежать дублей.
И ключевая мысль:
Цена Transactional Outbox намного ниже цены ручной починки рассинхрона между сервисами и системами.
А это в проде дороже золота.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤2
Совет по Java: старайся не шарить данные между потоками.
Используй неизменяемые объекты
Или строй взаимодействие потоков через сообщения, без прямой модификации общего состояния
С неизменяемыми объектами:
Обмен сообщениями:
👉 Java Portal
Используй неизменяемые объекты
Или строй взаимодействие потоков через сообщения, без прямой модификации общего состояния
С неизменяемыми объектами:
record Book(String title, int price) {} // Immutable
public class BookJob implements Runnable {
private final Book book;
... // constructor
@Override
public void run() {
System.out.println(book.title() + " " + book.price());
}
}Обмен сообщениями:
...
new Thread(() -> {
try {
queue.put("mess1");
} catch (InterruptedException e) {}
}).start();
...
new Thread(() -> {
try {
String mess = queue.take();
} catch (InterruptedException e) {}
}).start();
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🤔1
GitHub теперь в Telegram!
Самый прогерский канал, где за 10 минут ты научишься:
/ Пробив по фото и номеру в ТГ
// Как взломать вебку подруги
/// Мануал по OSINT разведке
Подписывайся, нас уже сотни тысяч: >@GitHub
Самый прогерский канал, где за 10 минут ты научишься:
/ Пробив по фото и номеру в ТГ
// Как взломать вебку подруги
/// Мануал по OSINT разведке
Подписывайся, нас уже сотни тысяч: >@GitHub
🤣6🤔1
image_2025-12-04_09-41-20.png
1.4 MB
Знали, что у EnableWebSecurity есть параметр debug, который включает отладку безопасности?
🤯
Это помогает разобраться, что вообще происходит во время разработки.
Но в проде такое включать нельзя.
👉 Java Portal
Это помогает разобраться, что вообще происходит во время разработки.
Но в проде такое включать нельзя.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6