Всем привет!
Для IntelliJ IDEA появился новый плагин - Spring Debugger.
Цель создания понятна - мир бинов типичного Spring приложения огромен и запутан. Периодически что-то ломается, возникают вопросы типа такого: "Почему (не)поднялся тот или иной бин"?
Как всегда - статья: https://habr.com/ru/companies/spring_aio/articles/924550/
И кратко то, что меня зацепило:
1) в окне Spring показывает какие из бинов не инстанцированы или заменены моком
2) во время выполнения показывает фактически значения настроек в application.properties(yml) - там где они переопределены или рассчитаны
3) при заходе в метод подсказывает, если он выполняется внутри транзакции и детали транзакции: уровень изоляции, propagation, место начала
4) там же отображает состояние JPA кэша первого уровня в реальном времени
5) REPL для Spring-контекста: в окне Threads&Variables можно искать не только локальные объекты, но и любые Spring бины из контекста, с автодополнением и вызовом методов.
6) там же можно вбить имя настройки и увидеть откуда оно считалось (главное не забыть переключить область поиска с Java на Spring Properties).
Увы, доступен только в Ultimate. Если это не препятствие - рекомендую.
P.S. Вначале создаем Spring приложения с кучей бинов, потом героически преодолеваем сложность)
#idea #ide #debug #dropapp
Для IntelliJ IDEA появился новый плагин - Spring Debugger.
Цель создания понятна - мир бинов типичного Spring приложения огромен и запутан. Периодически что-то ломается, возникают вопросы типа такого: "Почему (не)поднялся тот или иной бин"?
Как всегда - статья: https://habr.com/ru/companies/spring_aio/articles/924550/
И кратко то, что меня зацепило:
1) в окне Spring показывает какие из бинов не инстанцированы или заменены моком
2) во время выполнения показывает фактически значения настроек в application.properties(yml) - там где они переопределены или рассчитаны
3) при заходе в метод подсказывает, если он выполняется внутри транзакции и детали транзакции: уровень изоляции, propagation, место начала
4) там же отображает состояние JPA кэша первого уровня в реальном времени
5) REPL для Spring-контекста: в окне Threads&Variables можно искать не только локальные объекты, но и любые Spring бины из контекста, с автодополнением и вызовом методов.
6) там же можно вбить имя настройки и увидеть откуда оно считалось (главное не забыть переключить область поиска с Java на Spring Properties).
Увы, доступен только в Ultimate. Если это не препятствие - рекомендую.
P.S. Вначале создаем Spring приложения с кучей бинов, потом героически преодолеваем сложность)
#idea #ide #debug #dropapp
Хабр
Разбираемся со Spring Boot с помощью Spring Debugger
Команда Spring АйО перевела статью о работе со Spring Debugger и о том, как его применение существенно облегчает отладку приложений, написанных с использованием Spring Boot. На момент написания статьи...
UUID ключи в PostgreSQL
Я уже писал про версии UUID https://t.me/javaKotlinDevOps/264
Особенно интересной выглядит 7-я версия для использования в БД для построения индексов по двум причинам:
1) позволяет сортировать записи по времени создания
2) значение содержит метку времени, ее можно извлечь
Ну и эффект, наблюдаемый только в БД - записи ложатся последовательно в индексах и, соответственно, partition благодаря тому, что генерируются монотонно возрастающие значения.
Стандарт был принят в мае 2024 года https://datatracker.ietf.org/doc/rfc9562/
И не прошло и полгода (прошел год, но в мире БД это кажется даже быстро) и появляется PostgreSQL 18 c нативной поддержкой UUID v7 (функции uuidv7() и uuid_extract_timestamp) https://habr.com/ru/companies/spring_aio/articles/946168/
P.S. Если вчитаться в стандарт - попадаешь в кроличью нору:
1) для целей безопасности метка времени обрезается до миллисекунд
2) но чтобы получить возрастающие значения используется счетчик
3) счетчик инициализируется случайным числом, во избежание коллизий
4) есть защита от переполнения счетчика - допустимо использовать как счетчик ту часть метки времени, которую мы обнулили ранее, главное не перейти за границы миллисекунды. Если и этого не хватит - вопрос...
5) генератор должен хранить время t0, чтобы при переводе времени продолжать использовать исходное время и значения были уникальными и монотонно возрастающими
...
#postgresql #uuid
Я уже писал про версии UUID https://t.me/javaKotlinDevOps/264
Особенно интересной выглядит 7-я версия для использования в БД для построения индексов по двум причинам:
1) позволяет сортировать записи по времени создания
2) значение содержит метку времени, ее можно извлечь
Ну и эффект, наблюдаемый только в БД - записи ложатся последовательно в индексах и, соответственно, partition благодаря тому, что генерируются монотонно возрастающие значения.
Стандарт был принят в мае 2024 года https://datatracker.ietf.org/doc/rfc9562/
И не прошло и полгода (прошел год, но в мире БД это кажется даже быстро) и появляется PostgreSQL 18 c нативной поддержкой UUID v7 (функции uuidv7() и uuid_extract_timestamp) https://habr.com/ru/companies/spring_aio/articles/946168/
P.S. Если вчитаться в стандарт - попадаешь в кроличью нору:
1) для целей безопасности метка времени обрезается до миллисекунд
2) но чтобы получить возрастающие значения используется счетчик
3) счетчик инициализируется случайным числом, во избежание коллизий
4) есть защита от переполнения счетчика - допустимо использовать как счетчик ту часть метки времени, которую мы обнулили ранее, главное не перейти за границы миллисекунды. Если и этого не хватит - вопрос...
5) генератор должен хранить время t0, чтобы при переводе времени продолжать использовать исходное время и значения были уникальными и монотонно возрастающими
...
#postgresql #uuid
Telegram
(java || kotlin) && devOps
Всем привет!
Наверное все здесь знают, что такое UUID. Universally Unique IDentifier. Можно использовать как искусственный ключ. С высокой точностью обеспечивает уникальность, хотя и не 100%. Казалось бы, о чем здесь можно рассказывать. Ну и UUID и UUID.…
Наверное все здесь знают, что такое UUID. Universally Unique IDentifier. Можно использовать как искусственный ключ. С высокой точностью обеспечивает уникальность, хотя и не 100%. Казалось бы, о чем здесь можно рассказывать. Ну и UUID и UUID.…
👀2
Небольшая заметка.
Мы обсуждаем, как хорошо AI пишет код. Но люди его используют совсем не для этого: https://t-j.ru/news/how-people-use-chatgpt
Это я, к тому, для каких задач его будут оптимизировать.
С другой стороны: да, 4% казалось бы немного. Но если сравнить с обычным поиском, то рост раза в 2. Точных цифр по доле запросов по разработке в поисковом трафике нет, но тот же ChatGPT дает неплохую оценку исходя из числа разработчиков и среднего числа их запросов в день.
#ai
Мы обсуждаем, как хорошо AI пишет код. Но люди его используют совсем не для этого: https://t-j.ru/news/how-people-use-chatgpt
Это я, к тому, для каких задач его будут оптимизировать.
С другой стороны: да, 4% казалось бы немного. Но если сравнить с обычным поиском, то рост раза в 2. Точных цифр по доле запросов по разработке в поисковом трафике нет, но тот же ChatGPT дает неплохую оценку исходя из числа разработчиков и среднего числа их запросов в день.
#ai
Т—Ж
Как люди используют ChatGPT: главное из исследования OpenAI
Просят совета, гуглят и редактируют тексты
Как быстрее погрузиться в код?
Речь про существующий микросервис и нового разработчика.
Я уже писал, что JavaDoc (KDoc) не является обязательным для каждого метода\поля или класса (как минимум для бизнес-приложения, общие библиотеки - особый кейс), т.к. документацию никто не читает.
А что же тогда будет документацией? Например, тесты. Их конечно тоже новичок не будет читать на 100%, но во-первых их и так нужно писать, а во-вторых - при рефакторинге падающий тест покажет, что забыли поправить, а в целом любой существующий тест изменяемого класса покажет, как он работает.
А недавно я нашел еще один полезный способ задокументировать микросервис так, чтобы этой "документацией" пользовались.
Начну немного издалека. Есть такая ИТ консалтинговая компания как Thoughtworks. Ну есть и есть, где мы и где консалтинг. Но там работает такой небезызвестный человек, как Мартин Фаулер. Главный научным руководителем https://www.thoughtworks.com/profiles/leaders/martin-fowler
А это внушает некий уровень доверия.
Так вот, компания ведет реестр технологий а-ля техрадар.
И в текущей его версии есть такая штука https://www.thoughtworks.com/en-de/radar/techniques/api-request-collection-as-api-product-artifact
как коллекция API запросов как артефакт продукта.
На самом деле мысль лежит на поверхности, я уже достаточно давно практикую прихранивание запросов в формате IDEA api collection вместе с исходниками в тех проектах, над которыми приходилось работать. Да, над форматом стоит подумать отдельно, возможно Insomnia будет по-универсальнее, зависит от команды и организации. Но сама идея мне очень нравится. Такой документацией точно будут пользоваться.
P.S. Кто ее должен делать - разработчики или тестировщики и нужно ли шарить коллекцию между ними - тоже вопрос для обсуждения. В идеале - думаю, что да.
P.P.S. Да, когда я говорю про артефакт продукта - это значит мало ее сделать, ее нужно поддерживать в актуальном состоянии.
#api #onbording #documentation
Речь про существующий микросервис и нового разработчика.
Я уже писал, что JavaDoc (KDoc) не является обязательным для каждого метода\поля или класса (как минимум для бизнес-приложения, общие библиотеки - особый кейс), т.к. документацию никто не читает.
А что же тогда будет документацией? Например, тесты. Их конечно тоже новичок не будет читать на 100%, но во-первых их и так нужно писать, а во-вторых - при рефакторинге падающий тест покажет, что забыли поправить, а в целом любой существующий тест изменяемого класса покажет, как он работает.
А недавно я нашел еще один полезный способ задокументировать микросервис так, чтобы этой "документацией" пользовались.
Начну немного издалека. Есть такая ИТ консалтинговая компания как Thoughtworks. Ну есть и есть, где мы и где консалтинг. Но там работает такой небезызвестный человек, как Мартин Фаулер. Главный научным руководителем https://www.thoughtworks.com/profiles/leaders/martin-fowler
А это внушает некий уровень доверия.
Так вот, компания ведет реестр технологий а-ля техрадар.
И в текущей его версии есть такая штука https://www.thoughtworks.com/en-de/radar/techniques/api-request-collection-as-api-product-artifact
как коллекция API запросов как артефакт продукта.
На самом деле мысль лежит на поверхности, я уже достаточно давно практикую прихранивание запросов в формате IDEA api collection вместе с исходниками в тех проектах, над которыми приходилось работать. Да, над форматом стоит подумать отдельно, возможно Insomnia будет по-универсальнее, зависит от команды и организации. Но сама идея мне очень нравится. Такой документацией точно будут пользоваться.
P.S. Кто ее должен делать - разработчики или тестировщики и нужно ли шарить коллекцию между ними - тоже вопрос для обсуждения. В идеале - думаю, что да.
P.P.S. Да, когда я говорю про артефакт продукта - это значит мало ее сделать, ее нужно поддерживать в актуальном состоянии.
#api #onbording #documentation
Thoughtworks
Martin Fowler
Martin Fowler, Chief Scientist and Agile pioneer at Thoughtworks—author of key software architecture works. Learn more.
🔥1
Основные проблемы AI в разработке.
Я вижу две основные проблемы.
Первая - принципиально недетерминированный ответ как отражение вероятностной природы LLM. Если в креативных задачах это плюс, но в разработке скорее минус.
Вторая - естественный язык не самое лучшее API из-за своей неоднозначности.
И для второй, а частично и для первой проблемы есть решение - паттерн structured output. Суть проста - мы говорим модели, в каком виде хотели бы получить ответ. Это может быть JSON схема или класс Response. Базовый формат - JSON, но он на уровне библиотеки легко трансформируется в класс для большинства языков программирования. Ключевой момент - вызов модели должен вернуть правильный по структуре JSON с вероятностью 100%. И далее его можно или без лишних проверок парсить и передавать на вход следующему методу.
Реализован паттерн должен быть в самой модели, так как на уровне библиотеки или промта гарантии 100% соответствия получить нельзя.
Вот статья с примером использования:
https://habr.com/ru/articles/923096
P.S. Паттерны есть везде, коллекция AI паттернов постепенно растёт)
#ai #llm
Я вижу две основные проблемы.
Первая - принципиально недетерминированный ответ как отражение вероятностной природы LLM. Если в креативных задачах это плюс, но в разработке скорее минус.
Вторая - естественный язык не самое лучшее API из-за своей неоднозначности.
И для второй, а частично и для первой проблемы есть решение - паттерн structured output. Суть проста - мы говорим модели, в каком виде хотели бы получить ответ. Это может быть JSON схема или класс Response. Базовый формат - JSON, но он на уровне библиотеки легко трансформируется в класс для большинства языков программирования. Ключевой момент - вызов модели должен вернуть правильный по структуре JSON с вероятностью 100%. И далее его можно или без лишних проверок парсить и передавать на вход следующему методу.
Реализован паттерн должен быть в самой модели, так как на уровне библиотеки или промта гарантии 100% соответствия получить нельзя.
Вот статья с примером использования:
https://habr.com/ru/articles/923096
P.S. Паттерны есть везде, коллекция AI паттернов постепенно растёт)
#ai #llm
Хабр
Structured Output как полноценная замена Function Calling
В этой статье мы рассмотрим альтернативный подход вызова инструментов LLM, который использует Structured Output вместо традиционного Function Calling для обеспечения надежности...
RestTemplate is dead, baby)))
Spring наконец-то решили задепрекейтить RestTemplate.
Пруф: https://spring.io/blog/2025/09/30/the-state-of-http-clients-in-spring
Его замены в fluent стиле: RestClient для синхронного и WebCLient для асинхронного взаимодействия.
Видимо, команда Spring таки выпилила его из компонентов фреймворка и теперь предлагает это сделать всем остальным)
На самом деле я немного добавил сенсационности в пост.
А реальная хронология событий планируется такая:
- в ноябре этого года (Spring 7.0) будет объявлено о том, что компонент deprecated
- формально deprecated он станет в ноябре 2026 года (Spring 7.1)
- выпилят в Spring 8.0 где-то в 27 году.
Это мир Java == мир обратной совместимости)
#spring #web
Spring наконец-то решили задепрекейтить RestTemplate.
Пруф: https://spring.io/blog/2025/09/30/the-state-of-http-clients-in-spring
Его замены в fluent стиле: RestClient для синхронного и WebCLient для асинхронного взаимодействия.
Видимо, команда Spring таки выпилила его из компонентов фреймворка и теперь предлагает это сделать всем остальным)
На самом деле я немного добавил сенсационности в пост.
А реальная хронология событий планируется такая:
- в ноябре этого года (Spring 7.0) будет объявлено о том, что компонент deprecated
- формально deprecated он станет в ноябре 2026 года (Spring 7.1)
- выпилят в Spring 8.0 где-то в 27 году.
Это мир Java == мир обратной совместимости)
#spring #web
The state of HTTP clients in Spring
Level up your Java code and explore what Spring can do for you.
👍2
Языки программирования общего назначения?
Java, Python, C, Go. Формально, технически - да, все это универсальные языки, которые можно применять в любой, задача. А фактически?
Говорим Python - подразумеваем Data Science, ML и AI.
Go захватил разработку крипты. Плюс операторы в k8s.
Kotlin - от 70 до 90% приложений в Google Play (топовых приложений если быть точным, т.к. есть "хвост" легаси)
Похожая картина у Swift - примерно 60% в iOS (доля бинпрников в iOS 17).
C# - нативные Windows приложения (Delphi и VB.NET эту битву проиграли).
Groovy нашел свою нишу в Jenkins как DSL (Gradle еще, но там его теснит Kotlin, да и не должны Gradle скрипты быть большими).
Lua - язык плагинов (Nginx, Tarantool) и скриптовый язык для игр. То бишь - король DSL.
Драйвера пишут на C (до сих пор ли? Раньше так было).
Да, экосистема (библиотеки, фреймворки, документация, сообщество) рулит)
И вопрос - что я забыл?
#lang
Java, Python, C, Go. Формально, технически - да, все это универсальные языки, которые можно применять в любой, задача. А фактически?
Говорим Python - подразумеваем Data Science, ML и AI.
Go захватил разработку крипты. Плюс операторы в k8s.
Kotlin - от 70 до 90% приложений в Google Play (топовых приложений если быть точным, т.к. есть "хвост" легаси)
Похожая картина у Swift - примерно 60% в iOS (доля бинпрников в iOS 17).
C# - нативные Windows приложения (Delphi и VB.NET эту битву проиграли).
Groovy нашел свою нишу в Jenkins как DSL (Gradle еще, но там его теснит Kotlin, да и не должны Gradle скрипты быть большими).
Lua - язык плагинов (Nginx, Tarantool) и скриптовый язык для игр. То бишь - король DSL.
Драйвера пишут на C (до сих пор ли? Раньше так было).
Да, экосистема (библиотеки, фреймворки, документация, сообщество) рулит)
И вопрос - что я забыл?
#lang
Небольшой забавный (и при этом грустный) факт о JVM.
Для запуска Hello world приложения на Java JVM загружает 450 классов.
Пруф: https://inside.java/2025/01/28/jvm-start-up/
#jvm #fun_facts
Для запуска Hello world приложения на Java JVM загружает 450 классов.
Пруф: https://inside.java/2025/01/28/jvm-start-up/
#jvm #fun_facts
inside.java
A Deep Dive into JVM Start-up
A deep-dive into all the processes and work the JVM performs on start-up.
😱4
Если IDEA легла при старте. Или mini IDEA troobleshooting guide.
Что можно сделать?
Вариант номер ноль - обругать нехорошими словами разработчиков IDE и откатиться на предыдущую версию. Хотя, разработчики IDE могут быть не виноваты, о чем ниже)
Если вас этот вариант не устраивает - вот на что стоит обратить внимание.
Предусловие - надо вспомнить где у вас хранятся настройки IDEA. По умолчанию на примере Windows это %USERDATA%\AppData\Local\xxx\yyy, xxx - это JetBrains\GIGAIDE\..., а yyy - имя IDE.
Но через idea.properties это место можно переопределить.
И так.
1) Логи. По умолчанию лежат в %USERDATA%\AppData\Local\xxx\yyy\log\idea.log
В логах стоит обратить внимание на исключения. Как ни странно, искать их надо по SEVERE, а не ERROR
Возможно из исключения будет сразу понятна причина.
2) Плагины. Часто в исключении есть какие-то классы, но за что они отвечают - не ясно. Но если перед исключением есть строчка
Plugin to blame: xxx,
то предполагаемый виновник найден.
Очень часто это новый плагин или его новая версия.
Его надо отключить. Но IDE не стартует, и настройки в UI недоступны.
Не беда - внешние плагины можно отключить удалив соответствующую папку из %USERDATA%\AppData\Roaming\xxx\yyy\plugins.
Бывают сбои и во встроенных (bundled) плагинах, поэтому есть второй способ: добавить id плагина в файл %USERDATA%\AppData\Roaming\xxx\yyy\disabled_plugins.txt
Важно - id, а не имя. id это по сути grouId артифакта, найти его можно в логе.
3) Текущий проект. У меня были кейсы, когда даже с плагином с утечкой памяти, сжирающим 6, 8, 16 Гб - т.е. все что дадут - удавалось запустить IDE открыв пустой проект. Но IDEA по умолчанию открывает последние проекты. Вариант решения - переименовать папку, чтобы она их не нашла.
4) Опции запуска. https://www.jetbrains.com/help/idea/working-with-the-ide-features-from-command-line.html#arguments
Могут помочь решить проблему следующие:
а) disableNonBundledPlugins - запуск IDE без внешних плагинов
б) dontReopenProjects - более элегантный вариант открыть IDEA без последних проектов
5) Память. Если в логах есть OutOfMemoryError - можно попробовать увеличить Heap для IDEA. Почему можно попробовать - потому что это не панацея, при утечке памяти не поможет.
Второй вопрос - как увеличить? Через idea64.exe.vmoptions.
А если не хватает прав его поправить?
Есть его "профильный" (лежащий в профиле пользователя) двойник %USERDATA%\AppData\Roaming\xxx\yyy\idea64.exe.vmoptions.
Рекомендую использовать его, особенно если у вас настройки IDEA в кастомной папке, не меняющейся от версии к версии.
6) thread dump и heap dump. Больше помогут разрабам IDE, но глянуть можно.
Создаются в двух случаях.
а) При каждом зависании (freeze) создаются в %USERDATA%\AppData\Local\xxx\yyy\log\threadDumps-freeze-zzz
б) при OutOfMemory с включенной опцией -XX:+HeapDumpOnOutOfMemoryError (а в idea64.exe.vmoptions она по умолчанию есть) в %USERDATA% создается heapdump и лог, включающий threaddumps
На сегодня все, если найду еще интересные лайфхаки - сделаю новый пост.
#idea #ide #troubleshooting
Что можно сделать?
Вариант номер ноль - обругать нехорошими словами разработчиков IDE и откатиться на предыдущую версию. Хотя, разработчики IDE могут быть не виноваты, о чем ниже)
Если вас этот вариант не устраивает - вот на что стоит обратить внимание.
Предусловие - надо вспомнить где у вас хранятся настройки IDEA. По умолчанию на примере Windows это %USERDATA%\AppData\Local\xxx\yyy, xxx - это JetBrains\GIGAIDE\..., а yyy - имя IDE.
Но через idea.properties это место можно переопределить.
И так.
1) Логи. По умолчанию лежат в %USERDATA%\AppData\Local\xxx\yyy\log\idea.log
В логах стоит обратить внимание на исключения. Как ни странно, искать их надо по SEVERE, а не ERROR
Возможно из исключения будет сразу понятна причина.
2) Плагины. Часто в исключении есть какие-то классы, но за что они отвечают - не ясно. Но если перед исключением есть строчка
Plugin to blame: xxx,
то предполагаемый виновник найден.
Очень часто это новый плагин или его новая версия.
Его надо отключить. Но IDE не стартует, и настройки в UI недоступны.
Не беда - внешние плагины можно отключить удалив соответствующую папку из %USERDATA%\AppData\Roaming\xxx\yyy\plugins.
Бывают сбои и во встроенных (bundled) плагинах, поэтому есть второй способ: добавить id плагина в файл %USERDATA%\AppData\Roaming\xxx\yyy\disabled_plugins.txt
Важно - id, а не имя. id это по сути grouId артифакта, найти его можно в логе.
3) Текущий проект. У меня были кейсы, когда даже с плагином с утечкой памяти, сжирающим 6, 8, 16 Гб - т.е. все что дадут - удавалось запустить IDE открыв пустой проект. Но IDEA по умолчанию открывает последние проекты. Вариант решения - переименовать папку, чтобы она их не нашла.
4) Опции запуска. https://www.jetbrains.com/help/idea/working-with-the-ide-features-from-command-line.html#arguments
Могут помочь решить проблему следующие:
а) disableNonBundledPlugins - запуск IDE без внешних плагинов
б) dontReopenProjects - более элегантный вариант открыть IDEA без последних проектов
5) Память. Если в логах есть OutOfMemoryError - можно попробовать увеличить Heap для IDEA. Почему можно попробовать - потому что это не панацея, при утечке памяти не поможет.
Второй вопрос - как увеличить? Через idea64.exe.vmoptions.
А если не хватает прав его поправить?
Есть его "профильный" (лежащий в профиле пользователя) двойник %USERDATA%\AppData\Roaming\xxx\yyy\idea64.exe.vmoptions.
Рекомендую использовать его, особенно если у вас настройки IDEA в кастомной папке, не меняющейся от версии к версии.
6) thread dump и heap dump. Больше помогут разрабам IDE, но глянуть можно.
Создаются в двух случаях.
а) При каждом зависании (freeze) создаются в %USERDATA%\AppData\Local\xxx\yyy\log\threadDumps-freeze-zzz
б) при OutOfMemory с включенной опцией -XX:+HeapDumpOnOutOfMemoryError (а в idea64.exe.vmoptions она по умолчанию есть) в %USERDATA% создается heapdump и лог, включающий threaddumps
На сегодня все, если найду еще интересные лайфхаки - сделаю новый пост.
#idea #ide #troubleshooting
IntelliJ IDEA Help
Command-line interface | IntelliJ IDEA
👍2
Минутка философии на канале)
На тему AI конечно же)
Вопрос - не является ли массовое внедрение AI сейчас (причем со словами везде и надо еще вчера) временным хайпом?
Ответ - даже если и является, очень может быть, что является, AI из разработки уже не уйдет. Как не ушли Agile, DevOps, микросервисы.
Почему - потому что уже на текущем уровне инструмент позволяет автоматизировать рутину малой кровью. Не все модели, не любые задачи - но рабочие кейсы есть. Описание чужого кода, типовой код (маппинг), каркас приложения, базовый набор тестов, замена поиска... И их будет больше.
Вывод - изучать надо)
#ai
На тему AI конечно же)
Вопрос - не является ли массовое внедрение AI сейчас (причем со словами везде и надо еще вчера) временным хайпом?
Ответ - даже если и является, очень может быть, что является, AI из разработки уже не уйдет. Как не ушли Agile, DevOps, микросервисы.
Почему - потому что уже на текущем уровне инструмент позволяет автоматизировать рутину малой кровью. Не все модели, не любые задачи - но рабочие кейсы есть. Описание чужого кода, типовой код (маппинг), каркас приложения, базовый набор тестов, замена поиска... И их будет больше.
Вывод - изучать надо)
#ai
👍3💯2
Новая LTS Java.
Я о Java 25.
Вышла не вчера, поэтому также вышла и хорошая статья с обзором нововведений https://habr.com/ru/companies/T1Holding/articles/946778/.
Там даже табличка включения новых фич от 21 до 25 версии есть. И примеры кода - было\стало.
И от меня как всегда пару комментариев)
Для начала бросаются в глаза две фичи со "странным" названием Quantum-Resistant ...
Почему бросаются - квантовые компьютеры ожидаются в промышленном использовании в течение 10+ лет, а устойчивые к взлому квантовым компьютером алгоритмы в Java появились уже сейчас.
С - стратегия.
Б - банковское ПО)
Три фичи со словами Ahead-of-Time, главная из них - Ahead-of-Time Class Loading & Linking.
Это дальнейшее развитие темы CDS https://t.me/javaKotlinDevOps/316
Т.е. ускорение старта приложения.
Если CDS убирает этап верификации классов сохраняя в архиве уже проверенные классы,
то Ahead-of-Time Class Loading & Linking как следует из названия сохраняет всю необходимую для работы с классами информацию. Так сказать в распакованном виде, поэтому ее сразу можно грузить в Metaspace.
Одно но: набор классов у всех разный, поэтому нужно запустить приложение в тестовом режиме и собрать данные по актуальным классам, которые и будут сохранены в архиве.
Заодно сохраняется и статистика их использования (Ahead-of-Time Method Profiling), что позволяет при старте JVM сразу запустить компиляцию часто используемых методов.
Последняя фича - это offline Profile-Guided Optimization https://t.me/javaKotlinDevOps/315, которая ранее была killer feature коммерческих JVM: Azul ReadyNow и GraalVM Enterprise Native Image.
Итоговое ускорение загрузки: 42% vs 33% у CDS https://www.happycoders.eu/java/ahead-of-time-class-loading-and-linking/
Есть еще две оптимизационные фичи: Compact Object Headers и Linking Run-Time Images without JMODs.
Первая уменьшает размер любого объекта в памяти, оптимизируя заголовки. Вторая - уменьшает объем JDK, убирая оттуда JMOD файлы. JMOD появились вместе с модулями Java как развитие jar.
И классы в jmod файлах уже есть в JDK, т.е. имеем дублирование. Сейчас его убрали, размер JDK стал меньше на 25%. Важно в облаках с тысячами микросервисов.
На самом деле технология модулей в Java до сих пор не прижилась в коммерческой разработке, но команда Java не сдается)
Module Import Declarations - можно разом импортировать все классы в модуле. С одной стороны загрязняется область видимости, с другой - удобно.
Markdown Documentation Comments: Markdown - стандарт документации в ИТ в целом, получаем больше возможностей в JavaDoc. Да, JavaDoc нужны не всегда, но пригодится.
Фичи с JFR в названии - допилен профайлер: меньше влияние на исполнение кода (JFR Cooperative Sampling), больше данных (JFR Method Timing & Tracing).
Unnamed Variables & Patterns: _ (подчеркивание) обозначает для компилятора и валидаторов неиспользуемую переменную. Java пополнила длинный список языков, где это уже есть)
Scoped Values - более безопасный вариант Thread Local.
Также дошли до prod ready версии фичи из моего поста про Java 22 https://t.me/javaKotlinDevOps/278
* Launch Multi-File Source-Code Programs
* Implicitly Declared Classes and Instance Main Methods
* Stream Gatherers
* Class-File API
* Statements before super
Итого - решаются проблемы с производительностью и объемом, допиливается функционал (стримы, модули, JFR, Thread Local, GC), стандартизируются API (Class-File API), немного синтаксического сахара (_).
А String templates https://t.me/javaKotlinDevOps/246 выкинули. Слишком отличается от мэйнстрима, я про идею процессора STR."xxx", обрабатывающего строки
#java #jdk #java_new_version
Я о Java 25.
Вышла не вчера, поэтому также вышла и хорошая статья с обзором нововведений https://habr.com/ru/companies/T1Holding/articles/946778/.
Там даже табличка включения новых фич от 21 до 25 версии есть. И примеры кода - было\стало.
И от меня как всегда пару комментариев)
Для начала бросаются в глаза две фичи со "странным" названием Quantum-Resistant ...
Почему бросаются - квантовые компьютеры ожидаются в промышленном использовании в течение 10+ лет, а устойчивые к взлому квантовым компьютером алгоритмы в Java появились уже сейчас.
С - стратегия.
Б - банковское ПО)
Три фичи со словами Ahead-of-Time, главная из них - Ahead-of-Time Class Loading & Linking.
Это дальнейшее развитие темы CDS https://t.me/javaKotlinDevOps/316
Т.е. ускорение старта приложения.
Если CDS убирает этап верификации классов сохраняя в архиве уже проверенные классы,
то Ahead-of-Time Class Loading & Linking как следует из названия сохраняет всю необходимую для работы с классами информацию. Так сказать в распакованном виде, поэтому ее сразу можно грузить в Metaspace.
Одно но: набор классов у всех разный, поэтому нужно запустить приложение в тестовом режиме и собрать данные по актуальным классам, которые и будут сохранены в архиве.
Заодно сохраняется и статистика их использования (Ahead-of-Time Method Profiling), что позволяет при старте JVM сразу запустить компиляцию часто используемых методов.
Последняя фича - это offline Profile-Guided Optimization https://t.me/javaKotlinDevOps/315, которая ранее была killer feature коммерческих JVM: Azul ReadyNow и GraalVM Enterprise Native Image.
Итоговое ускорение загрузки: 42% vs 33% у CDS https://www.happycoders.eu/java/ahead-of-time-class-loading-and-linking/
Есть еще две оптимизационные фичи: Compact Object Headers и Linking Run-Time Images without JMODs.
Первая уменьшает размер любого объекта в памяти, оптимизируя заголовки. Вторая - уменьшает объем JDK, убирая оттуда JMOD файлы. JMOD появились вместе с модулями Java как развитие jar.
И классы в jmod файлах уже есть в JDK, т.е. имеем дублирование. Сейчас его убрали, размер JDK стал меньше на 25%. Важно в облаках с тысячами микросервисов.
На самом деле технология модулей в Java до сих пор не прижилась в коммерческой разработке, но команда Java не сдается)
Module Import Declarations - можно разом импортировать все классы в модуле. С одной стороны загрязняется область видимости, с другой - удобно.
Markdown Documentation Comments: Markdown - стандарт документации в ИТ в целом, получаем больше возможностей в JavaDoc. Да, JavaDoc нужны не всегда, но пригодится.
Фичи с JFR в названии - допилен профайлер: меньше влияние на исполнение кода (JFR Cooperative Sampling), больше данных (JFR Method Timing & Tracing).
Unnamed Variables & Patterns: _ (подчеркивание) обозначает для компилятора и валидаторов неиспользуемую переменную. Java пополнила длинный список языков, где это уже есть)
Scoped Values - более безопасный вариант Thread Local.
Также дошли до prod ready версии фичи из моего поста про Java 22 https://t.me/javaKotlinDevOps/278
* Launch Multi-File Source-Code Programs
* Implicitly Declared Classes and Instance Main Methods
* Stream Gatherers
* Class-File API
* Statements before super
Итого - решаются проблемы с производительностью и объемом, допиливается функционал (стримы, модули, JFR, Thread Local, GC), стандартизируются API (Class-File API), немного синтаксического сахара (_).
А String templates https://t.me/javaKotlinDevOps/246 выкинули. Слишком отличается от мэйнстрима, я про идею процессора STR."xxx", обрабатывающего строки
#java #jdk #java_new_version
Хабр
Возвращение LTS: ты не пройдёшь… мимо новых фич Java 25
В одной из моих предыдущих статей я писал о фичах между LTS-версиями Java 17 и 21 . Сегодня, два года спустя ( Как?! Уже два года?! ), выходит новый LTS-релиз — Java 25 . Подавляющее большинство...
Серия: "Хозяйке на заметку" про PostgreSQL.
А точнее про создание индексов.
Вроде все просто.
Но есть ряд интересных опций.
1) CONCURRENTLY
Получается так:
Когда нужно - всегда если накат идет на активное плечо ПРОМа. Опция не блокирует изменение таблицы пользователя. Минусы: команда выполняется дольше.
2) INCLUDE
Известно, что чтение значения индекса работает быстрее, т.к. это значение хранится в индексе, не нужно ходить в таблицу. Но кроме того в индекс можно положить любые другие значения из записи таблицы. Можно, но осторожно, т.к. это в любом случае дублирование данных. Эффект надо подтверждать на НТ.
Получаем:
3) WHERE
Позволяет поместить в индекс не все значения столбца, имеющиеся в таблице.
Решает следующие кейсы:
а) низкая селективность индекса: выбирает только значения с высокой селективностью
б) экономия места в памяти (и возможно в каких-то случаях на диске): выбираем в индекс только необходимое
в) частичная уникальность: если нужен уникальный индекс, но он соблюдается не для всех значений.
Выглядит так:
P.S. Еще есть интересная опция USING, позволяющая использовать разные типы индексов (по умолчанию в PostgreSQL используется btree), но это отдельная тема)
Детали в официальной документации https://www.postgresql.org/docs/current/sql-createindex.html
#postgresql #db #performance
А точнее про создание индексов.
CREATE INDEX table_idx ON books (title)
Вроде все просто.
Но есть ряд интересных опций.
1) CONCURRENTLY
Получается так:
CREATE INDEX CONCURRENTLY table_idx ON books (title)
Когда нужно - всегда если накат идет на активное плечо ПРОМа. Опция не блокирует изменение таблицы пользователя. Минусы: команда выполняется дольше.
2) INCLUDE
Известно, что чтение значения индекса работает быстрее, т.к. это значение хранится в индексе, не нужно ходить в таблицу. Но кроме того в индекс можно положить любые другие значения из записи таблицы. Можно, но осторожно, т.к. это в любом случае дублирование данных. Эффект надо подтверждать на НТ.
Получаем:
CREATE INDEX table_idx ON books (title) INCLUDE (isbn)
3) WHERE
Позволяет поместить в индекс не все значения столбца, имеющиеся в таблице.
Решает следующие кейсы:
а) низкая селективность индекса: выбирает только значения с высокой селективностью
б) экономия места в памяти (и возможно в каких-то случаях на диске): выбираем в индекс только необходимое
в) частичная уникальность: если нужен уникальный индекс, но он соблюдается не для всех значений.
Выглядит так:
CREATE INDEX table_idx ON books (title) WHERE country = 'Russia'
P.S. Еще есть интересная опция USING, позволяющая использовать разные типы индексов (по умолчанию в PostgreSQL используется btree), но это отдельная тема)
Детали в официальной документации https://www.postgresql.org/docs/current/sql-createindex.html
#postgresql #db #performance
PostgreSQL Documentation
CREATE INDEX
CREATE INDEX CREATE INDEX — define a new index Synopsis CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ …
❤4
Рубрика "Виртуальные споры с Бугаенко")))
Егор любит провокативные посты, причём всегда (почти всегда?) в таких постах есть здравая мысль, заставляющая задуматься о том, как я пишу код. И этим они хороши)
Сейчас набрел на 2 поста о переменных:
https://www.yegor256.com/2015/01/12/compound-name-is-code-smell.html
https://www.yegor256.com/2015/09/01/redundant-variables-are-evil.html
Краткое содержание первого: составные имена переменных - типа flieName - это code smell. Аргумент - если имя пришлось сделать из 2+ слов, то это значит у нам слишком большая область видимости и нарушение Single Responsibility.
Тут в целом да. Я за небольшие методы, компилятор их оптимизирует. И такой критерий простоты метода как простые имена переменных - не очевидно, не единственный, но красиво.
А вот если говорить про имена полей класса, то тут скорее нет. Да, к классам тоже применим Single Responsibility, да, в имени поля не должно повторяться имя класса. Но видится, что строгое следование данному правилу усугубит "ООП-болезнь" - бесконечное дробление классов. А так мы отходим от структуры предметной области и усложняем чтение кода из-за прыжков между файлами. Вспомним, что разработка - искусство компромиссов)
Второй пост о том, что вынесение результата выполнения строчки кода в одноразовую локальную переменную - зло. Т.к. появляется 2+ строчки вместо одной, и ухудшается читаемость.
С одной стороны да. Но если у нас есть вызов метода, он уже достаточно сложный, а расчёт значений его параметров увеличивает длину строки кода до 100, 200... символов?
Да, можно выделить часть кода в отдельные методы. Методы тоже одноразовые...
А тогда какая разница?
Поэтому я бы сказал так: автоматом выносить все расчитываемые знпченич в переменные точно не надо.
Но и обратное не верно. Иногда такой приём улучшает читаемость, и в этом случае оправдан. Снова компромиссы)))
#clean_code #dev_compromises
Егор любит провокативные посты, причём всегда (почти всегда?) в таких постах есть здравая мысль, заставляющая задуматься о том, как я пишу код. И этим они хороши)
Сейчас набрел на 2 поста о переменных:
https://www.yegor256.com/2015/01/12/compound-name-is-code-smell.html
https://www.yegor256.com/2015/09/01/redundant-variables-are-evil.html
Краткое содержание первого: составные имена переменных - типа flieName - это code smell. Аргумент - если имя пришлось сделать из 2+ слов, то это значит у нам слишком большая область видимости и нарушение Single Responsibility.
Тут в целом да. Я за небольшие методы, компилятор их оптимизирует. И такой критерий простоты метода как простые имена переменных - не очевидно, не единственный, но красиво.
А вот если говорить про имена полей класса, то тут скорее нет. Да, к классам тоже применим Single Responsibility, да, в имени поля не должно повторяться имя класса. Но видится, что строгое следование данному правилу усугубит "ООП-болезнь" - бесконечное дробление классов. А так мы отходим от структуры предметной области и усложняем чтение кода из-за прыжков между файлами. Вспомним, что разработка - искусство компромиссов)
Второй пост о том, что вынесение результата выполнения строчки кода в одноразовую локальную переменную - зло. Т.к. появляется 2+ строчки вместо одной, и ухудшается читаемость.
С одной стороны да. Но если у нас есть вызов метода, он уже достаточно сложный, а расчёт значений его параметров увеличивает длину строки кода до 100, 200... символов?
Да, можно выделить часть кода в отдельные методы. Методы тоже одноразовые...
А тогда какая разница?
Поэтому я бы сказал так: автоматом выносить все расчитываемые знпченич в переменные точно не надо.
Но и обратное не верно. Иногда такой приём улучшает читаемость, и в этом случае оправдан. Снова компромиссы)))
#clean_code #dev_compromises
Yegor Bugayenko
A Compound Name Is a Code Smell
A variable name that consists of several words is a code smell because it indicates a variable scope that's too big.
Снова про индексы.
Пост навеян вот этой статьей: https://vladmihalcea.com/index-selectivity/
Рекомендую прочитать, она короткая.
Многие знают про селективность индексов. На собесах в ответ на вопрос: на какие поля нужно делать индексы - я часто слышу про низкую селективность.
Суть в том, что если в колонке значения сильно не уникальные - хорошие примеры это boolean и enum - то индекс делать не надо.
Вообще говоря да, это так. Ответ верный.
Но есть нюанс. Полный ответ такой. Проблема такого индекса не в том, что БД будет неэффективно работать. БД после первого же запроса с использованием индекса поймет, что его стоимость выше, чем у full scan. И переключит все оставшиеся запросы на full scan.
А вот в чем мы точно проиграем - индекс съест место на диске и замедлит вставку. И что более важно: введет в заблуждение разработчика, т.к. создавая индекс он очевидно хочет решить с помощью него какую-то проблему (потенциальную?) с производительностью. А индекс по факту просто не работает.
P.S. И да, если по каким-то значениям в столбце селективность хорошая - поможет частичный индекс (WHERE в индексе).
P.P.S Сломать БД сложнее, чем кажется) Но все в ваших руках) И быстрее это можно сделать отсутствием нужно индекса, чем лишним индексом.
#db #performance
Пост навеян вот этой статьей: https://vladmihalcea.com/index-selectivity/
Рекомендую прочитать, она короткая.
Многие знают про селективность индексов. На собесах в ответ на вопрос: на какие поля нужно делать индексы - я часто слышу про низкую селективность.
Суть в том, что если в колонке значения сильно не уникальные - хорошие примеры это boolean и enum - то индекс делать не надо.
Вообще говоря да, это так. Ответ верный.
Но есть нюанс. Полный ответ такой. Проблема такого индекса не в том, что БД будет неэффективно работать. БД после первого же запроса с использованием индекса поймет, что его стоимость выше, чем у full scan. И переключит все оставшиеся запросы на full scan.
А вот в чем мы точно проиграем - индекс съест место на диске и замедлит вставку. И что более важно: введет в заблуждение разработчика, т.к. создавая индекс он очевидно хочет решить с помощью него какую-то проблему (потенциальную?) с производительностью. А индекс по факту просто не работает.
P.S. И да, если по каким-то значениям в столбце селективность хорошая - поможет частичный индекс (WHERE в индексе).
P.P.S Сломать БД сложнее, чем кажется) Но все в ваших руках) И быстрее это можно сделать отсутствием нужно индекса, чем лишним индексом.
#db #performance
Vlad Mihalcea
Index Selectivity - Vlad Mihalcea
Learn how Index Selectivity works in a relational database system and why using an index works best for high selectivity values.
Регулярная рубрика - новости AI.
Нашел очередную статью про RAG https://habr.com/ru/companies/raft/articles/954158/
Казалось бы, нашел и нашел.
Но что интересно.
Вот есть AI. AI агент для примера.
Он общается с LLM.
LLM бывают разные.
Можно прикрутить AI proxy для совместимости по API.
А еще есть разные фреймворки для построения агентов.
Агент вызывает какие-то тулы.
Или MCP сервера по некому стандартизированному протоколу.
Или другого агента, для этого тоже есть стандартизированные протоколы.
Как источник домен-специфичных данных агент использует RAG.
RAG - это векторное хранилище, они бывают разные. Как специализированные, так и в виде расширения того же PotgreSQL.
Плюс есть технология преобразования данных (текстовых как правило, но не только) в векторный формат (embedding). Это тоже разные специализированные модели (но не те модели, что обрабатывают запрос пользователя).
Плюс есть технология разбиения данных на части (chunks), т.к. поиск по RAG - это сравнение векторов. Поэтому размер вектора для сравнения должен быть конечен, а документы в теории могут весить многие мегабайты.
Так вот. Даже для разбиения докумнетов на chunks уже появилось несколько конкурирующих библиотек, про это статья в начале поста.
О чем это говорит? Растет экосистема. Т.е. технология LLM потихоньку приходит к своей зрелости.
P.S. И поспорю сам с собой: за этот год по словам компетентных людей (я только учусь) сменилось три (!) принципа построения AI агентов.
#ai #rag
Нашел очередную статью про RAG https://habr.com/ru/companies/raft/articles/954158/
Казалось бы, нашел и нашел.
Но что интересно.
Вот есть AI. AI агент для примера.
Он общается с LLM.
LLM бывают разные.
Можно прикрутить AI proxy для совместимости по API.
А еще есть разные фреймворки для построения агентов.
Агент вызывает какие-то тулы.
Или MCP сервера по некому стандартизированному протоколу.
Или другого агента, для этого тоже есть стандартизированные протоколы.
Как источник домен-специфичных данных агент использует RAG.
RAG - это векторное хранилище, они бывают разные. Как специализированные, так и в виде расширения того же PotgreSQL.
Плюс есть технология преобразования данных (текстовых как правило, но не только) в векторный формат (embedding). Это тоже разные специализированные модели (но не те модели, что обрабатывают запрос пользователя).
Плюс есть технология разбиения данных на части (chunks), т.к. поиск по RAG - это сравнение векторов. Поэтому размер вектора для сравнения должен быть конечен, а документы в теории могут весить многие мегабайты.
Так вот. Даже для разбиения докумнетов на chunks уже появилось несколько конкурирующих библиотек, про это статья в начале поста.
О чем это говорит? Растет экосистема. Т.е. технология LLM потихоньку приходит к своей зрелости.
P.S. И поспорю сам с собой: за этот год по словам компетентных людей (я только учусь) сменилось три (!) принципа построения AI агентов.
#ai #rag
Хабр
Chonkie: революция в RAG-чанкинге — скорость, лёгкость, удобство
В эпоху, когда большие языковые модели (LLM) становятся всё более мощными и применяются во многих задачах, одна из ключевых проблем остаётся прежней — как эффективно снабжать их релевантным...
LLM как серебряная пуля?
Конечно же нет.
А если серьезно - что не умеет LLM?
1) выдавать актуальную информацию. Фиксится подключением веб-поиска
2) выдавать 100% точные ответы. LLM вероятностна по своей природе, поэтому даже самая мощная модель с огромным контекстным окном с выверенным промтом может галлюцинировать
3) отвечать на доменноспецифичные вопросы. Фиксится RAG, куда закачивается доменная специфика
4) выполнять сложные вычисления. Опять же LLM - статистический вычислитель, а не математический. Решается вынесением вычислений в тулы
5) работать с большими объёмами информации. Над этим - контекстное окно - работают все разработчики LLM, окно уже превышает 1 млн токенов, но в любом случае оно конечно. А ещё токены стоят денег. Альтернативныое решение - помещение больших документов в RAG, чтобы не гонять их туда сюда, или разбиение на части (chunks) перед взаимодействием с LLM.
6) формировать JSON. Ладно, если быть точным - плохо умеет. Как ни странно, уменьшение размера и упрощение шаблона ответа может ускорить его генерацию. structured output не спасает
7) приготовить еду, изготовить телефон, построить дом. В общем взаимодействовать с физическим миром напрямую
8) понимать людей. Да, модель отвечает на любой вопрос. Ну почти любой, цензура как никак) Да, кому-то AI уже заменяет "кожаного" собеседника. Но в описанных случаях будет получен некий среднестатистический ответ, который должен порадовать спрашивающего. А если ваш вопрос уникальный и сложный, то промт должен быть непротиворечивым, компактным и структурированным. Так ли общаются люди? Да нет)))
9) изобретать, ставить задачи, мыслить. Опять же - LLM - это просто статистическая машина, обученная на большом объёме данных.
Так что кожаным мешками работа ещё найдётся.
P.S. и не только строителя дата-центров)
#ai
Конечно же нет.
А если серьезно - что не умеет LLM?
1) выдавать актуальную информацию. Фиксится подключением веб-поиска
2) выдавать 100% точные ответы. LLM вероятностна по своей природе, поэтому даже самая мощная модель с огромным контекстным окном с выверенным промтом может галлюцинировать
3) отвечать на доменноспецифичные вопросы. Фиксится RAG, куда закачивается доменная специфика
4) выполнять сложные вычисления. Опять же LLM - статистический вычислитель, а не математический. Решается вынесением вычислений в тулы
5) работать с большими объёмами информации. Над этим - контекстное окно - работают все разработчики LLM, окно уже превышает 1 млн токенов, но в любом случае оно конечно. А ещё токены стоят денег. Альтернативныое решение - помещение больших документов в RAG, чтобы не гонять их туда сюда, или разбиение на части (chunks) перед взаимодействием с LLM.
6) формировать JSON. Ладно, если быть точным - плохо умеет. Как ни странно, уменьшение размера и упрощение шаблона ответа может ускорить его генерацию. structured output не спасает
7) приготовить еду, изготовить телефон, построить дом. В общем взаимодействовать с физическим миром напрямую
8) понимать людей. Да, модель отвечает на любой вопрос. Ну почти любой, цензура как никак) Да, кому-то AI уже заменяет "кожаного" собеседника. Но в описанных случаях будет получен некий среднестатистический ответ, который должен порадовать спрашивающего. А если ваш вопрос уникальный и сложный, то промт должен быть непротиворечивым, компактным и структурированным. Так ли общаются люди? Да нет)))
9) изобретать, ставить задачи, мыслить. Опять же - LLM - это просто статистическая машина, обученная на большом объёме данных.
Так что кожаным мешками работа ещё найдётся.
P.S. и не только строителя дата-центров)
#ai
👍3
Бесконечный PostgreSQL
В SQL есть такая штука, как подзапросы.
Пример:
Но конкретно в PostgreSQL у подзапросов есть целых 4 альтернативы:
1) CTE (Общее Табличное Выражение)
2) VIEW
3) MATERIALIZED VIEW
4) TEMPORARY TABLE
Все они отличаются от подзапросов тем, что позволяют переиспользование.
И практически все - кроме обычного VIEW - материализуются, т.е. сохраняют результат на диск.
Есть отличия во времени жизни. CTE живут в рамках запроса, временные таблицы - сессии, а VIEW - до удаления. Поэтому VIEW позволяют навешивать права доступа.
Детали как обычно в статье: https://habr.com/ru/articles/855694/
Также рекомендую почитать комменты к статье, там важные дополнения:
- CTE тоже могут материализоваться как и VIEW, но этим сложнее управлять. А наличие или отсутствие материализации играет роль если в выборке есть динамически вычисляемые столбцы - например, генерация uuid, текущая дата или просто random.
- про временные таблицы важно помнить, что они живут только в рамках текущей сессии (соединения). Поэтому при работе с пулом коннектов, т.е. практически всегда, ими пользоваться не стоит.
Ну и еще один важный момент - материализация = сохранение текущего состояния на диск. Данные обновляться не будут!
Меня удивило существование CTE. Хотя если поискать - они в том или ином виде существуют во всех основных СУБД. Даже в SQLite)
#rdbms #postgresql
В SQL есть такая штука, как подзапросы.
Пример:
SELECT column1, column2
FROM table_name
WHERE column1 IN (
SELECT column1
FROM another_table
WHERE condition
);
Но конкретно в PostgreSQL у подзапросов есть целых 4 альтернативы:
1) CTE (Общее Табличное Выражение)
2) VIEW
3) MATERIALIZED VIEW
4) TEMPORARY TABLE
Все они отличаются от подзапросов тем, что позволяют переиспользование.
И практически все - кроме обычного VIEW - материализуются, т.е. сохраняют результат на диск.
Есть отличия во времени жизни. CTE живут в рамках запроса, временные таблицы - сессии, а VIEW - до удаления. Поэтому VIEW позволяют навешивать права доступа.
Детали как обычно в статье: https://habr.com/ru/articles/855694/
Также рекомендую почитать комменты к статье, там важные дополнения:
- CTE тоже могут материализоваться как и VIEW, но этим сложнее управлять. А наличие или отсутствие материализации играет роль если в выборке есть динамически вычисляемые столбцы - например, генерация uuid, текущая дата или просто random.
- про временные таблицы важно помнить, что они живут только в рамках текущей сессии (соединения). Поэтому при работе с пулом коннектов, т.е. практически всегда, ими пользоваться не стоит.
Ну и еще один важный момент - материализация = сохранение текущего состояния на диск. Данные обновляться не будут!
Меня удивило существование CTE. Хотя если поискать - они в том или ином виде существуют во всех основных СУБД. Даже в SQLite)
#rdbms #postgresql
Хабр
СTE, подзапрос или представление?
Здравствуйте, дорогие друзья! Сегодня мы рассмотрим различные подходы, которые разработчики используют для работы с данными в БД. В современном мире разработки, где информация становитесь все больше и...
Серия "хозяйке на заметку", а точнее разработчику библиотек на заметку.
Разработка библиотек отличается от разработки приложения тем, что публичные API в них живут намного дольше, и об этом надо помнить.
Любое публичное API, т.е. все public классы и методы, должно быть обратно совместимым как минимум в текущей мажорной версии.
Но жизнь как всегда сложнее. И что же у нас есть?
Java
1) объявить метод устаревшим с какой-то версии - @Deprecated.
Причем эту аннотацию можно не просто повесить на метод, у нее есть два поля: forRemoval и since, см. https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Deprecated.html
2) указать на что заменяем метод. @Deprecated не предоставляет такого механизма.
Но есть на свете добрые люди: https://errorprone.info/docs/inlineme
Как это может быть использовано:
а) статический анализ, собственно errorprone плагин: https://errorprone.info/docs/installation
б) миграция: https://docs.openrewrite.org/recipes/java/logging/log4j/inlinemethods
3) скрыть метод для потребителей не удаляя его из кодовой базы библиотеки. Т.е. оставляя его для тулов или для внутреннего использования. Java - снова нет( И даже добрые не помогли(
4) указать степень зрелости API. Стандартно - опять нет, но есть такая библиотечка @API Guardian https://github.com/apiguardian-team/apiguardian, позволяющая пометить API примерно так:
Используется в JUnit, к слову.
Более простая альтернатива: @Beta из Guava, https://guava.dev/releases/23.4-jre/api/docs/com/google/common/annotations/Beta.html
5) потребовать у клиента явного подтверждения в коде, что он готов использовать бета-версию, а не просто warning компилятора - увы, нет.
Kotlin
1) @Deprecated
2) @Deprecated(replaceWith) https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-replace-with/
3) @Deprecated(level) https://www.baeldung.com/kotlin/deprecation
4-5) Механизм Opt-In: https://kotlinlang.org/docs/opt-in-requirements.html#opt-in-to-inherit-from-a-class-or-interface
Все это, естественно, поддерживается в IDEA из коробки.
Плюс в Kotlin можно использовать @API Guardian
Получилась реклама Kotlin, что не удивительно, учитывая время его появления и назначение языка.
#api #java #kotlin
Разработка библиотек отличается от разработки приложения тем, что публичные API в них живут намного дольше, и об этом надо помнить.
Любое публичное API, т.е. все public классы и методы, должно быть обратно совместимым как минимум в текущей мажорной версии.
Но жизнь как всегда сложнее. И что же у нас есть?
Java
1) объявить метод устаревшим с какой-то версии - @Deprecated.
Причем эту аннотацию можно не просто повесить на метод, у нее есть два поля: forRemoval и since, см. https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Deprecated.html
2) указать на что заменяем метод. @Deprecated не предоставляет такого механизма.
Но есть на свете добрые люди: https://errorprone.info/docs/inlineme
Как это может быть использовано:
а) статический анализ, собственно errorprone плагин: https://errorprone.info/docs/installation
б) миграция: https://docs.openrewrite.org/recipes/java/logging/log4j/inlinemethods
3) скрыть метод для потребителей не удаляя его из кодовой базы библиотеки. Т.е. оставляя его для тулов или для внутреннего использования. Java - снова нет( И даже добрые не помогли(
4) указать степень зрелости API. Стандартно - опять нет, но есть такая библиотечка @API Guardian https://github.com/apiguardian-team/apiguardian, позволяющая пометить API примерно так:
@API(status = STABLE, since = "1.0")
public class StableService {
@API(status = EXPERIMENTAL)
public void experimentalMethod() {
}
@API(status = DEPRECATED, since = "2.0")
public void deprecatedMethod() {
}
@API(status = INTERNAL)
public void internalMethod() {
}
}
Используется в JUnit, к слову.
Более простая альтернатива: @Beta из Guava, https://guava.dev/releases/23.4-jre/api/docs/com/google/common/annotations/Beta.html
5) потребовать у клиента явного подтверждения в коде, что он готов использовать бета-версию, а не просто warning компилятора - увы, нет.
Kotlin
1) @Deprecated
2) @Deprecated(replaceWith) https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-replace-with/
3) @Deprecated(level) https://www.baeldung.com/kotlin/deprecation
4-5) Механизм Opt-In: https://kotlinlang.org/docs/opt-in-requirements.html#opt-in-to-inherit-from-a-class-or-interface
// Library code
@RequiresOptIn(message = "This API is experimental. It could change in the future without notice.")
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class MyDateTime
@MyDateTime
// A class requiring opt-in
class DateProvider
// Client code
@OptIn(MyDateTime::class)
// Uses DateProvider
fun getDate(): Date {
val dateProvider: DateProvider
// ...
}
Все это, естественно, поддерживается в IDEA из коробки.
Плюс в Kotlin можно использовать @API Guardian
Получилась реклама Kotlin, что не удивительно, учитывая время его появления и назначение языка.
#api #java #kotlin
Oracle
Deprecated (Java SE 17 & JDK 17)
declaration: module: java.base, package: java.lang, annotation type: Deprecated
EXPLAIN не так прост, как кажется.
Многие - сужу по проводимым собесам - знают про EXPLAIN и план выполнения запроса.
Вопрос - насколько этот план, а точнее цифры в нем, отражают реальность? Например, время выполнения запроса.
Я бы ввел 4 уровня приближения к реальности:
1) EXPLAIN - ничего не выполняет на самом деле, вместо этого использует накопленную статистику. Следовательно, может ошибаться, если:
а) эвристики СУБД (пусть будет PostgreSQL) не подходят к запросу
б) статистика устарела.
Самый быстрый, практически мгновенный, с него лучше начинать.
Вывод:
Обратите внимание на строчки со Plan и Cost в названии: идет расчет по статистике.
2) EXPLAIN (ANALYZE) - выполняет запрос по настоящему, считает реальное время выполнения, число записей и использование памяти.
Для запросов на изменение - реально меняет данные в БД, если использовать - только внутри транзакции с откатом.
Но с полученными данными ничего не делает, поэтому достаточно быстрый.
Вывод:
Появляются параметры со Actual в названии - это реальные показатели, поэтому то же время может меняться от вызова к вызову т.к. работает кэширование и меняется нагрузка на сервере.
Набор возвращаемых значений настраивается доп. параметрами.
В примере выше на самом деле использовался EXPLAIN (ANALYZE, TIMING), можно еще смотреть расход памяти, стоимость запроса в "попугаях", использование кэша, ...
Многие - сужу по проводимым собесам - знают про EXPLAIN и план выполнения запроса.
Вопрос - насколько этот план, а точнее цифры в нем, отражают реальность? Например, время выполнения запроса.
Я бы ввел 4 уровня приближения к реальности:
1) EXPLAIN - ничего не выполняет на самом деле, вместо этого использует накопленную статистику. Следовательно, может ошибаться, если:
а) эвристики СУБД (пусть будет PostgreSQL) не подходят к запросу
б) статистика устарела.
Самый быстрый, практически мгновенный, с него лучше начинать.
Вывод:
[
{
"Plan": {
"Node Type": "Bitmap Heap Scan",
"Parallel Aware": false,
"Async Capable": false,
"Relation Name": "customer",
"Alias": "customer",
"Startup Cost": 12072.01,
"Total Cost": 59658.76,
"Plan Rows": 358140,
"Plan Width": 4,
"Recheck Cond": "(c_mktsegment = 'FURNITURE'::bpchar)",
"Plans": [
{
"Node Type": "Bitmap Index Scan",
"Parent Relationship": "Outer",
"Parallel Aware": false,
"Async Capable": false,
"Index Name": "idx_customer_mktsegment_acctbal",
"Startup Cost": 0.00,
"Total Cost": 11982.48,
"Plan Rows": 358140,
"Plan Width": 0,
"Index Cond": "(c_mktsegment = 'FURNITURE'::bpchar)"
}
]
}
}
]
Обратите внимание на строчки со Plan и Cost в названии: идет расчет по статистике.
2) EXPLAIN (ANALYZE) - выполняет запрос по настоящему, считает реальное время выполнения, число записей и использование памяти.
Для запросов на изменение - реально меняет данные в БД, если использовать - только внутри транзакции с откатом.
Но с полученными данными ничего не делает, поэтому достаточно быстрый.
Вывод:
[
{
"Plan": {
"Node Type": "Bitmap Heap Scan",
"Parallel Aware": false,
"Async Capable": false,
"Relation Name": "customer",
"Alias": "customer",
"Actual Startup Time": 48.349,
"Actual Total Time": 184.486,
"Actual Rows": 359251,
"Actual Loops": 1,
"Recheck Cond": "(c_mktsegment = 'FURNITURE'::bpchar)",
"Rows Removed by Index Recheck": 0,
"Exact Heap Blocks": 43106,
"Lossy Heap Blocks": 0,
"Plans": [
{
"Node Type": "Bitmap Index Scan",
"Parent Relationship": "Outer",
"Parallel Aware": false,
"Async Capable": false,
"Index Name": "idx_customer_mktsegment_acctbal",
"Actual Startup Time": 39.360,
"Actual Total Time": 39.362,
"Actual Rows": 359251,
"Actual Loops": 1,
"Index Cond": "(c_mktsegment = 'FURNITURE'::bpchar)"
}
]
}
]
Появляются параметры со Actual в названии - это реальные показатели, поэтому то же время может меняться от вызова к вызову т.к. работает кэширование и меняется нагрузка на сервере.
Набор возвращаемых значений настраивается доп. параметрами.
В примере выше на самом деле использовался EXPLAIN (ANALYZE, TIMING), можно еще смотреть расход памяти, стоимость запроса в "попугаях", использование кэша, ...
3) EXPLAIN (ANALYZE, SERIALIZE, TIMING) - дополнительно появляется шаг преобразования данных на сервере, как это происходит при реальном запросе.
Дает еще более точный прогноз времени выполнения, но это все еще не реальное время, и дальше станет ясно почему.
Вывод:
Появился отдельный блок Serialization.
4) собственно выполнение оригинального запроса с клиента. Дополнительно включает в себя сетевую задержку между клиентом и сервером и преобразования на клиенте.
Перед выполнением лучше запустить count(*) для оценки масштаба бедствия)
#rdbmc #postgresql #troubleshooting
Дает еще более точный прогноз времени выполнения, но это все еще не реальное время, и дальше станет ясно почему.
Вывод:
[
{
"Plan": {
"Node Type": "Bitmap Heap Scan",
"Parallel Aware": false,
"Async Capable": false,
"Relation Name": "customer",
"Alias": "customer",
"Actual Rows": 359251,
"Actual Loops": 1,
"Recheck Cond": "(c_mktsegment = 'FURNITURE'::bpchar)",
"Rows Removed by Index Recheck": 0,
"Exact Heap Blocks": 43106,
"Lossy Heap Blocks": 0,
"Plans": [
{
"Node Type": "Bitmap Index Scan",
"Parent Relationship": "Outer",
"Parallel Aware": false,
"Async Capable": false,
"Index Name": "idx_customer_mktsegment_acctbal",
"Actual Rows": 359251,
"Actual Loops": 1,
"Index Cond": "(c_mktsegment = 'FURNITURE'::bpchar)"
}
]
},
"Serialization": {
"Time": 35.041,
"Output Volume": 4345,
"Format": "text"
}
}
]
Появился отдельный блок Serialization.
4) собственно выполнение оригинального запроса с клиента. Дополнительно включает в себя сетевую задержку между клиентом и сервером и преобразования на клиенте.
Перед выполнением лучше запустить count(*) для оценки масштаба бедствия)
#rdbmc #postgresql #troubleshooting