(java || kotlin) && devOps
342 subscribers
13 photos
2 videos
7 files
420 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
Еще один AI стандарт намечается.

https://agentskills.io/home

В чем суть?
Есть агенты, каждый агент может делать что-то специфичное. Возникает идея стандартизировать его функционал, чтобы переиспользовать.
Например: чтение pdf файлов, создание xlsx таблиц...
Т.е. в первую очередь это касается навыков небольшого размера, полезных множеству агентов. Но не только.

Если посмотреть что представляет собой спецификация навыка - промты, документация, описания API и скрипты.
Пример: https://github.com/anthropics/skills/tree/main/skills/docx
Т.е. навык нужно поддерживать: версии, обновления, security fixes.

Еще можно сравнить с MCP серверами.
MCP - кастомные навыки, домен-специфичные, требующие доступа к БД или другим сервисам, реализуются в отдельном сервисе (MCP сервер).
Skills - навыки общего назначения, лежат внутри агента.

Почему стандарт? Предложил Anthropic, но поддерживают кроме Claude Code уже OpenAI с Microsoft.
Т.е. как минимум 3 из ведущих dev AI агентов. Глядись и Cline подтянется. И GigaCode.

P.S. Да помню я, что в названии блога Java!))))

#ai #mcp
1
Непрерывное развитие Spring

Когда я увидел вот эту штуку: https://docs.spring.io/spring-framework/reference/core/beans/java/programmatic-bean-registration.html - Programmatic Bean Registration, т.е. новый API для программной регистрации бинов, я подумал: "Стоп, где-то я это уже слышал? А старый API чем не угодил?"
Вот тут человек прям провел расследование с экскурсом в историю https://habr.com/ru/companies/spring_aio/articles/915512/

Ну и как всегда краткое содержание:
а) чуть более удобное API
б) новое API явно предназначено для регистрации бинов, что упрощает работу разного рода оптимизаторов старта приложения. Вот где собака порылась.

Было:

@Component
class ProgrammaticBeanRegistry implements BeanDefinitionRegistryPostProcessor {

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
registry.registerBeanDefinition("withCallback",
BeanDefinitionBuilder.genericBeanDefinition(WithCallback.class).setPrimary(true).setLazyInit(false)
.setScope("prototype").getBeanDefinition());
}
}


Стало:

@Component
static class MyBeanRegistry implements BeanRegistrar {

@Override
public void register(BeanRegistry registry, Environment env) {
if (env.matchesProfiles("dev|qa")) {
registry.registerBean("testBean", WithCallback.class, spec -> spec.fallback().lazyInit().order(Ordered.HIGHEST_PRECEDENCE));
} else if (env.matchesProfiles("prod")) {
registry.registerBean("prodBean", WithCallback.class, spec -> spec.primary().prototype().lazyInit());
}
}
}


Эволюцию не остановить)

P.S. Пока все не перепишут код на новое API - оптимизации работать не будут. Как минимум сам Spring это должен сделать.

#spring
1
Немного о инициализации Spring Bean

Я думаю все или почти все Java разработчики знают аннотацию @Primary.
Это когда есть несколько бинов одного типа и корректно указать, какой из них нужно грузить не получается, приходится "прибивать гвоздями".
Корректно - это через имена бинов или привязку к профилям.
Такая необходимость возникает, если проблемный бин в библиотечном коде, и изменить его код невозможно. А автор библиотеки не предусмотрел переопределение бина.

Так вот, для авторов библиотек есть хорошее решение - @Fallback.
Как всегда статья - https://www.baeldung.com/spring-fallback-beans
Как понятно из названия аннотация определяет бин, который загрузится в контекст только тогда, когда других кандидатов не нашлось.
И кроме fallback, ее можно использовать как default. Т.е. если есть ненулевая вероятность того, что бин понадобится переопределить.

Появилась начиная с Spring Framework 6.2.0-M1.

#spring
1
Тест для проверки мозга после из новогодних праздников)

Почему? Тут будут алгоритмы)

