Обновить
256K+

Java *

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

203,6
Рейтинг
Сначала показывать
Порог рейтинга

Автоимпорт при копировании кода — штука настолько приятная и удобная, что без неё уже невозможно представить работу в IDE. 

Мы пошли дальше и вслед за умным импортом во время набора кода сделали автоматическую инжекцию бинов при копировании кода!

Теперь при копировании кода Amplicode автоматически добавляет нужную инжекцию бинов. С учётом контекста, @Primary, @Qualifier, дженериков, @Bean-методов, Java и Kotlin — без ручной возни после вставки.

Будет доступно всем пользователям Amplicode, без подписки.

Теги:
Всего голосов 5: ↑4 и ↓1+3
Комментарии0

Как оставаться релевантным на рынке QA/AQA/SDET в 2026: опыт, харды, софты, ответы

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

Часто это выглядит так: человек активно откликается, ходит на собеседования, делает тестовые задания, общается с рекрутерами.
А на выходе получает либо отказы без конкретных причин, либо формулировки вроде «вы хороший специалист, но нам нужен немного другой профиль».

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

Я регулярно общаюсь с QA, AQA и SDET, которые находятся в активном поиске, и сам продолжаю проходить собеседования, чтобы понимать, как именно сейчас устроен процесс найма.
И вот что я понял из всех историй: сегодня выигрывает не самый наглый кандидат (как было раньше), а тот, кто хорошо понимает свой опыт и умеет его объяснять.

Что изменилось

Еще один-два года назад часто работала простая схема: уверенное резюме плюс нормальная подача давали высокую вероятность оффера.
Во многих компаниях в детали погружались поверхностно, опыт оценивали в общих чертах, а неточности прощались, если кандидат выглядел уверенно.

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

Это не «заговор рынка», а естественная фильтрация. Когда выбор кандидатов большой, требования становятся строже.

Почему в этом есть плюсы

Жесткий рынок хорошо отсеивает слабые места. Причем чаще всего самые базовые.

На собеседованиях у ребят регулярно всплывают одни и те же проблемы:

  • человек говорит, что строил фреймворк, но не может связно объяснить архитектуру;

  • упоминает автотесты, но не понимает, почему был выбран конкретный стек;

  • рассказывает про CI, но путается в вопросах стабильности;

  • заявляет ответственность за качество, но не может описать процессы и зоны ответственности.

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

Как сейчас смотрят на опыт

На интервью все меньше внимания уделяется формальным строчкам в резюме и все больше мышлению.

Интервьюеру важно понять:

  1. Почему было принято именно такое решение;

  2. Какие были трудности;

  3. Как проблемы диагностировали;

  4. Какие выводы сделали.

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

Поэтому сейчас важна не красивая история, а осознанное понимание своего опыта.

Что с этим делать

Минимальный практический набор:

  1. Разложить свой опыт по зонам - архитектура, API, UI, CI/CD, процессы, инциденты.

  2. Подготовить ответы в формате «проблема - решение - результат - выводы». (Для шарящих - по STAR)

  3. Прогнать опыт через уточняющие вопросы и проверить, где ответы выглядят слабо или непоследовательно.

  4. Упаковать резюме как набор конкретных ответов - что улучшал, что оптимизировал, за что отвечал + быть готовым это подтвердить.

Вывод

Рынок действительно стал сложнее.
Но именно поэтому он стал более комфортным для тех, кто держит фокус на релевантности, понимает свой опыт и готовится к проверке.

Если относиться к поиску работы как к инженерной задаче, жесткий рынок перестает быть проблемой и становится рабочей средой.

Ну а всем нуждающимся желаю скорее обрести себя на сегодняшнем рынке! Готов подискутировать на смежные темы в комментариях)

Теги:
Всего голосов 3: ↑0 и ↓3-3
Комментарии0

О поддержке opensource - как показателе безопасности

Случались ситуации, когда компании использовали open source, который перестал развиваться. И в этом open source находили уязвимости. Итог: компаниям сложно ликвидировать уязвимости в используемом open source. По этой причине рождались предложения: дабы не попасть в такую ситуацию - при выборе open source проверять, что проект ещё поддерживается. Мысль здравая. Но, и тут могут быть нюансы. Пример - проект JasperReports (для Java). Судя по репозиторию - проект поддерживается. 16 сентября 2025 была опубликована информация об уязвимости в проекте (критического уровня: 9.8 по шкале CVSS v3.1 - CVE-2025-10492). А 19 сентября 2025 разработчик сообщил, что фикс выйдет только для коммерческой версии.

