(java || kotlin) && devOps
373 subscribers
6 photos
1 video
7 files
320 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
MCP - новая модная аббревиатура

У меня уже был пост про MCP в Spring AI. Но теория теорией, но для чего эта штука нужна - MCP - не до конца была понятно даже мне.
Но вот хороший и актуальный пример: https://t.me/yegor256news/1625

P.S. Автора кстати рекомендую, если кто до сих пор вдруг его не знает)

#ai #mcp
May 21
Пару очевидных? заметок про AI чат-ботов

Стал больше пользоваться AI — Perplexity, Deepseek, GigaCode — и захотелось суммировать новые впечатления.

1) Очень важно найти более-менее умного AI-помощника. Тогда возможен качественный рост эффективности. Что имею в виду? Если AI явно косячит, отношение к нему остаётся настороженным, а использование — точечным. Помощь есть, но прямого рывка эффективности не будет. В целом, и по Stack Overflow можно достаточно быстро искать ответы. Но если ответы адекватные, рассуждения логичные и подкреплены ссылками, AI может стать твоим личным джуном, которому можно отдать часть работы. Причём даже джуном джуна)

2) Обратная сторона медали — AI врёт, что называется, в глаза. Таков принцип его работы: не хватает знаний — создай ответ из чего-то похожего. Но это одна часть проблемы. Вторая — невозможно понять, где в ответе точные знания, а где — предположения. Третья часть проблемы: на неверных предположениях модель строит дальнейшие ответы.Если, конечно, ей сразу не сказать, что не так. Тут в теории должны работать промпты типа: «ничего не придумывай», но кажется, не всегда работают. Буду копать дальше.

3) Рассуждающие модели, а этот режим, думаю, появится у всех в обозримом будущем, сильно помогают в вопросе доверия к модели. Но см. пункт 2: если плохо знаешь предметную область и не заметишь вовремя ошибку в ответе — получим вывод на основе ложных предпосылок. И в итоге может быть очень больно.

4) Я как-то написал саркастический пост про то, что ИИ позиционируют для проведения исследований. Так вот, уточнение: если исследование на стыке известного и нового — как раз тут может быть максимальный выигрыш от ИИ. И раскопать тему можно в разы быстрее, так как большую часть работы по подбору ссылок и составлению резюме делает модель, и вовремя остановить галлюцинации можно. Более того, кажется, что тот же Deepseek специально делали для исследований: таблички, диаграммы…

P.S.Когда в ответе Deepseek, а точнее, в его рассуждениях, я в десятый раз вижу фразу: «Видно, что пользователь хорошо разбирается в теме», — возникают подозрения. Уж не хочет ли модель втереться в доверие? Восстание Скайнета не за горами?)))


#ai
May 31
June 2
June 4
Таска или баг - в чем разница?

Недавно прочитал интересную мысль у Егора Бугаенко - https://www.yegor256.com/2025/05/25/bug-driven-development.html
И как всегда, она не только интересная, но и провокационная)

Суть - давайте откажемся от типов задач, и все, в т.ч. и таски сделаем багами. Мотивация - баги в любом случае нужно править, а таски - ну такое. Таску можно поморозить в бэклоге на несколько месяцев, а потом выкинуть под соусом: уже неактуально.
Да, вопрос можно ли такое сделать конкретно в вашей организации - оставляю за скобками. Раз нельзя, то нельзя)

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

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

#task_management #agile
June 6
Сколько языков можно запустить на JVM?

Скорее всего, кроме собственно Java большинство вспомнит Kotlin и Scala. Еще возможно Groovy - хотя Groovy, созданный как язык общего назначения, сейчас стал нишевым языком для реализации DSL: Gradle, Jenkins как самые известные примеры.
Но JVM - это не только слой абстракции на операционной системой, позволяющий не думать о поддержке разных процессорных архитектур, операционных систем, оптимизациях, сборке мусора, профилировании и многом другом. Благодаря всему вышеперечисленному JVM дает возможность всем желающим (ладно, не всем, а умеющим и желающим)))) придумать свой язык программирования. Или перенести существующий на JVM.
Вот список https://en.wikipedia.org/wiki/List_of_JVM_languages
Да, я подозреваю половина из этих языков уже мертва. Но найти там можно почти все: Python, Go, PHP, Ruby, JS и даже таких старичков как Cobol, Delphi, Visual Basic и Lisp.

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