Я уже писал про Consistent Ring Hashing - https://t.me/javaKotlinDevOps/46 - решение для для равномерного распределения данных по нодам\серверам\шардам
Но это не единственное решение, особенно когда появляются требования:
1) много нод (тысячи, десятки тысяч)
2) частое добавление и удаление нод
3) минимальный объем перемещения данных при ребалансировке нод
4) простота алгоритма и, соответственно, его отладки
5) минимальное потребление памяти для хранения данных маршрутизации
6) минимальное время вычисления целевой ноды
7) максимально равномерное распределение данных
8) возможность назначать веса нодам

Естественно, единственно оптимального решения для всех этих требований нет.
Но есть варианты:
1) Consistent Ring Hashing с виртуальными нодами
2) Rendezvous Hashing
3) Jump Consistent Hashing https://iq.opengenus.org/jump-consistent-hash/ (VPN)
4) Consistent Hashing with Bounded Loads https://gweb-research2023-stg.uc.r.appspot.com/blog/consistent-hashing-with-bounded-loads/

И парочка сравнительных статей с которых стоит начать:
https://dtf.ru/gamedev/1215676-consistent-protiv-rendezvous-chem-otlichayutsya-podhody-dlya-heshirovaniya-dannyh-na-servere
https://chaotic.land/ru/posts/2024/09/data-sharding-algorithms/

Для себя сделал такие выводы:
1) Consistent Ring Hashing - база
2) Rendezvous Hashing - простой алгоритм, равномерное распределение "из коробки", но медленнее, что сказывается при большом числе нод
3) Jump Consistent Hashing - быстрый, тоже равномерный "из коробки", но плохо себя ведет при частом изменении числа нод и необходимости добавления весов

P.S. С наступающим!)

#algorithm #distributedsystem
И снова про зависимости)

В продолжение поста проблемы с поиском и добавлением зависимостей в Maven/Gradle проекты https://t.me/javaKotlinDevOps/503 - в комментарии к посту пришёл @gmyasoedov и предложил решение (разработал если быть точным). Это плагин IDEA, переиспользующий движок и UI поиска зависимостей от Maven Central. Есть итеграция с редактором IDEA и поддержка Maven и Gradle. Плюс некоторые другие плюшки - типа провалиться в папку с локальной зависимостью.

Детали тут https://habr.com/ru/articles/981132/

Лично я буду пробовать.

#idea #maven #gradle
👍1
Третий репозиторий Java разработчика

Изначально был Maven Central.
Потом появился Docker Hub.
Теперь ещё и Hugging Face - хранилище opensource моделей.

И с ним возникают свои нюансы.
Например:
1) у некоторых моделей нужно зайти в UI и запросить доступ, явно согласившись с лицензией. Чем это принципиально отличается от License.md - не понятно

2) если JVM и Docker скрывают от нас железо, то LLM модели - нет. От того, что у вас - CPU, GPU или NPU - зависит выбор модели. Базовая модель может быть одинаковой, но появляется новое измерение - оптимизация под железо. Кроме того, у разных NPU - Intel, AMD, Qualcomm, Google, anyone else?)- разные SDK. А NPU выглядит перспективной штукой, так как он специализированный и более дешёвый. В общем, напрашивается новый слой абстракции.

#ai #llm #infrastructure
Локальный LLM

Тема локальных LLM последнее время начала развиваться, т.к. не все хотят или могут зависеть от дяди "в облаке".
Нет интернета, конфиденциальные данные, стоимость...

Но с запуском модели локально есть два препятствия - доступность хороших моделей и отсутствие мощного GPU.
С моделями подвижки есть - особенно с выкладыванием достаточно мощных моделей Qwen и DeepSeek в opensource. В общем смотри https://huggingface.co.
А вот с GPU все сложнее.
Все больше людей переходят на ноуты - как на работе, так и дома. И там видеокарта встроенная и слабая.
Что делать?
В последнее время появляются ноуты, а точнее процессоры со встроенным AI ядром.
Например: https://www.intel.com/content/www/us/en/products/sku/241751/intel-core-ultra-7-processor-255h-24m-cache-up-to-5-10-ghz/specifications.html
Чип как я понял у всех процессоров Intel пока один, называется NPU 3720.

