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

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

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

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

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

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

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

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

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

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


#ai
😁3🤔2
skip level в ИТ

О чем речь? Не о том, как из джуна стать сеньором, не уверен, что это возможно) А об обращении к вышестоящему руководителю.
Причем кейсы могут быть разные, т.к. часто есть две иерархии - продуктовая\проектная и ИТ-ная. PO и ИТ лид. Прожект и тимлид.

Т.е. возникает проблема при общении с одним из руководителей и желание пойти к другому. Желание нормальное, но я здесь вижу три кейса.

1) системная проблема в проекте или команде. Тогда "жаловаться" можно и нужно, если проблема будет решена - плюсы в карму и не только в карму)

2) проблема личного развития. Тут есть важная развилка. Она решается следующим вопросом: что я сделал для своего развития?

а) если ответ: я хочу заниматься Х и получить за это У, но злой продакт меня не понимает, пойду к ИТ лиду, чтобы он заставил продакта меня развивать - то это напоминает поведение трехлетнего ребенка. Мама не дала конфетку, пойду к папе. Что делать с ребенком - ничего, ребенок же. Что делать с ИТ-шником - это очень серьезный звоночек на то, что нам с ним не по пути.

б) если же ответ: я сделал уже вот это, учусь, готов учиться еще больше, но все без толку ... - это уже тема для предметного разговора. И опять же плюс в карму.

#it_career
Как внедрить AI?

Кажется, что сейчас все и везде внедряют AI. Я тут вижу два основных проблемных момента. И это не правильные промты, не продумывание мульти-агентной архитектуры, не тестирование, не AI-зация существующих API чтобы агенты могли ими пользоваться. Это все конечно же важно, но вполне реализуемо. А обратить внимание стоит вот на что:

1) достаточность набора данных. Много данных - хорошая статистика, точные ответы. Мало данных - точность ответов падает, галлюцинации растут. Вторая проблема маленького объема данных - если данных мало, то возможно алгоритм все же детерминированный, а значит проблема решается кучей if без всякого AI. Ну хорошо, кучей if, разделенных на несколько методов\классов по принципу SRE) Хотя и тут для AI остается ниша распознавания человеческой речи и маппинга запроса на API.

2) найти ту предметную область, где результат работы модели (или агента) в случае если он верный - создает вау эффект у пользователя, а если не верный - может быть проигнорирован. Хороший пример - рекомендации любого контента или товара. Не очень хороший пример - финансовая сфера, цена ошибки тут велика. И не важно - ошибочный ли это перевод денег или плохая рекомендация как распределить свои финансы или какие акции покупать.

Но конечно же, хоронить на AI в финансах не надо, надо искать)

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

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

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

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

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

#task_management #agile
🔥2
Сколько языков можно запустить на 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
1
Можно ли писать код без багов?

Сразу после прочтения этого поста: https://korshakov.com/posts/no-bugs захотелось написать свой пост на пост)
Потом появился неплохой комментарий https://t.me/rybakalexey/190 и кажется - что тут добавить?
Прошло время, и я понял, что именно)

Вкратце содержимое предыдущих серий:
1) писать без багов, ладно с минимальным количеством багов, можно
2) для этого нужно начать заставлять себя постоянно улучшать код до тех пор, пока это не станет привычкой
3) первое время это замедлит разработку, потом скорость вернется в норму

Ключевое слово - фокус на том, чтобы всегда делать код лучше. Под кодом я понимаю в т.ч. и архитектуру, тесты, ....

Я бы хотел добавить немного практики - на что можно обратить внимание.

0) нулевой пункт - потому что очевидный. Следование практиками чистого кода. Ключевой момент - понятные наименования и читаемость. Нет читаемости - нет понимания, как код работает, легче допустить ошибку при модификации.

0.5) еще один нулевой пункт - модульные тесты. Тесты - это основная страховка при рефакторинге и серьезных изменениях в архитектуре. Без тестов проект сразу становится legacy.