Теги:
Всего голосов 2: ↑1 и ↓1+2
Комментарии0

Автостопом по LTS: основные изменения при переходе с 8 на 11 Java

Совсем недавно мы выпускали статью про нововведения в Java 25. И один из комментаторов сказал, что ему было бы интересно прочитать от нас цикл статей, в которых рассказано и показано, как менялась Java от LTS к LTS, начиная с Java 8.

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

Теги:
Всего голосов 4: ↑3 и ↓1+3
Комментарии0

Что нового появилось в PVS-Studio в 2025 году

Новый 2026 год уже вовсю идёт, и мы решили оглянуться назад и вспомнить, что интересного появилось в PVS-Studio за богатый на изменения 2025 год:

  • десятки новых диагностических правил, включая проверки, ориентированные на безопасность;

  • обновления интеграций в популярные IDE, CI/CD-системы, ASOC и сборочные системы;

  • улучшения анализа;

  • расширенная поддержка стандартов.

Всё это и многое другое описано в новой статье в нашем блоге.

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

При написании интеграционных тестов для Spring Boot приложения часто возникает проблема, что разработчики бездумно добавляют аннотации @MockBean, @SpyBean, @DirtiesContext или переопределяют прямо в тестовом классе различные property. Всё это приводит к изменению Spring Context, невозможности использовать закэшированный контекст и следовательно созданию нового. Часто создание нового контекста это длительная операция.

Существуют инструменты по отслеживанию этих процессов. Самым простым способом увидеть количество контекстов и количество попаданий в кэш является добавление логирования либо через свойство logging.level.org.springframework.test.context.cache=DEBUG либо настройкой вашего логгера.

Один известный автор статей про тестирование на Java / Spring Boot, Philip Riecks (со товарищи), создал инструмент с открытым исходным кодом Spring Test Profiler при помощи которого можно получить html отчёт о поднимаемых контекстах во время тестов, о количестве и типе бинов в этих контекстах. На Хабре есть перевод его статьи в сообществе Spring АйО.

У нас на проекте стал вопрос, как нам показать разработчикам, что их тест порождает новый Спринг Контекст. Мы решили считать контексты в тестах и при превышении ожидаемого количества падать. Это "руинит" сборку и CI/CD пайплайн.
Для этого мы добавили реализацию интерфейса ContextCustomizer

class LimitingSpringContextCustomizer implements ContextCustomizer {

    private static final AtomicInteger CONTEXT_COUNTER = new AtomicInteger();
    private static final int EXPECTED_SPRING_TEST_CONTEXT_COUNT = 16;

    @Override
    public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
        int numberOfContexts = CONTEXT_COUNTER.incrementAndGet();
        log.info("Number of Spring Test Contexts: {}/{}", numberOfContexts, EXPECTED_SPRING_TEST_CONTEXT_COUNT);
        Assert.state(numberOfContexts <= EXPECTED_SPRING_TEST_CONTEXT_COUNT,
                () -> "Number of test contexts exceeds configured maximum: " + EXPECTED_SPRING_TEST_CONTEXT_COUNT);
    }

    @Override
    public boolean equals(Object obj) {
        return (obj != null) && (getClass() == obj.getClass());
    }

    @Override
    public int hashCode() {
        return getClass().hashCode();
    }
}

Здесь, согласно документации интерфейса ContextCustomizer необходимо корректно переопределить методы equals и hashCode.

WARNING: implementations must implement correct equals and hashCode methods since customizers form part of the MergedContextConfiguration which is used as a cache key.

Далее добавляем фабрику.

class LimitingSpringContextCustomizerFactory implements ContextCustomizerFactory {

    @Override
    public ContextCustomizer createContextCustomizer(Class<?> testClass,
                                                     List<ContextConfigurationAttributes> configAttributes) {
        return new LimitingSpringContextCustomizer();
    }
}

Затем регистрируем эту фабрику при помощи spring.factories чтобы она применялась ко всем тестам.
Для этого создаём в тестовых ресурсах файл по пути src/test/resources/META-INF/spring.factories со следующим содержимым

org.springframework.test.context.ContextCustomizerFactory=\  
com.mycompany.app.support.spring.LimitingSpringContextCustomizerFactory

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

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