Попробовал я запустить на таком чипе нормальную LLM - нормальную, в смысле LLM общего назначения, а не заточенную под embedding, обработку картинок или голоса...
Сразу наткнулся на ряд подводных камней:
1) широкоизвестная (в узких кругах запускателей LLM моделей) ollama NPU не поддерживает. Надеюсь, это временно, но сейчас так. Зато Intel сделал свой SDK - OpenVINO, с похожим функционалом.
Поддерживаются Windows и Ubuntu 22 https://docs.openvino.ai/2025/openvino-workflow/running-inference/inference-devices-and-modes/npu-device.html
2) в WSL, и далее Docker Desktop NPU не пробрасывается, работает только в native режиме. Я про Windows, но подозреваю проблемы и на Ubuntu

Ну ок, пробуем OpenVINO, благо на huggingface есть коллекция LLMs optimized for NPU, в документации к модели есть инструкция по запуску, например: https://huggingface.co/OpenVINO/gemma-3-4b-it-int4-cw-ov
Но и тут сплошные нюансы:
1) обязательно нужен последний драйвер от Intel, у моего кажется версия от 25.12.2025, что намекает на то, что "тема горячая". На исходной версии драйвера, поставленной Windows, запуск LLM падал с ошибкой компиляции. Об фазе активной разработки говорит раздел "Supported Features and properties" по ссылке ниже.
2) нельзя так просто взять и запустить модель на NPU (c). Требуются модели с квантизацией - это по сути сжатая модель, когда веса преобразуются из Double в Int с минимальным влиянием на точность ответа (так обещают). В случае NPU лучше даже в int4, чем в int8, цифры приведу позже.
Список моделей можно найти тут: https://docs.openvino.ai/2025/documentation/compatibility-and-support/supported-models.html или вот так https://huggingface.co/OpenVINO
3) модели с числом параметров больше 4b (4 млрд) лучше не брать. Они возможно запустятся, но время ответа уйдет за 1 минуту
4) рекомендую внимательно прочитать https://docs.openvino.ai/2025/openvino-workflow-generative/inference-with-genai/inference-with-genai-on-npu.html, оттуда станет ясно, что сейчас при запуске модели через NPU происходит долгая компиляция. Я к чему - кэширование обязательно, оно раза в 3-4 увеличивает скорость запуска. Второго и последующих естественно.
Другие опции - performance hints и AOT (Ahead of Time) компиляция пока сыроваты, а там, где они у меня завелись AOT Weightless - результат был примерно такой же, как с кэшем.
Кэш и AOT по сути являются альтернативами. AOT должен быть быстрее, но он еще сырой и требует двух запусков с разными параметрами, в то время как подключение кэша прозрачно.

Еще что интересно.
Если вернуться с списку моделей от Intel - https://docs.openvino.ai/2025/documentation/compatibility-and-support/supported-models.html, то там порядка 1000 моделей совместимы с NPU. Это сильно меньше, чем CPU\GPU, но много.
А вот если посмотреть на категорию этих моделей, то Large Language Model будет меньше чем у сотни.
Остальные - это Object Detection, Speech Recognition, Image\Video classification, Text To Speech, Natural Language Processing, Audio, Image generation, Image to Image. Вообще говоря классификация интересна сама по себе, но я бы хотел заострить внимание на том, что LLM меньше 10%.
Это говорит о том, для чего Intel делала свой чип.
1
И о главном - скорость ответа.
Тестировал на двух типах моделей, Python, OpenVINO 2025.4.1 GenAi API, Windows 11, Intel Core Ultra 7 255H:
1) анализ изображения, модель gemma-3-4b-it-int4-cw-ov, пайплайн openvino_genai.VLMPipeline
CPU 30c
CPU+cache 22c
NPU 80c
NPU+cache 25c
GPU 20c
GPU+cache 14c

2) режим чата, модель qwen2.5-1.5b-instruct-int4-ov, пайплайн openvino_genai.LLMPipeline
CPU 6c
CPU+cache 5c
NPU 40c
NPU+cache 10c
NPU+AOT 9c
GPU 9c
GPU+cache 5c

Это не полноценный бенчмарк, но пару прогонов делал.

Итог: для картинок быстрее GPU, для текста - паритет CPU и GPU. Чуда не произошло.
Но. Одним NPU ядром разгрузить 14 ядер CPU - в целом уже неплохо.
И кэширование гораздо важнее для NPU, не понимаю почему.

P.S. Интересный момент - железо сильно влияет на ответ на одной и той же модели и промте. Т.е. смысл везде похож, но текст ответа сильно отличается:

Here's what's unusual in the picture:
The cat is lying completely flat inside a cardboard box! It's a very relaxed and adorable pose for a cat, but it’s not typical behavior – cats usually prefer to be curled up or have some space around them.
Let me know if you want to analyze the picture further!

Here's what's unusual about the picture:
* **The cat is in a box!** It's not just *near* a box, but it's completely curled up and lying down *inside* a cardboard box. It’s a classic, adorable, and slightly unusual behavior for cats.
Let me know if you'd like me to elaborate on why it’s unusual!

Here's what's unusual in the picture:
* **The cat is lying in a cardboard box.** Cats are known for enjoying boxes, but it's particularly amusing to see one completely relaxed and stretched out inside one!
Let me know if you'd like to analyze another image!

Повторяемость на одном и том же типе железа при этом хорошая.

#ai #hardware
🔥1
Я вот прямо зауважал Русскую редакцию Microsoft после прочтения этой фразы в Совершенном коде Макконела.
Жаль имя переводчика не указали)

#book_review
😁7🔥1
Продолжение по Совершенному коду Макконела.

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


P.S. заметки по книге еще будут)

#book_review
😁6
AI и Совершенный код - видишь связь?)

А она есть)
Одна из важных вещей, которую "с порога" подсвечивает Макконнелл (да, оказывается двойных согласных там целых три) - собственно программирование делится на несколько этапов: детальное проектирование, кодирование и отладка, модульные и интеграционные тесты, интеграция на стенде.
Возможно даже отладку стоило бы выделить отдельно, т.к. часто по факту так и происходит. Но не суть.

Важно, что это все такие же полноправные этапы большого процесса разработки, как и сбор требований, проработка архитектуры, тестирование, сопровождение...
Особо интересно проектирование. Объем его может варьироваться - от размера проекта или итерации при Agile разработке, от детальности проработки архитектуры, но такой этап есть.
И важно о нем не забывать.

Так вот, если применять AI в разработке - забыть о проектировании становится сложнее.
Если сразу попросить агента сделать что-то - результат будет каким-то)
Даже простейшая задачка типа: "обнови Gradle wrapper" - может привести к непредсказуемому результату.
Например, агент попытается вытянуть Gradle с родного сайта, хотя это может быть запрещено политикой компании (ака кровавый enterprise).
Или обновить до такой версии, которая потребует обновления Java.
Да и заодно и обновить код под новую версию Java)
Не даром некоторые AI агенты в IDE имеют два режима - Plan и Act.

Второй важный момент - как раз тут вырисовывается водораздел: проектирование - ведет человек, возможно совместно с AI. Кодирование и отладку вполне можно оставить AI.

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

#ai #book_review
👍2
На самом деле грустная новость - Stack overflow умирает.
Окей - решения существующих проблем уже проиндексированы различными LLM, и ответы достаточно точные.

А что делать с новыми?

#ai #troubleshooting
Forwarded from /g/'s Tech Memes
RIP

StackOverflow provided data to LLMs, LLMs replaced StackOverflow, and now no new Q&A hub exists to provide fresh data
😭2
И снова к Совершенному коду)

Там есть раздел про выбор языка.

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

И в итоге язык влияет на скорость разработки, причем несколькими путями:
1) на незнакомом языке происходит замедление разработки до 30%
2) в разных языках объем полезной работы, которую в среднем производит одна строка кода, отличается. Это не только и не столько про скорость написания кода, но и про скорость чтения и понимания. Данный показатель как раз иллюстрирует табличка из поста.

Из таблицы видно, что Java никогда не была лидером по выразительности. Но надо отметить - в последние лет 10 работа над этим ведется.

Kotlin я думаю даже выше 6-ки будет.

#lang #book_review
Немного разбавлю серию про Совершенный код, но обязательно к ней вернусь)

У меня было много постов про собеседования - и по типовым вопросам, и по ошибкам, и по разным этапам (live coding, алгоритмы). Можно найти по тэгу #interview.
Появилась мысль оценить важность разных этапов интервью разработчика. IMHO конечно же)

1) code review - как по мне самый полезный этап, т.к. разработчик чаще всего приходит в существующую команду с каким-то кодом, и с этим кодом ему придется работать. Brownfield другими словами.
Этап показывает и навыки чтения кода, и практическое применение теоретических знаний при исправлении ошибок, и способность кандидата рассуждать, уверенность в своих знаниях объясняя ошибку и способ ее исправления.