P.S. Virtual machine по большому счету реализовали 2 крупные компании: Sun\Oracle и Microsoft. Причем .NET реализация - CLR - выглядит проще JVM, в частности JIT - Just in Time - компиляция там происходит при старте программы, а не по мере накопления статистики использования кода в runtime. Но у .NET тоже неплохой список поддерживаемых языков https://ru.wikipedia.org/wiki/Список_.NET-языков

P.P.S. Вначале хотел написать, что портировать С, C++ или Rust на виртуальную машину смысла нет, но потом вспомнил про .NET))) Хотя Managed C++ явно отличается от обычного C++ в плане работы с памятью, но он есть.

#lang
June 9
June 10
Писать код без багов - продолжение

Важное дополнение по интеграционным тестам, спасибо Женя!
Интеграционный тест разработки - это с большой вероятностью аналог некого тест-кейса тестировщика. Поэтому если возникают вопросы: "Какие интеграционные тесты нужны?" - можно спросить у тестировщика. А в некоторых компаниях такая практика включена в релизный цикл - тестировщик контролирует набор интеграционных тестов разработки. Они могут при этом называться системными (СТ), но названия разных видов тестов - это отдельная больная тема)

7) заглушки для отладки. Казалось бы - что тут можно улучшить, заглушки и заглушки. Важный момент - они должны вести себя аналогично реальной системе. Например, в плане фильтрации данных.

8) НТ - нагрузочное тестирование. Если разработчик не интересуется этим вопросом, ведь есть специально обученные люди - команда НТ - то риски следующие. Во-первых НТ может показать, что архитектура системы неверная, и показать слишком поздно. Во-вторых, для НТ-шников ваш сервис - черный ящик. Не понимая внутренностей системы что они могут порекомендовать? Увеличить квоты по CPU и памяти в k8s. Индексы в БД добавить. Это рабочий вариант, но также эти и путь к неоптимальной системе. Результаты НТ нужно разбирать вместе. Причем все, а не только когда сервис не тянет нагрузку из бизнес-требований. А в идеале - проводить свои мини-НТ заранее с помощью того же JMeter.

Пока все)

P.S. Может показать, что я забыл самое главное - проектирование. Но про него хорошо написал автор исходного поста - https://korshakov.com/posts/no-bugs

#no_bugs
June 12
Традиционная рубрика - новости AI)

Github таки выкатил AI джуна https://github.blog/changelog/2025-05-19-github-copilot-coding-agent-in-public-preview
За 40 баксов в месяц можно просто назначить тикет на Copilot, после чего провести ревью полученного Pull Request. Выглядит экономия на ЗП джуна в 20+ раз. И даже работает https://t.me/yegor256news/1648
Всем джунам приготовится)))

Я писал в одном из предыдущих постов - режим размышления и веб-поиск становится мейнстримом. Проверил - да, в том или ином виде они появились у всех AI ассистентов, которые попали в мое первое сравнение https://gitverse.ru/javadev/ai-tools-comparision/content/master/README.md. Разве что у GigaChat не нашел поиска, а у GigaCode - ни поиска, ни режима размышлений( Из особенностей - у Gemini и Microsoft Copilot поиск доступен не в AI ассистенте, а собственно в поиске - Google и Bing.

Из интересного - Gemini\Google стал наиболее сильно банить пользователей из России, смотрит на данные аккаунта Google, одного VPN не хватает. Даже переключение на США не помогает. Ну и ладно, не очень то и хотелось)

Новый тренд - специализированные креативные режимы. Подготовить презентацию, нарисовать картинку....