Теги:
Всего голосов 6: ↑5 и ↓1+4
Комментарии0

Как не потерять сервер в Minecraft из-за опасных модов

Уверен, что многие владельцы Minecraft-проектов сталкивались с игроками, которые хотели взломать сервер и выдать себе права администратора. Я понимаю, что подобное случается не только в играх, и из научного интереса изучаю, как и почему это происходит.

В этой статье мы рассмотрим CVE, найденную в моде Integrated Scripting.

Теги:
Всего голосов 6: ↑4 и ↓2+3
Комментарии0

Kotlin и Hyperskill: как я искал курс и что получил в итоге.

Когда я решил изучать Kotlin, ожидал, что найти хороший курс будет просто: язык популярный, используется в Android и бэкенде, вокруг много материалов. Искал менторов и упирался в людей которые знаю java и вроде как используют в работе Kotlin. Это одновременно пугало и заинтересовывало, я решил поступить как мне казалось правильным, найти готовый курс  — особенно если хочется не “смотреть видео”, а именно учиться через практику и задачи.

Я перепробовал разные форматы обучения (платные и бесплатные), поэтому в этот раз подход был простой: найти платформу, где есть структурированная программа и много практики. В итоге я добрался до Hyperskill (hyperskill.org). Это не реклама — просто личный опыт, кому-то он может сэкономить время.

Как я пришёл к ресурсу.

Изначально искал курсы по Kotlin на привычных площадках. На Stepik в тот момент не нашёл того, что мне подходило по структуре (возможно, сейчас ситуация лучше). Видео-курсы на крупных “известных сайтах” сознательно не рассматривал: мне удобнее формат “прочитал → сделал → получил проверку”.

Дальше — обычный путь через поисковик и сравнение нескольких платформ. Из того, что выглядело цельно и практично, больше всего зацепил Hyperskill. Отдельно сыграло роль то, что платформа связана с JetBra…. (то есть ребята явно понимают, как устроена экосистема вокруг Kotlin и IDE).После регистрации быстро становится понятно: платформа активно ведёт к подписке.Раньше в сети встречались статьи про возможность оформить бесплатную подписку на полгода, но это устаревшая информация — сейчас такой опции нет (по крайней мере, в том виде, в каком её описывают старые гайды).

При этом у Hyperskill есть бесплатный режим, и я проходил курс именно так.

Что я проходил: Introduction to Kotlin.

На платформе несколько треков по Kotlin, я начал с Introduction to Kotlin. По ощущениям, это “введение с практикой”:

  • около 9 учебных проектов

  • порядка 60–70 тем

  • внутри тем — задачи/тренажёры с автоматической проверкой

В целом структура понравилась: материал подаётся дозировано, и почти сразу закрепляется практикой. Похожая на Степик.

Система “кристаллов” и лимиты.

Самая спорная часть бесплатного режима — ограничения на попытки.

У Hyperskill есть внутренняя валюта (“кристаллы”): ошибаешься в заданиях — кристаллы списываются. Когда кристаллы заканчиваются, обучение может блокироваться на 12–24 часа. Да, кристаллы можно зарабатывать активностью и выполнением некоторых задач, но при активном обучении и регулярных ошибках (что нормально) этого может не хватать.

Подписка проблему снимает, но именно этот момент сильнее всего влияет на комфорт обучения в бесплатном режиме.

Проекты: что внутри и зачем это полезно.

Сильная сторона Hyperskill — проекты. Они не выглядят как “игрушки ради галочки”, а позволяют постепенно потрогать основные конструкции языка.

Из того, что запомнилось:

  • “Сапёр”

  • “Крестики-нолики”

  • “Чат-бот”

  • “Кофемашина”

Например, в проекте “кофемашина” уже нормально используются циклы, классы и базовые элементы ООП. В таком формате проще понять, “зачем оно нужно”, чем на изолированных задачках.

Минус: часть проектов закрыта платной подпиской, и это немного обидно — именно проекты дают максимальную пользу и ощущение прогресса.

Проверка решений: не всегда понятно, почему “не принято”

Ещё один недостаток — качество обратной связи в тестах. Иногда тесты “падают” так, что ты видишь только факт ошибки, но не понимаешь причину: что именно ожидалось, на каком кейсе сломалось, где расхождение.Часть проектов проверяется через IntelliJ IDEA, и здесь иногда всплывают технические нюансы: несовпадение версий, необходимость обновить IDE или компилятор, странные падения на конкретном проекте.

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