2) разбор проблем\инцидентов из практики нанимающей команды. Полезно, т.к. позволяет понять понять навыка кандидата по решению проблем и "примерить" опыт кандидата на команду. А возможно - получить "инсайты" по улучшению архитектуры\кода)
Разработка - это не только лишь код, проблемы часто съедают больше времени, чем собственно работа с кодом.

3) live coding не (!) алгоритмических задач. Ну или простых алгоритмических. Позволяет понять, как кандидат подходит к решению задач, соотношение проектирование vs кодирование, и конечно как пишет код.
Не забыл он еще с AI агентом или тимлидством, как это делать?)

4) теория. Хотя многие ругают, я считаю полезной, как показатель кругозора и\или опыта. Lazy Load, индексы, как работает GC, Atomic, как работает Spring (а это важно, есть компании его запрещающие на основании того, что никто не знает до конца, как он работает).
Тут важно докручивать вопросы, чтобы этап не превратился в проверку памяти кандидата. Не так важно, сталкивался кандидат сам с проблемой или посмотрел ролик Борисова. Важно понял ли)

5) system design - с уровня Senior обязательно, но есть нюанс. Главное противоречие этого этапа - необходимость за условный час спроектировать систему. Т.е. сделать за час то, что у обычного архитектора занимает дни, возможно неделю.
Но польза конечно же есть: как кандидат задает ли кандидат вопросы, правильные ли они - показывает способность работы с бизнесом. Все ли аспекты архитектуры затронул, как рассуждает - навыки архитектуры и проектирования.
Главное не требовать спроектировать 100% системы за час) Тогда это превратится в проверку натасканности на задачу, как часто происходит алгоритмической секцией. Или с заучиванием теории.
Второе важное замечание - практическая применимость. Если собес на архитектора - окей, но даже архитектор не проектирует систему целиком по методикам system design.
Но что важно: да, эталонного сеанса system design я в реальной работе не встречал. При этом все его части сами по себе полезны для разработчика уровня Senior+

6) алгоритмическая секция - по сути это такая "олимпиада 2.0". Или тест на IQ 120+. Если пытаемся сделать команду спецназовцев от разработки - да, иначе стоит подумать над необходимостью) Главная проблема секции - на практике алгоритмы пишут единицы процентов разработчиков.

7) знакомство с ИТ лидом и\или командой - это софт-скилы, тоже важно, один в поле не воин.

#interview
👍1
И снова минутка цитат, подтверждающая мысль, что Стив (Макконнелл) умеет жечь глаголом сердца людей:

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

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


P.S. Справедливости ради отдельно обсуждается кейс mixin - классов, не являющихся самостоятельной сущностью, а лишь содержащих какой-то общеупотребительный функционал. Пример: Comparator. То, что в Java реализуется как интерфейс с методами по умолчанию. Этот вариант - ок, но здесь множественное наследование лишь средство подмешать данный функционал в класс

#book_review
Небольшое дополнение по принципу Liskov к https://t.me/javaKotlinDevOps/182

Краткое содержание предыдущей серии - основной способ нарушить это принцип в Java - сломать семантический контракт метода.

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

P.S. Это тоже Совершенный код)

#solid #book_review
Нужно ли читать чужой код?
Я не про код-ревью, а про процесс разработки.

С одной стороны я всегда топлю за то, что если есть проблемы с внешней библиотекой - не понятно, почему метод возвращает такой результат или ошибку - залезь в ее код, и посмотри.
Но Стив Макконнелл (да, снова Совершенный код) подсвечивает один интересный момент - разницу между синтаксической и семантической инкапсуляцией внутренностей класса.
С синтаксической все просто - объявил по максимуму все private и профит.
А вот семантическая, а точнее ее нарушение - это наши догадки насчет внутреннего устройства чужого класса, влияющие на наш код.
А догадки эти обычно возникают после чтения кода...
Тут еще хорошая аналогия с работой разработчика и тестировщика. Для тестировщика код - это черный ящик. А для разработчика - нет. Или все же да?)