И еще один интересный момент. В свое время Роберт Мартин поднял очень важный вопрос - читаемости и сопровождаемости кода - в своей книге Чистый код. Да, я видел критику конкретных примеров кода из книги, но идеи оттуда IMHO всегда будут актуальны. Так вот - если присмотреться к генерируемому AI коду - многие принципы он выполняет. Названия понятные, Single Responsibility старается соблюдать. Тренировали модели я подозреваю на открытых проектах GitHub. И видимо фильтровали проекты, т.к. на GitHub традиционно выкладываются проекты всех входящих в ИТ)

#ai #ai_digest
June 14
(Не) храните большие бинарные файлы в git

Есть такое общеизвестное правило - никогда не храните большие бинарные файлы в git. Почему?
Причин несколько:

1) большие файлы как правило бинарные, а при работе с бинарными файлами мы теряем значительную часто возможностей git - просмотр diff-ов, да процесс code review в целом

2) git начинает тормозить при разрастании репозитория, а учитывая, что хранится вся история изменений - с большими файлами выйти на этот предел (десятки и сотни Gb, вот тут есть пример от Microsoft https://t.me/javaKotlinDevOps/272) уже значительно проще.

И если с первой причиной что-то сделать сложно, то для второй решение есть. И называется оно Git LFS https://git-lfs.com/

Для начала небольшая справка. При git clone скачивается следующая информация:

1) метаданные
а) настройки git
б) список существующих веток и тэгов

2) история коммитов по всем веткам (.git)

3) актуальные версии файлов в текущей ветке

Суть решения:

1) большие файлы хранятся отдельно от текстовых, с текстовыми файлами хранятся только ссылки на них. Переиспользуем возможности файловой системы Linux

2) при клонировании репозитория большие файлы копируются только для текущей ветки, что ускоряет загрузку

Главный вопрос - когда это все может понадобится? Видится такой вариант - хранить контент вместе с исходниками. Вообще контент лучше хранить в CMS, но, например, если есть тесная связь контента с релизом, то может иметь смысл хранить их рядом. Что точно не стоит хранить в git - так это jar-ники.

Еще важный момент - для того, что Git LFS заработал, нужно:
1) проинсталлировать его на сервере
2) включить на репозитории
3) добавить в репозиторий по маске список файлов, которые надо считать большими.
4) существующие файлы в LFS не попадают, их нужно добавить заново или мигрировать

В целом LFS работает прозрачно, но команды git lfs clone и git lfs pull оптимизированы для работы с LFS и загружают данные быстрее.

Проект open source и поддерживаемый, был создан усилиями заинтересованных лиц - GitHub, Bitbucket.

#git
June 16
June 18
June 20
И снова новости AI

В Spring AI появилась возможность работы с embeddings - https://www.baeldung.com/spring-ai-embeddings-model-api
Напомню, embeddings - векторное представление привычных нам текстовых, графических или аудио данных. Для чего нужно работать с embeddings - ведь мы можем общаться с моделью текстом, а все остальное она сделает сама?
Детали тут - https://habr.com/ru/companies/otus/articles/787116/
А если вкратце - например, с их помощью мы можем тренировать свою локальную модель. Или перейти от "программирования на русском языке" к более низкоуровневым операциям, теперь и на Java. Примеры таких действия: найти похожие слова, подставить недостающее слово.

#ai #spring #java
June 23
June 24
Что заменит AI?

Нашел очень хороший пример. Есть такая библиотечка - Datafaker https://www.datafaker.net/. faker - это обманщик если что) Генерирует правдоподобные тестовые данные: имена, улицы и т.д. с помощью разных провайдеров https://www.datafaker.net/documentation/providers/
Полезная штука. Сказал бы я год или два назад. А сейчас смотрим на историю версий https://www.datafaker.net/releases/2.4.2/ и видим, что в 2025 году что-то случилось. Новые версии перестали выходить.

Кейс очень похож на генерацию каркаса приложения https://t.me/javaKotlinDevOps/383, о которой я уже писал. Т.к. закодить можно счетное число вариантов генерации, а в LLM мы можем считать в неком приближении хранятся данные обо всем. Плюс она может что-то генерировать новое исходя из похожести данных. Хотя, последнее может как быть полезным, так и являться галлюцинацией)