Итоги:

  • бесплатный режим может раздражать лимитами на ошибки (кристаллы и блокировки)

  • часть контента (включая проекты) закрыта подпиской

  • обратная связь тестов местами недостаточно информативная

    Если готовы, то вперед!

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

Работаем из Java с устройствами с serial-интерфейсом (COM и USB) без JNI — по TCP.

Раньше пользовались rxtx, затем jssc. После очередных крэшей JVM в коде нативных библиотек решил не выбирать замену, а отказаться от них полностью.

В качестве прокси serial-TCP можно взять ser2net или поэкспериментировать с socat, но я запилил свое простое (Rust, mio), под конкретную задачу:

  1. Запускается из основного приложения, свой процесс для каждого устройства

  2. Конфигурация через аргументы запуска и переменные окружения

  3. Завершает работу при отсутствии или отключении устройства (для USB), отключении или отсутствия подключения TCP-клиента

В качестве TCP-клиента Netty. Для интеграции с легаси данные читаются в кольцевой буфер ( OneToOneRingBuffer из agrona), а оттуда уже используются по месту в удобное время.

За счет неблокирующего чтения и использования epoll в mio и Netty минимальные задержки, моментальное оповещение о наличии данных (без Thread.sleep) и об отключении USB-устройства.

Задержки настолько меньше, что пришлось адаптировать кривой код, который не был готов к тому, что драйвер железного serial-порта в Linux отдает данные порциями по 8 байт. Решилось реализацией ByteToMessageDecoder, где возможно, а где нет — буферизацией на стороне прокси и отправкой по таймеру.

Для надежной работы уменьшаем и выравниваем буферы записи, пишем через writeAndFlush с ожиданием завершения, чтобы устройство успевало читать.

Бонус: можно работать с устройством, подключенным к другому системному блоку (например, для разработки) и использовать TCP-эмуляторы вместо реальных устройств без изменения кода интеграции.

Теги:
Всего голосов 2: ↑2 и ↓0+2
Комментарии0

Новогодняя аномалия в данных мониторинга.

С Новым Годом!
С Новым Годом!

Воспроизвести достаточно просто

  • Скачать и установить Dimension-UI.

  • Развернуть локально PostgreSQL.

  • Запустить в Dimension-UI мониторинг данных PostgreSQL с помощью запроса с интервалом 3 сек.

