Во многом его ценность определяет опыт тех, кто его разрабатывает и ведёт.
Об этом как раз новый пост Proglib Academy
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Proglib.academy | IT-курсы
Курс «ИИ для разработчиков» ведут практики из ведущих российских IT-компаний
В ближайшее время познакомим вас с каждым преподавателем. Программа курса — по ссылке
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱2
🐧 Магия Linux CLI
Процесс жрёт CPU на 100%, а top показывает только PID? Используйте strace -cp <PID>, и вы получите статистику системных вызовов — сразу видно, процесс висит на диске, сети или чём-то ещё.
🔹 Зачем это нужно
— Показывает, на какие системные вызовы тратится время: read, write, futex, epoll_wait.
— Если 90% времени в futex, то дедлок или контеншн на мьютексе.
— Если read/write, то проблема с I/O, проверяйте диск или NFS.
— Если connect/sendto, то приложение ждёт ответа от другого сервиса.
🔹 Как использовать
— Статистика вызовов процесса:
— Трассировка в реальном времени:
— Только файловые операции:
— С таймстемпами:
— Трейсить с дочерними процессами:
💡 strace замедляет процесс, поэтому на проде используйте strace -c (только статистика) вместо полной трассировки — оверхед минимальный.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
Процесс жрёт CPU на 100%, а top показывает только PID? Используйте strace -cp <PID>, и вы получите статистику системных вызовов — сразу видно, процесс висит на диске, сети или чём-то ещё.
🔹 Зачем это нужно
— Показывает, на какие системные вызовы тратится время: read, write, futex, epoll_wait.
— Если 90% времени в futex, то дедлок или контеншн на мьютексе.
— Если read/write, то проблема с I/O, проверяйте диск или NFS.
— Если connect/sendto, то приложение ждёт ответа от другого сервиса.
🔹 Как использовать
— Статистика вызовов процесса:
strace -cp <PID>— Трассировка в реальном времени:
strace -p <PID> -e trace=network— Только файловые операции:
strace -p <PID> -e trace=file— С таймстемпами:
strace -p <PID> -T -e trace=write— Трейсить с дочерними процессами:
strace -fp <PID>══════ Навигация ══════
Вакансии • Задачи • Собесы
#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
Собираем бэкенд-комьюнити на JVM Day
Бэкендеры, 29 августа в Москве пройдет хардкорная конференция. Ждут своих: Java-, Scala- и Kotlin-разработчиков, архитекторов и тимлидов.
Здесь выступят и расскажут:
— Андрей Кулешов — что нового в мире JVM за год.
— Сергей Петрелевич — разработка по Mechanical Sympathy.
— Александр Ланцов — Java после Loom: другие модели concurrency.
— Антон Курако — как бенчмарки вводят в заблуждение.
А вечером во дворе T-Space — посиделки, интерактивы и открытый микрофон с историями ошибок.
Мест мало, а цена билета будет расти.
Успевай зарегистрироваться
Бэкендеры, 29 августа в Москве пройдет хардкорная конференция. Ждут своих: Java-, Scala- и Kotlin-разработчиков, архитекторов и тимлидов.
Здесь выступят и расскажут:
— Андрей Кулешов — что нового в мире JVM за год.
— Сергей Петрелевич — разработка по Mechanical Sympathy.
— Александр Ланцов — Java после Loom: другие модели concurrency.
— Антон Курако — как бенчмарки вводят в заблуждение.
А вечером во дворе T-Space — посиделки, интерактивы и открытый микрофон с историями ошибок.
Мест мало, а цена билета будет расти.
Успевай зарегистрироваться
❤🔥5
Если стандартных возможностей IDE для контроля покрытия тестами уже недостаточно, стоит обратить внимание на JaCoCo. Этот инструмент выходит за рамки базового функционала.
В отличие от встроенных средств IntelliJ IDEA, которые отлично справляются с локальной разработкой, JaCoCo предлагает комплексный подход к анализу покрытия:
JaCoCo идеален для проектов, где важна прозрачность метрик тестирования и автоматизация проверок качества кода на всех этапах разработки.
🔹 Курс «Алгоритмы и структуры данных»
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤3🔥1👏1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁21👍3👏1
Ниже — бесплатный вебинар о том, как этого избежать ⚠️
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Proglib.academy | IT-курсы
Где-то есть тесты, где-то их забыли. Где-то агент следует архитектуре проекта, где-то предлагает решение, которое с ней не сочетается.
Завтра покажем, как передать AI инженерный контекст команды и не превратить его внедрение в ещё один источник хаоса.
Бесплатно. 60 минут доклада + 30 минут вопросов.
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱2❤1
Один из недооценённых скиллов в разработке — это умение провести правильную границу между сервисами. Большинство «распределённых монолитов», которые мы встречаем в продакшене, рождаются именно здесь.
Разобрали тему — держи шпаргалку 👇
🔹 Что такое Service Boundary
Это контракт на три вещи:
— за что сервис отвечает;
— какими данными он владеет;
— как он общается с соседями.
Представь компанию: HR не лезет в финансы, а склад не занимается зарплатами. Так же должны работать твои сервисы.
🔹 4 принципа, которые работают
1. Business Capability First
Режь по бизнес-функциям, а не по техническим слоям. OrderService, PaymentService, UserService, потому что именно так бизнес думает о системе.
2. Single Responsibility
Один сервис — одна ответственность. Если в описании сервиса есть союз и, это уже тревожный звоночек 🚨
3. Data Ownership
У каждого сервиса своя БД. Без исключений. Shared database = shared pain.
4. Loose Coupling
Только API, никакого прямого доступа к чужим таблицам.
🔹 Классический антипаттерн
// ❌ Бизнес-логика смешана в одном сервисе
@Service
public class BadOrderService {
public String processOrderAndPayment(int id) {
String order = orderRepository.findById(id)
.orElse("Order not found");
String paymentStatus = "Payment Successful"; // 🚨 чужая ответственность
return order + " | " + paymentStatus;
}
}
Выглядит безобидно, пока не нужно масштабировать платежи отдельно, сменить платёжного провайдера или добавить retry-логику только для оплаты. Тут и начнутся реальные проблемы.
🔹 Советы из практики
→ Начни с монолита. Не дроби систему заранее. Сначала пойми домен, потом режь по швам.
→ Следи за chatty communication. Если сервис делает 10 вызовов к соседям на каждый запрос, граница явно проведена не там.
→ Изучи DDD. Bounded Context из Domain-Driven Design это лучший инструмент для поиска правильных границ. Инвестиция окупается быстро
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥2❤1❤🔥1👾1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁20👍4💯4🔥1🤩1
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Proglib.academy | IT-курсы
Агент работает только с тем контекстом, который ему дали. Если документация неполная или устарела, он начинает додумывать — отсюда появляется неверный код.
Также разберём, как выбирать модель под задачу: Claude, DeepSeek, Qwen и другие
Впереди 7 недель работы со своим репозиторием. Вебинары проходят вживую и остаются в записи.
Стартуем 31 августа. До конца июля можно присоединиться по ранней цене, а доступ к материалам останется бессрочным
Please open Telegram to view this post
VIEW IN TELEGRAM
🎉1🥱1
Если вы перешли на virtual threads, но продолжаете использовать ThreadLocal, то у вас проблема, которая пока просто не выстрелила.
ThreadLocal хранит данные в ThreadLocalMap — по одной map на каждый тред. Когда тредов было 200 в пуле, это было терпимо. Когда виртуальных тредов сотни тысяч, каждый несёт свою map, и heap начинает гореть. Плюс мутабельность: ThreadLocal.set() в глубоком call stack — это неявное состояние, которое легко забыть почистить через .remove(). В try-finally это работает до первого необработанного исключения.
Java 21 предлагает замену — ScopedValue.
🔹 Ключевые отличия
ScopedValue.where(TENANT_ID, tenant).run(() -> { ... }) — значение привязано к scope, а не к треду. Вышли из блока и значение автоматически недоступно. Никакого .remove(), никакого «забыл почистить».
Иммутабельность по дизайну. Нельзя сделать .set(). Если нужно другое значение, создаёте вложенный scope. Это убирает целый класс багов с «протеканием» контекста между запросами.
Легковесность. Внутри массив вместо HashMap. При масштабе в 100k+ тредов разница в потреблении памяти ощутимая.
Работает в связке со StructuredTaskScope: дочерние виртуальные треды автоматически наследуют scoped values родителя. Не нужно вручную пробрасывать контекст.
Практический вывод: если вы мигрируете на virtual threads, аудит ThreadLocal — обязательный шаг. ScopedValue пока preview, но API стабилизируется, и направление очевидно. Как минимум стоит уже сейчас заменить ThreadLocal на ReentrantLock-protected shared state или ScopedValue там, где передаёте tenant ID, request context, trace ID и подобные per-request данные.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤1🔥1🎉1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁24💯3👍1
🧹 Git-команда, которая спасёт ваш репозиторий от мусора
Проблема: вы удалили ветки, сделали git reset, отменили мёржи, но репозиторий почему-то весит всё больше. git clone на новом месте занимает вечность. Куда уходит место?
Дело в том, что Git — барахольщик. Он хранит все объекты: старые блобы, недостижимые коммиты, забытые stash'ы. Даже то, что вам давно не нужно.
💡 Решение: git gc и его старший брат git gc --aggressive
Рассмотрим все все возможности git gc.
1️⃣ Сколько мусора накопилось
Обратите внимание на size-pack — это реальный вес вашего репо.
2️⃣ Самые тяжёлые объекты в истории
Часто находятся артефакты сборки, дампы БД или случайно закоммиченные .jar на 200 МБ 😬
3️⃣ Запустите агрессивную сборку мусора
--aggressive заставляет Git перепаковать объекты с нуля, а --prune=now удаляет недостижимые объекты немедленно, не дожидаясь дефолтных двух недель.
4️⃣ Сравните результат
На живых проектах с историей в 2+ года разница бывает в разы.
⚠️ --prune=now безвозвратно удалит объекты, на которые нет ссылок. Если вы планировали восстановить что-то через git reflog — сделайте это до запуска.
💡 Бонус для CI/CD: если ваш пайплайн клонирует репо каждый раз — добавьте git gc в ночной cron. Экономия трафика и времени сборки может приятно удивить.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
Проблема: вы удалили ветки, сделали git reset, отменили мёржи, но репозиторий почему-то весит всё больше. git clone на новом месте занимает вечность. Куда уходит место?
Дело в том, что Git — барахольщик. Он хранит все объекты: старые блобы, недостижимые коммиты, забытые stash'ы. Даже то, что вам давно не нужно.
Рассмотрим все все возможности git gc.
git count-objects -vH
Обратите внимание на size-pack — это реальный вес вашего репо.
git rev-list --objects --all \
| git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
| awk '/^blob/ {print $3, $4}' \
| sort -rn \
| head -10
Часто находятся артефакты сборки, дампы БД или случайно закоммиченные .jar на 200 МБ 😬
git gc --aggressive --prune=now
--aggressive заставляет Git перепаковать объекты с нуля, а --prune=now удаляет недостижимые объекты немедленно, не дожидаясь дефолтных двух недель.
git count-objects -vH
На живых проектах с историей в 2+ года разница бывает в разы.
💡 Бонус для CI/CD: если ваш пайплайн клонирует репо каждый раз — добавьте git gc в ночной cron. Экономия трафика и времени сборки может приятно удивить.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥4❤1
Куда на самом деле уходят токены во время агентного кодинга? ⚡️
Forwarded from Proglib.academy | IT-курсы
В итоге станет понятнее, сколько ресурсов выделять на запуск, когда его останавливать и в какой момент лучше изменить подход🔍
До 31 июля курс можно купить со скидкой, а все материалы останутся в бессрочном доступе.
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱2❤1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁11👍1🔥1
Надоели моки репозиториев, которые не ловят реальные SQL-баги?
Настраиваем Testcontainers, запускаем настоящий PostgreSQL прямо в тестах, без внешних зависимостей.
⚙️ Шаг 1 — Зависимости (Maven)
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.19.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.19.7</version>
<scope>test</scope>
</dependency>
> Для Gradle:
testImplementation "org.testcontainers:postgresql:1.19.7"🐳 Шаг 2 — Базовый тест
@SpringBootTest
@Testcontainers
class UserRepositoryTest {
@Container
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:16-alpine");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Autowired
UserRepository userRepository;
@Test
void shouldSaveAndFindUser() {
var user = new User("alice@example.com");
userRepository.save(user);
var found = userRepository.findByEmail("alice@example.com");
assertThat(found).isPresent();
}
}
Всё. Spring подхватит datasource-проперти через @DynamicPropertySource — Liquibase/Flyway накатятся сами.
⚡️ Шаг 3 — Ускоряем: переиспользуем контейнер
По умолчанию контейнер поднимается на каждый тест-класс.
Чтобы один инстанс жил на весь прогон — выносим в абстрактный класс:
@SpringBootTest
@Testcontainers
public abstract class BaseIntegrationTest {
@Container
static final PostgreSQLContainer<?> POSTGRES =
new PostgreSQLContainer<>("postgres:16-alpine")
.withReuse(true); // ← ключевая строка
@DynamicPropertySource
static void props(DynamicPropertyRegistry r) {
r.add("spring.datasource.url", POSTGRES::getJdbcUrl);
r.add("spring.datasource.username", POSTGRES::getUsername);
r.add("spring.datasource.password", POSTGRES::getPassword);
}
}
Наследуй в каждом интеграционном тесте — контейнер поднимется один раз.
🔍 Шаг 4 — Отладка: смотрим логи контейнера
POSTGRES.followOutput(new Slf4jLogConsumer(
LoggerFactory.getLogger("postgres-container")
));
Добавь до старта контейнера и все PostgreSQL логи пойдут в твой аппендер.
🔖 Сохраняй пост для следующего проекта.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2🔥2