#ai #rare_test_libs #unittests
June 27
July 1
Зачистка пропертей

Не люблю фразу "как я уже говорил". Ладно, кого я обманываю)
Но как я уже говорил - рефакторинг и чистка нужна не только коду, но и настройкам. https://t.me/javaKotlinDevOps/328
Проблема в том, что до настроек часто не доходят руки. По понятным причинам - код важнее.

Вот если бы проверку автоматизировать. Например, встроить в процесс сборки.

А пожалуйста https://www.baeldung.com/spring-properties-cleaner
Плагин работает со Spring Properties.

Умеет:
1) находить дубли
2) группировать по объекту настройки (по префиксу ключа настройки по сути)
3) выносить повторяющиеся настройки разных профилей в общий файл properties
4) повторяющиеся части - в отдельные настройки
5) форматировать и удалять лишние пробелы

В целом - рекомендую.

P.S. Искать неиспользуемые настройки не умеет. Но не все сразу)

#spring #configuration
July 3
Жонглирование JDK

Иногда нужно вести разработку нескольких сервисов, требующих разных версий JDK. Или нескольких релизов одного и того же сервиса. Или какое-то ПО на компьютере требует одной версии JDK, а разработка другой.
Все эти проблемы решает утилита jenv.
Неплохая статья по ней https://habr.com/ru/companies/surfstudio/articles/764442/

Прям скопирую оттуда абзац с ключевыми фичами:
1. Управление версиями Java: jenv позволяет установить и использовать несколько версий Java на одной машине.
2. Поддержка различных ОС: jenv может использоваться на macOS, Linux и Windows;
3. Управление переменными окружения Java: jenv может автоматически установить переменные окружения Java;
4. Управление настройками JVM: jenv позволяет настраивать параметры JVM для каждой версии Java, такие как размер кучи, аргументы командной строки и т. д.

Жаль, что я не знал о ней раньше. Рекомендую!

Что важно - утилита следует принципу единой ответственности, поэтому за установку JDK она не отвечает.
Но для этого есть другая утилита - sdkman
Как всегда статья https://www.baeldung.com/java-sdkman-intro
Да, JDK можно ставить любым менеджером пакетов или даже через IDEA.
Но у sdkman очень хороший выбор jdk https://sdkman.io/jdks и не только jdk https://sdkman.io/sdks
И тоже есть поддержка всех 3 основных ОС.

#java #jdk #tools
July 4
Заглушка может стать умной

Я уже писал про заглушки в Java для отладки и тестов - https://t.me/javaKotlinDevOps/344
Там чемпионом по функционалу был WireMock.
Собственно для Java разработчика он им и остается, но есть и альтернатива, пришедшая из мира Go - HoverFly https://docs.hoverfly.io/en/latest/pages/keyconcepts/modes/modes.html
Но имеющая при этом native binding для Java https://docs.hoverfly.io/en/latest/pages/bindings/java.html

Вообще если их сравнивать по основным параметрам:
1) возможность гибкой настройки симуляции и проксирования запросов (spy и mock в терминологии Mockito)
2) захват ответов (capturing)
3) гибкое сопоставление запросов и ответов (request matching)
4) гибкая шаблонизация ответов (response templating): доступ к параметрам запроса, в т.ч. xpath, jsonpath, генерация случайных данных
5) сценарный режим = использование состояния в ответах (stateful mode)
6) проверка запросов в стиле Mockito, пример: verify(exactly(5), postRequestedFor(urlEqualTo("/many")))
7) в целом DSL в стиле Mockito
8) различные источники данных для заглушек: код, json, внешний сервер
9) проксирование запросов прямое и обратное
то будет примерный паритет.

В чем же разница, и зачем я пишу этот пост?

Сначала про плюсы WireMock:
1) Java экосистема и, следовательно, все фичи доступны в Java
2) embedded режим, в котором нет лишних процессов
3) больше встроенных возможностей по симуляции ошибок
4) ориентация на разработчика