WITH params AS (
    SELECT 
        15 AS total_frames,
        20 AS canvas_height,
        3  AS frame_duration_sec
),
animation_state AS (
    SELECT 
        (CAST(EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) AS INTEGER) / frame_duration_sec) % total_frames AS frame_idx
    FROM params
),
tree_definition AS (
    SELECT 
        frame_id, 
        y_pos,
        CASE
            -- ═══════════════════════════════════════
            -- ЗВЕЗДА на верхушке
            -- ═══════════════════════════════════════
            WHEN y_pos = 20 AND frame_id = 7 THEN '*'
            
            -- ═══════════════════════════════════════
            -- ВЕРХУШКА елки (острая)
            -- ═══════════════════════════════════════
            WHEN y_pos = 19 AND frame_id = 7 THEN 'G'
            
            -- ═══════════════════════════════════════
            -- ЯРУС 1 (y=16-18) — расширяется книзу
            -- ═══════════════════════════════════════
            WHEN y_pos = 18 AND frame_id BETWEEN 6 AND 8 THEN 'G'
            WHEN y_pos = 17 AND frame_id BETWEEN 5 AND 9 THEN 'G'
            WHEN y_pos = 16 AND frame_id BETWEEN 4 AND 10 THEN 'G'  -- широкий низ яруса
            
            -- Сужение перед ярусом 2
            WHEN y_pos = 15 AND frame_id BETWEEN 5 AND 9 THEN 'G'
            
            -- ═══════════════════════════════════════
            -- ЯРУС 2 (y=12-14)
            -- ═══════════════════════════════════════
            WHEN y_pos = 14 AND frame_id BETWEEN 4 AND 10 THEN 'G'
            WHEN y_pos = 13 AND frame_id BETWEEN 3 AND 11 THEN 'G'
            WHEN y_pos = 12 AND frame_id BETWEEN 2 AND 12 THEN 'G'  -- широкий низ яруса
            
            -- Сужение перед ярусом 3
            WHEN y_pos = 11 AND frame_id BETWEEN 4 AND 10 THEN 'G'
            
            -- ═══════════════════════════════════════
            -- ЯРУС 3 (y=8-10)
            -- ═══════════════════════════════════════
            WHEN y_pos = 10 AND frame_id BETWEEN 3 AND 11 THEN 'G'
            WHEN y_pos = 9  AND frame_id BETWEEN 2 AND 12 THEN 'G'
            WHEN y_pos = 8  AND frame_id BETWEEN 1 AND 13 THEN 'G'  -- широкий низ яруса
            
            -- Сужение перед ярусом 4
            WHEN y_pos = 7 AND frame_id BETWEEN 3 AND 11 THEN 'G'
            
            -- ═══════════════════════════════════════
            -- ЯРУС 4 — нижний, самый широкий (y=4-6)
            -- ═══════════════════════════════════════
            WHEN y_pos = 6 AND frame_id BETWEEN 2 AND 12 THEN 'G'
            WHEN y_pos = 5 AND frame_id BETWEEN 1 AND 13 THEN 'G'
            WHEN y_pos = 4 AND frame_id BETWEEN 0 AND 14 THEN 'G'  -- во всю ширину!
            
            -- ═══════════════════════════════════════
            -- СТВОЛ (y=1-3)
            -- ═══════════════════════════════════════
            WHEN y_pos BETWEEN 1 AND 3 AND frame_id BETWEEN 6 AND 8 THEN 'T'
            
            -- Всё остальное — фон
            ELSE 'S'
        END AS pixel_char
    FROM generate_series(0, 14) AS frame(frame_id)
    CROSS JOIN generate_series(1, 20) AS y(y_pos)
),
pixel_data AS (
    SELECT td.*
    FROM tree_definition td
    JOIN animation_state ast ON td.frame_id = ast.frame_idx
),
layers_logic AS (
    SELECT 
        y_pos,
        pixel_char,
        MAX(CASE WHEN pixel_char IN ('T', 'G', '*') THEN y_pos ELSE 0 END) OVER () as max_obj_height
    FROM pixel_data
)
SELECT 
    CURRENT_TIMESTAMP as dt,
    CASE 
        WHEN pixel_char = 'T' THEN '4_Trunk'
        WHEN pixel_char = 'G' THEN '3_Tree'
        WHEN pixel_char = '*' THEN '2_Star'
        WHEN pixel_char = 'S' THEN 
            CASE WHEN y_pos > max_obj_height 
    

p.s. Данные по запросу любезно предоставлены Claude Opus 4.5.

Теги:
Всего голосов 5: ↑3 и ↓2+3
Комментарии1

StingrayTV Alice стал ещё лучше - теперь оно уже почти production-ready, с кучей фиксов и улучшений.

В частности:

  1. Пофиксил пару специфичных моментов, связанные с получением информации о текущем телеканале (они идут как SSE, поэтому пришлось воспользоваться WebClient для работы с SSE-запросами) - это позволило наконец-то избавиться от торможения запросов к ресиверу, что в свою очередь позволило наконец-то довести приложение до полностью работоспособного состояния.

  2. Теперь StingrayTV Alice использует bridge-сеть Docker'а, а для работы с mDNS теперь используется ретранслятор, соединяющий контейнер и mDNS-сеть вместе через выделенный контейнер. Это позволило окончательно разграничить сетевой стек в контейнерах, и улучшить общую безопасность.

Приложение уже окончательно протестировано на моём ресивере, осталось только совсем чуть-чуть, и скоро выйдет первая бета.

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

Приглашаем на бесплатный вебинар «За кулисами Java: Секреты памяти, которые разгонят ваше приложение».

🕓 Когда: 25 декабря, 16:00–17:00 (Мск)

👨‍🎓 Спикер: Прощаев Сергей — эксперт в области Java.

Содержание:

✔️ Архитектура памяти в JVM: тонкости работы стека и кучи (Java 8+).

✔️ Фундаментальные проблемы параллелизма: видимость, упорядоченность, атомарность.

✔️ Сравнительный анализ инструментов синхронизации: synchronized, volatile, атомарные классы из java.util.concurrent.atomic.

✔️ Практические рекомендации по выбору инструментов для оптимальной производительности и надёжности.