1) TDD. Какая связь с багами? Через тесты, конечно. Если тесты пишутся после кода - всегда есть риск, что из-за сдвинувшихся сроков на тебя надавят и заставят отдать фичу на тестирование как есть. А это баги и вообще говоря еще больший сдвиг сроков. Но объяснить это менеджеру сложно. Если же тесты пишутся до кода - гнать в ПРОМ фичу без части функционала никто не будет. Хотя может быть и стоило рассмотреть именно такой вариант)

2) Управление техдолгом. Он возникает, когда вот прямо сейчас сделать все красиво не получается - https://t.me/javaKotlinDevOps/312
Ключевая мысль - техдолг нужно оцифровывать. Как TODO, как таски, как TODO превращенные роботом в таски - не важно. Главное, что техдолг записан, после чего потерять его станет сложнее. Улучшится прозрачность, появится артефакт для обсуждения с командой и планирования исправления техдолга. Голова разработчика - хорошо, но нет) Опять же: есть бизнес, у него есть новые фичи, меняются люди - в итоге благие намерения ими и остались, техдолг забыт, архитектура и код медленно превращается в "большой ком грязи".

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

4) Качественное ручное и автоматическое код-ревью. Некачественное - это замечания типа добавь комментарий к конструктору в SonarQube или скоростное код-ревью за 5 секунд от коллеги. Ни первая, ни вторая практика не найдут всех ошибок. Может даже и половины не найдут. Но какие-то найдут, и это в итоге сделает код лучше. Поэтому профиль SonarQube или другого анализатора нужно настраивать "под себя", все найденные им баги править. О ручном код-ревью договариваться с коллегами, PO или ИТ лидом чтобы на это выделялось время. Ну и соблюдать рекомендации по pull requests https://t.me/javaKotlinDevOps/148

5) внимание к вопросам сопровождения, понимание их болей. Идеально конечно было бы you build it - you run it, но не везде это возможно. Сопровождение - по крайней мере там, где я это видел - работа достаточно стрессовая. Поэтому система должна быть максимально простой в плане сопровождения. Это значит: инструкция по внедрению, понятные и актуальные наименования, необходимый минимум настроек, логи без мусора, метрики и трейсы, наличие рубильников ("feature toggle"), rate limiters, быстрое время старта пода. Иначе - баги и инциденты ПРОМа.

6) время на уборку мусора. GC тут не поможет, речь о мусоре в проекте. Это могут быть настройки https://t.me/javaKotlinDevOps/328, это может быть неиспользуемый функционал или просто лишние библиотеки. Про это часто, даже откровенно говоря почти всегда, забывают

Пока все, думаю еще со временем накину)

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

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

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

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

Пока все)

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

#no_bugs
Традиционная рубрика - новости 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
1
(Не) храните большие бинарные файлы в 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
AI и leetcode

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

Что меняется с появлением AI?

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

2) с точки зрения сторонников данной практики ничего не меняется - такие задачки как проверяли способности к мышлению, проектированию и кодированию, так и проверяют. И я думаю, что они останутся на собесах

3) у противников данной практики основной аргумент усиливается. Если раньше можно было сказать - с вероятностью 90% мне это в реальной работе не понадобится, то сейчас цифра примерно равна 99%)

4) но возникает интересный момент. Вот решил кандидат за 1.5 часа 3 задачки. Даже 10 минут в резерве осталось. Появляется чувство: "А я хорош!)". Возникает мысль - интересно, а AI агент эти задачки решит. И агент решает их за 10 минут... И какие-то самые некрасивые мысли лезут ко мне в голову...

#ai #interview #algorithms
Предыдущий пост был немного провокационным)
Вынесу мой ответ на поставленный вопрос отдельно:

Алгоритмическое мышление - важный навык программиста. Но его проявление не исчерпываются вариантом - написать какую-то сложную сортировку за 30 минут. Сейчас проявление этого мышления уходит в сторону - приемочное тестирование кода, полученного от AI и вверх - проектирование: разбиение на микросервисы, на слои, классы, методы, разделение на код, который можно отдать AI, и код, который лучше написать самому.