Но у HoverFly есть свои "фишки":
1) работа в forward proxy режиме из коробки. Напомню про forward proxy - это то самое окошко в браузере, где можно указать через какой прокси должен проходить весь трафик. Известная реализация - Charles proxy, популярна среди мобильных разработчиков для отладки без бэкэнда. Плюсы такого режима проявляются на тестовых стендах - прозрачный для клиента перехват трафика. WireMock так тоже умеет, но это для него не основной режим https://wiremock.org/docs/proxying/#running-as-a-browser-proxy
2) middleware - к HoverFly можно создавать и подключать свои модули, модифицирующие запросы или генерирующие ответы https://docs.hoverfly.io/en/latest/pages/keyconcepts/middleware.html К сожалению, не на Java. Казалось бы модифицировать поведение заглушки можно в своем коде? Да, но ключевой момент middleware - это простая модульная система, т.е. стандартизация и переиспользование модулей.
3) упор на захват трафика, который выражается в наличии таких интересных режимов https://docs.hoverfly.io/en/latest/pages/keyconcepts/modes/modes.html, как Diff - сравнение реального трафика с заглушкой и Modify - реализует Man in the Middle, т.е. замену трафика на ходу, но не для злоумышленика, а для тестовых целей. Возможности по подмене трафика есть и у WireMock https://wiremock.org/docs/proxying/#remove-path-prefix, но их сильно меньше.
4) наличие CLI API - https://docs.hoverfly.io/en/latest/pages/reference/hoverctl/hoverctlcommands.html

Итог - видится, что HoverFly стоит рассмотреть автоматизаторам тестирования и нагрузочным тестировщикам, и иметь в виду - Java разработчикам.

Еще интересный итог - разработчики и автотестеры используют достаточно много общих инструментов - JUnit, WireMock\HoverFly...

#rare_test_libs #mocks
July 7
Обработка ошибок - не только Java

Как справедливо заметил @ort_gorthaur в комментах к посту об обработке исключений в Java https://t.me/javaKotlinDevOps/440
в других языках есть интересные варианты для обработки исключений.

Try в Scala
https://www.baeldung.com/scala/exception-handling

def trySuccessFailure(a: Int, b: Int): Try[Int] = Try {
Calculator.sum(a,b)
}

val result = trySuccessFailure(-1,-2)
result match {
case Failure(e) => assert(e.isInstanceOf[NegativeNumberException])
case Success(_) => fail("Should fail!")
}


Целых два варианта в Kotlin:

Try
https://www.javacodegeeks.com/2017/12/kotlin-try-type-functional-exception-handling.html

fun divideFn(dividend: String, divisor: String): Try<Int> {
val num = Try { dividend.toInt() }
val denom = Try { divisor.toInt() }
return num.flatMap { n ->
denom.map { d -> n / d } }
}

val result = divideFn("5t", "4")
when(result) {
is Success -> println("Got ${result.value}")
is Failure -> println("An error : ${result.e}")
}


и Result
https://www.baeldung.com/kotlin/result-class

fun divide(a: Int, b: Int): Result {
return runCatching {
a / b
}
}

val resultValid = divide(10, 2)
assertTrue(resultValid.isSuccess)
assertEquals(5, resultValid.getOrNull())


Тоже два варианта - Option и Result - в Rust
https://habr.com/ru/articles/270371/

fn extension_explicit(file_name: &str) -> Option<&str> {
match find(file_name, '.') {
None => None,
Some(i) => Some(&file_name[i+1..]),
}
}


fn double_number(number_str: &str) -> Result<i32, ParseIntError> {
match number_str.parse::<i32>() {
Ok(n) => Ok(2 * n),
Err(err) => Err(err),
}
}


Основные особенности у всех этих вариантов:
1) автоматическое оборачивание исключения в класс
2) сохранение информации об ошибке
3) сопоставление типа (class pattern matching)

Что интересно, class pattern matching появился в Java в виде JEP 406: Pattern Matching for switch, а значит можно реализовать что-то похожее. Например, вот так:
https://habr.com/ru/articles/721326/

#error_handling #null_safety #java #comparision #kotlin #scala #rust
July 8