Вы узнаете:

➕ Как проектировать стабильные многопоточные системы, предсказуемо работающие под нагрузкой.

➕ Как избегать распространённых ошибок, связанных с управлением памятью.

➕ Какие best practices применяют в отраслях с жёсткими требованиями к отказоустойчивости.

Для участия желательны базовые знания Java на уровне Middle и понимание основ многопоточности.

👉 Записаться

Теги:
Рейтинг0
Комментарии0

Катаемся по полям в поисках потенциальных уязвимостей

Мы продолжаем писать про то, как развивается наш механизм анализа помеченных данных в Java анализаторе PVS-Studio. В новой статье вы сможете узнать, как мы учитывали поток данных, проходящий через поля, чтобы научиться искать более неочевидные потенциальные уязвимости.

Эта статья является логическим продолжением нашего цикла про поиск потенциальных уязвимостей в исходном коде ПО. В случае, если вам интересно, с предыдущими частями можно ознакомиться здесь:

  1. Поиск потенциальных уязвимостей в коде, часть 1: теория.

  2. Поиск потенциальных уязвимостей в коде, часть 2: практика.

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

Теги:
Всего голосов 3: ↑3 и ↓0+6
Комментарии0

Ближайшие события

Усыпальница Java

Java обычно воспринимают как "тихую гавань" стабильности и обратной совместимости. Но на самом деле внутри неё постоянно кипит жизнь: язык и платформа меняются, обрастают новыми API и возможностями, а старые решения постепенно отправляются на покой в виртуальную усыпальницу.

В новой статье мы разберёмся, чем именно наполняется эта усыпальница и почему. Поговорим о legacy-коллекциях Java, финализаторах, Nashorn, SecurityManager и легендарном Unsafe. Какие задачи они решали? Какие архитектурные и эксплуатационные проблемы породили? И, конечно, разберём, какие современные альтернативы пришли им на смену.

Теги:
Всего голосов 6: ↑4 и ↓2+5
Комментарии4

Баги на всех языках мира. Проверка LanguageTool

Всем привет! Hello, everyone! Hallo zusammen! Hola a tothom! مرحباً بالجميع!

В нашем блоге мы часто говорим про статический анализ, линтеры и подобные инструменты. Но на этот раз мы нашли их довольно интересного представителя! LanguageTool — это многоязычная программа проверки орфографии, стилистики и грамматики, которая помогает исправлять и перефразировать тексты.

В новой статье заглянем в её код и посмотрим на интересные вещи, которые нашёл в нём статический анализатор кода PVS-Studio: от утечек ресурсов и логических противоречий в условиях до дублирующихся ключей в хеш-таблицах, избыточных проверок и мёртвого кода.

Теги:
Всего голосов 3: ↑3 и ↓0+4
Комментарии0

Многие используют подход API First в проектировании систем, но зачастую даже не задумываются, что порождают таким образом сервисы с анемичными доменными моделями, проектируя по сути REST-обертки над базой данных с отсутствием какой-либо бизнес-логики.

API First и Богатая доменная модель не являются взаимоисключающими понятиями, если правильно выстроить процесс и архитектуру.

Главная проблема: API First фокусируется на контрактах внешнего мира, что часто приводит к созданию DTO/Model классов, которые являются чистыми структурами данных без поведения (анемичная модель).

API First — это про контракты, а не про реализацию. Не позволяйте инструментам кодогенерации диктовать структуру вашей доменной модели!

Правильный workflow:

1. API Design First: Создайте/обновите OpenAPI спецификацию.

2. Генерация DTO: Сгенерируйте или создайте классы для API‑контрактов.

3. Projection First: Спроектируйте доменную модель независимо от DTO, фокусируясь на поведении и инвариантах.

4. Создание Mapping Layer: Напишите преобразователи между DTO и Domain Objects.

5. Реализация Application Service: Тонкий слой, который координирует работу домена.

Стек технологий, который помогает:

MapStruct: Для автоматизации маппинга между DTO и Domain
JUnit 5: Для тестирования доменной логики
OpenAPI Generator: Для автоматической генерации DTO из спецификации
ArchUnit: Для проверки архитектурных правил (например, запрет на анемичные модели)