#ai
И снова новости 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
Надо задавать вопросы.

Есть такое понятие - "сеньорность". Синоним опыта разработки по сути, насмотренность.
Так вот, один из ее секретов - задавать правильные вопросы.

Какие вопросы правильные? Предположим у меня есть знания в некой предметной области разработки ПО. И я вижу или слышу что-то такое, касающееся этой области, что вызывает у меня вопрос - почему так? Так вот - этот вопрос нужно задать явно. И проанализировать ответ, конечно.

Потенциальные проблемы я вижу две:

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

2) если ты плохо знаешь предметную область, например, ты больше ИТ менеджер, чем тимлид. Тогда можно в самом деле можно перебрать с "глупыми" вопросами, что скажется на доверии команды. Тут решения могут быть такие: "покурить" тему перед вопросом, проконсультироваться с независимым экспертом или "прореживать" такие вопросы. В любом случае баги или ошибки будут, вопросы от тимлида команде - это лишь еще одна сеть для ловли багов. А таких сетей должно быть много.

#seniority
Что заменит 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
Что возвращать при ошибке?

Какие есть варианты?
1) exception
2) false
3) Optional и аналоги
4) NullObject
5) null

Для начала я бы отбросил (ну или отложил для особых случаев) вариант с null. Он давно уже "проклят", как приводящий к NPE.

Оставшиеся варианты я предлагаю разделить на две группы - NullObject vs все остальные

Основная разница между ними - первый не требует немедленной обработки ошибок, другие - требуют. Отсутствие такого требования - это преимущество, т.к. дает нам гибкость. Если надо - проверили на ошибку сразу, не надо - позже. Но у гибкости есть обратная сторона - увеличивается сложность. Т.к. NullObject выглядит как настоящий объект - он может пролезть достаточно далеко по коду. Вплоть до сохранения в БД, где ошибка и произойдёт. Или не произойдёт, что видится ещё худшим вариантом. Итого - для отложенной обработки ошибок NullObject выглядит оптимальным даже учитывая описанные выше риски.

exception vs false vs Optional.

false плох тем, что не дает ничего вернуть из метода. Иногда это ок, но в общем случае - не ок. Ну и method chaining конечно же ломает.

exception vs Optional
Да начала exception бывают checked и unchecked. Первые с точки зрения обработки ошибок надёжнее - сложнее забыть обработать ошибку (если только использовать @sneakythrows и аналоги). Но checked exception имеют свои минусы, не даром нигде, кроме Java, они не прижились.

unchecked exception vs Optional
У exception есть один большой минус. Unchecked exception из чужого, плохо документированного кода, да к тому же возникающий редко - проблема, т.к. может дойти не до того уровня обработки ошибок, который планировался. Еще одна проблема - прерывание потока выполнения. Если этим злоупотреблять - имеем аналог go to, антипаттерн.С другой стороны exception  достаточно гибкий - можно отлавливать локально, на уровне сервиса или контроллера или на уровне фреймворка (Spring @ExceptionHandler). Код обработки ошибок может быть любым.
Плюсы Optional - его можно свести либо exception, либо к NullObject. Минусы - если захочешь тащить его выше - читаемость кода ухудшается. Т.е. Optional - это как правило короткоживущий объект. Он не совместим с JPA и с Java сериализацией. Еще важный минус - Optional не предоставляет средств для хранения деталей ошибки. Для меня минусы перевешивают плюсы. И судя по коду, который я вижу - не только для меня)

Если поставить вопрос: "Когда лучше обработать ошибку?" - то мой ответ: "Лучше сразу, это надёжнее".

Ну и традиционный итог: разработка - искусство  компромиссов)

#dev_compromises #null_safety #error_handling
Зачистка пропертей

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

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

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

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

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

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

#spring #configuration
Жонглирование 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
Заглушка может стать умной

Я уже писал про заглушки в 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
Обработка ошибок - не только 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