Я для себя решил так. Если найдено неочевидное\неправильное поведение внешней библиотеки, ее автор доступен и готов к сотрудничеству - стоит по советам Стива зайти к нему и попросить поправить.
А если хотя бы одно из этих условий не выполняется - можно и нужно залезть в код. И возможно даже завязаться на его внутренние детали реализации. Да, да, я про костыль.
Но с обязательными условиями:
1) proxy слой
2) с подробным комментарием что делается и почему.
И с заведением техдолга если все же есть возможность поправить эту проблему прямым образом.

#book_review #code
👍1💯1
assert в боевом коде?

На всякий случай напомню https://docs.oracle.com/javase/8/docs/technotes/guides/language/assert.html

Пример:

Connection conn = getConnection();
assert conn != null;


Важной особенностью assert-ов является тот факт, что по умолчанию проверки, выполняемые в assert, выключены.
Для включения нужно передать опцию -ea (-enableassertions) при запуске, просто или с указанием пакета.
И как раз этот факт является одним из двух гвоздей, убивающих данную фичу.
Второй гвоздь - позиционирование assert-ов примерно такое же, как и у отладочных логов.
Это я читаю как в Совершенном коде (да, он спонсор данного поста))), так и в статье выше обсуждается как бы их удалить из кода.

Теперь на отойдем на шаг назад.
Все ошибки во входящих данных можно разделить на две категории - ожидаемые и нет.
Это деление не дискретное, а непрерывное, но в любом случае приводит к вопросу - как проверять данные на неожиданные ошибки? Нужно ли это делать вообще?
С ожидаемыми все понятно - пишем проверку, if и далее возврат кода ошибки\exception\запись в лог.
А неожиданные - что с ними делать?
Самый яркий пример - проблема nullability в Java. Объекты у нас везде, тогда в теории почти в любом методе нужна проверка на null.
Или не нужна, т.к. это сильно увеличивает объем кода и ухудшает читаемость.

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

Решением проблемы является созданием слоя валидации (или расположение валидации на сервисном слое). До того, как данные прошли этот слой считаем, что там может быть что угодно.
После - минимум проверок.
Да, часть валидации происходит в API (маппинг API в объекты), но не вся и не всегда только API является поставщиком данных.

Еще предлагаемый кейс для assert - pre-condition, post-condition, инварианты - т.е. реализация контрактов для методов и классов в коде.
Причем часто основная идея здесь не проверка условий, а именно документирование контракта с помощью assert.
И тут снова вступает в силу ненулевая вероятность удаления assert-ов, т.к. в боевом коде они выглядят чужеродно.
Я тут за JavaDoc, т.к. по JavaDoc можно построить отдельный jar с документацией, который может использовать IDE.
С контрактами есть отдельный важный момент: контракт - это часть класса, выносить его в слой валидации плохо.
Но в таком случае лучше его реализовать или обычным кодом или JavaDoc.

Итого остается редкий кейс разработки кусочка монолита, когда нет уверенности, что контракты соблюдаются. Условно разработка чего-то уровня JDK.

Используете ли assert в боевом коде? Для чего?

#book_review #contracts #validations
"Цените легкость чтения кода выше, чем удобство его написания"

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

Т.к. если не задумываться об удобстве чтения кода, то мы получаем:
1) дублирование - проще же скопировать, чем выделить новую абстракцию
2) вечный техдолг из-за не проведенного вовремя рефакторинга
3) божественные классы: пусть новый метод Y не вписывается в абстракцию класса Х, но чтобы это заметить - надо выйти за рамки текущей задачи
4) огромные иерархии классов, длинные методы - проще добавить код по аналогии
5) слабое покрытие тестами - код работает, мне он на данный момент абсолютно понятен. Зачем тесты писать - ради тестов?
6) методы и классы с неактуальными названиями
7) все методы в классе являются public - они же вызываются из public метода, да и вдруг кому-то пригодятся
8) спагетти-код
...
и получаем легаси в итоге.

#book_review
Рубрика "Загадки от Стива".

Если объект класса создается в коде всего один раз - стоит заменить такой класс объектом.
О чем речь?

Пример:
у нас есть разные виды карт: Мир, Мир Supreme, Visa Classic, Visa Digital..
Можно завести под каждый тип отдельный подкласс, но в большинстве случае достаточно параметризовать все отличия разных типов карт и просто создавать объекты одного класса.


#book_review #oop