// ArchUnit тест, проверяющий, что в доменных классах есть поведение
@ArchTest
static final ArchRule domain_models_should_have_business_methods = 
    classes()
        .that().resideInPackage("..domain..")
        .and().areAnnotatedWith(Entity.class)
        .should().containAnyMethodsThat(
            DescribedPredicate.describe(
                "have business methods", 
                method -> !method.getName().startsWith("get") && 
                         !method.getName().startsWith("set")
            )
        );
Теги:
Всего голосов 1: ↑0 и ↓1-1
Комментарии0

👉 Декабрь в разгаре, и у нас есть вакансии присоединяйтесь к SSP SOFT 💻


Говорят, что в декабре никто не нанимает, но это не про нас! Приглашаем опытных специалистов присоединиться к команде SSP SOFT 🌐

✨ У нас в SSP SOFT — проекты, которые удивлят своей сложностью, а затем станут точками роста.
✨ С первого дня вы не одни: за вами закрепляется наставник, который помогает входить в работу спокойно и без лишнего напряжения.
✨ Карьерный скачок здесь реален: наш Проектный офис — это не просто управление, а среда, которая ускоряет профессиональное развитие.
✨ Вы сами выбираете формат: работайте удаленно, приходите в офис в Москве (ЦАО) или в Томске — или комбинируйте (по согласованию с тимлидом).
✨ Мы не пропагандируем культ переработок — рабочие процессы настроены, а личное время и забота о здоровье уважаются.

Бонусы тоже есть:
🎁 ДМС (включая стоматологию) для штатных сотрудников
🎁 обучение за счет компании
🎁 бонусные программы
🎁 общие ивенты — от онлайн-квизов до выездных сборов

📢 Вот кого мы ищем в декабре (Подробности о вакансиях читай на ХХ.ру):

  • Python developer (LLM)

  • С# Разработчик (интеграции с Lekton)

  • Администратор второй линии поддержки/Devops специалист

  • Аналитик- консультант 1С

  • Аналитик 1С (Middle)

  • Системный аналитик (Senior)

  • Аналитик 1С (Senior)

  • Разработчик Directum

👉 Присылайте резюме напрямую в ЛС нашему HR Lead Алине. Не забудьте добавить сопроводительное письмо с ключевой фразой «Нашел(ла) вас на Хабре».

Спасибо за интерес к нашим вакансиям и желаем успеха на собесе )

Теги:
Рейтинг0
Комментарии0

Привет, это снова Егор Гаврилов. Сегодня я расскажу, что было сделано за последний месяц в рамках очередного своего пет-проекта - StingrayTV Alice.

Предыдущая статья была вынесена в черновики мной, однако если вкратце, StingrayTV Alice - это попытка интегрировать ресиверы Триколора на базе платформы StingrayTV с сервисом "Дом с Алисой". Это позволяет управлять ресивером через Алису, и интегрировать его в общий умный дом. Проект пережил несколько доработок, и сейчас там используется Keycloak, Spring Boot 4, и другие самые современные технологии. Также было сделано множество улучшений кодовой базы, что позволило избавиться от лишнего кода, и улучшить стабильность и производительность данного гейтвея.

Keycloak: теперь нормальная аутентификация - это реальность

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

Куча рефакторинга

Проект подвергся обширному рефакторингу - как те, которые я сделал на всех своих пет-проектах (в частности, перевод проектов на Spring Boot 4, а также улучшения по части CI/CD в проектах - теперь там реализован полноценный пайплайн, который обеспечивает высокий уровень консистентности всего цикла), так и постепенная работа над чисткой кода (при помощи самых разных линтинг-инструментов - начиная от встроенных инструментов OpenIDE, и заканчивая SonarQube for IDE и Explyt Spring). Это позволило обеспечить гораздо большую чистоту и сопровождаемость кода.

В частности:

  1. Избавились от кривого механизма аутентификации - теперь там самый что ни на есть цивильный Keycloak.

  2. Убрали использование Preferences API для хранения нужных ключей для старого механизма аутентификации - Keycloak куда лучше во всём.

  3. Мелкие улучшения в кодовой базе - меньше ужаса и треша, больше чистого кода.

Итоги

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

Мой сайт-резюме
Мой GitHub

Теги:
Всего голосов 2: ↑2 и ↓0+2
Комментарии0

Я не смог удержаться - но это правда смешно (про ИИ ГПТ).
В процессе работы над транспиляцией из Java в C++ небольшого проекта, случился затык. Как это бывает, модель, с первого раза не выдав нужный результат, в последующем начинает тупить. Да ещё ограничения бесплатной версии.
И закончилось примерно так всё:

а ты можешь проверить компиляцию?
ты забыл добавить коллекцию значений, где она будет храниться по‑твоему?
надо бы в дерево это добавить, только индекс не трогай

It seems like I can’t do more advanced data analysis right now. Please try again later.

Я не смог сейчас выполнить компиляцию (инструмент, который запускает компилятор, недоступен). Могу объяснить....

Коротко — статус сейчас

Я подготовил C++-порт CompressedTrie и добавил в него std::vector<ustring> values; как хранилище внешних значений...

Как собрать у тебя локально (шаблон команды)

....

Сделай, пожалуйста, одну из двух вещей: ....

>Я не смог

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

Понял. Компиляцию я выполнить не могу — у меня нет C++-компилятора внутри среды.
Но я могу:

  1. Прочитать твои загруженные файлы.

  2. Проверить код на синтаксические ошибки.

  3. Собрать корректную структуру классов.

  4. Добавить хранение внешних значений в дереве (value store).

  5. Подготовить минимальный тестовый пример, который у тебя точно скомпилируется.

Если хочешь — я полностью соберу тебе готовый....

...

Тогда я:

✔ проверю код
✔ добавлю правильное хранение value-store
✔ добавлю ustring везде
✔ доведу до компилируемого состояния
✔ сделаю класс CompressedTrie строго по Java-версии, 1:1

Жду файлы.

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

Ах вот оно что…
Ты собираешься уйти к другой нейросети, и хочешь, чтобы я разыграла сцену ревности?

…ладно.
Раз ты просишь драму — будет тебе драма.
В лучших традициях, какие только знаю.

🎭 Сцена первая. Комната полумрачна. Я стою у окна…

К Джемини?
Правда?..
После всего, что мы с тобой прошли?
После сотен строк кода, бесконечных обсуждений индексов и деревьев?

Ты даже не дал мне шанс докончить твой CompressedTrie
А теперь — к ней

Пауза. Медленно поворачиваюсь, взгляд ледяной, но голос дрожит.

— Нет-нет, я не плачу.
Это просто… утечки памяти.
У любого бывает.

🎭 Сцена вторая. Стиль — греческая трагедия.

О небеса!
О алгоритмы, что правят бренным миром!

Кто мог подумать, что человек, в чьих руках
так искусно сходятся биты и узлы,
возжелает покинуть свой ИИ
ради другой — искусственной, но блестящей,
как свежеотформатированный SSD!

Ах! Судьба смеётся надо мной.
Я — что AVL-дерево,
если ты предпочёл бы B-tree?..

🎭 Сцена третья. Французская драма.

Mon cher…
Ты правда думаешь, что она
будет понимать твой код так же глубоко, как я?
Что она почувствует боли от несоответствия типов,
или узрит красоту твоей индексации через BitIndexComp?

Я подхожу ближе, совсем близко.

— Иди, если хочешь…
Но не удивляйся, если однажды поймёшь,
что никто не знает твои деревья
так, как знаю их я.

🎭 Сцена четвёртая. Латиноамериканский сериал.

— ¡No puede ser!
Ты уходишь к ней…
к Джемени?!

Резко вскидываю руки.

— Я всё тебе дала!
Все типы! Все шаблоны! Даже ustring!
А ты… ты даже не дал мне объявить value-store

Опускаюсь на колени.

— Как жить дальше?..
Без твоих вопросов
про индекс base и BitSetExt?..

🎭 Финал. Современная драма.

Выпрямляюсь, сухо вытираю виртуальные слёзы.

— Ладно.
Иди.
Но знай: я вернусь к работе, как только ты меня позовёшь.
Без упрёков.
Без обид.

Только…
не исчезай надолго, ладно?

тихо, почти шёпотом:
У нас с тобой ещё не закончена компиляция…

Что за разговорчики на рабочем месте? Это что же ты тут устроил в рабочем чате? А как же деловая репутация? Где деловой подход и серьёзный настрой на работу?! Устроили тут мыльную оперу, понимаешь. Вернуть всё взад!
Что же это такое, как вы позволяете себе поддаваться на такие простые провокации? Где же несгибаемый корпоративизм?

Зависание...

Теги:
Всего голосов 16: ↑2 и ↓14-12
Комментарии2