Всем привет!
Недавно обсуждали с коллегой необходимость JavaDoc\KDoc и в дополнение к высказанным ранее мыслям https://t.me/javaKotlinDevOps/183 возникла еще одна.
Напомню, основная моя идея была такая: массовый JavaDoc бесполезен, он должен быть точечным - там где назначение кода не понятно из наименования.
Немного переобуюсь) Массовый JavaDoc все же может быть полезен. Где? Для для описания монолита. И при одном условии.
Почему монолита - там много кода. Если монолит спроектирован правильно - модульного кода, но модулей все равно много и вникнуть в суть просто изучая код сложно. При этом над ним работает много человек, в идеале не привязанных к конкретным модулям.
А условие, точнее 3 условия, такие:
1) при каждой сборке develop ветки должен собираться и выкладываться актуальный JavaDoc. Тут даже мало JavaDoc артефакта, нужен сайт, где его можно прочитать. Например, GitHub Pages\GitLab Pages или аналоги.
2) должна быть точка входа или оглавление, например readme.md.
3) при написании документации и в особенность на ревью кода нужно обращать внимание не на наличие JavaDoc, а на его содержимое
P.S. Но JavaDoc конструкторов - все равно зашквар)
#javadoc #documentation
Недавно обсуждали с коллегой необходимость JavaDoc\KDoc и в дополнение к высказанным ранее мыслям https://t.me/javaKotlinDevOps/183 возникла еще одна.
Напомню, основная моя идея была такая: массовый JavaDoc бесполезен, он должен быть точечным - там где назначение кода не понятно из наименования.
Немного переобуюсь) Массовый JavaDoc все же может быть полезен. Где? Для для описания монолита. И при одном условии.
Почему монолита - там много кода. Если монолит спроектирован правильно - модульного кода, но модулей все равно много и вникнуть в суть просто изучая код сложно. При этом над ним работает много человек, в идеале не привязанных к конкретным модулям.
А условие, точнее 3 условия, такие:
1) при каждой сборке develop ветки должен собираться и выкладываться актуальный JavaDoc. Тут даже мало JavaDoc артефакта, нужен сайт, где его можно прочитать. Например, GitHub Pages\GitLab Pages или аналоги.
2) должна быть точка входа или оглавление, например readme.md.
3) при написании документации и в особенность на ревью кода нужно обращать внимание не на наличие JavaDoc, а на его содержимое
P.S. Но JavaDoc конструкторов - все равно зашквар)
#javadoc #documentation
Telegram
(java || kotlin) && devOps
Всем привет!
Уже несколько раз упоминал в последних постах JavaDoc\KDoc. Нужен ли он вообще?
Мой ответ: да, но не всегда.
Основной критерий - JavaDoc должен приносить пользу. Т.е. давать дополнительную информацию. Дополнительную к чему?
1) названию модуля…
Уже несколько раз упоминал в последних постах JavaDoc\KDoc. Нужен ли он вообще?
Мой ответ: да, но не всегда.
Основной критерий - JavaDoc должен приносить пользу. Т.е. давать дополнительную информацию. Дополнительную к чему?
1) названию модуля…
Всем привет!
Хочу порекомендовать хорошую статью на Хабре о необходимости кэша.
https://habr.com/ru/companies/oleg-bunin/articles/883422/
Со сравнительными тестами Redis, Memcached, PostgreSQL и MySQL.
Из статьи я почерпнул для себя несколько основных тезисов:
1) в наше время получить 1 000 000 rps с сервера на чтение - это реальность. И это круто! Речь про стандартный сервер, а не 100 ядер\1000 Гб памяти как можно было бы подумать
2) реляционные СУБД приблизились к кэшам (key-value noSQL хранилищам если хотите) по скорости чтения
3) как правильно заметил автор: будь он СТО - не разрешил бы использовать СУБД как кэш. И вот почему. Сравнимая производительность БД-кэш достигается при 2 условиях - нет операций записи в БД (а соответственно и блокировок записей) и все выборки идут по первичному ключу (это самая быстрая операция выборки). Казалось бы - соблюдай эти условия и все будет работать. Но ведь у нас СУБД. Окей, GRANT на запись отберем у всех. Но ведь СУБД может сложные JOIN-ы. И это никак не ограничить правами. Там могут быть сложные индексы. И рано или поздно найдется разработчик, которые эти возможности захочет использовать))) И в пике производительность упадет даже не в разы, а на порядки. Например, не провели НТ. Или забыли обновить профиль НТ. С кэшом такого по понятным причинам не произойдет. Вывод - у каждого инструмента свое назначение.
4) проблема неконсистентности данных кэш-БД все равно будет. Поэтому перед тем, как добавлять в систему кэш - стоит подумать, провести НТ и еще раз подумать. Возможно где-то есть или планируется архивная реплика БД. Там проблема констистентности данных решается механизмом репликации .Если часть нагрузки на чтение увести на нее - возможно кэш и не нужен.
P.S. Отдельная интересная тема: PostgreSQL показывает, что принцип число процессов ОС = числу ядер - не аксиома)
#rdbmc #cache #arch_compromises
Хочу порекомендовать хорошую статью на Хабре о необходимости кэша.
https://habr.com/ru/companies/oleg-bunin/articles/883422/
Со сравнительными тестами Redis, Memcached, PostgreSQL и MySQL.
Из статьи я почерпнул для себя несколько основных тезисов:
1) в наше время получить 1 000 000 rps с сервера на чтение - это реальность. И это круто! Речь про стандартный сервер, а не 100 ядер\1000 Гб памяти как можно было бы подумать
2) реляционные СУБД приблизились к кэшам (key-value noSQL хранилищам если хотите) по скорости чтения
3) как правильно заметил автор: будь он СТО - не разрешил бы использовать СУБД как кэш. И вот почему. Сравнимая производительность БД-кэш достигается при 2 условиях - нет операций записи в БД (а соответственно и блокировок записей) и все выборки идут по первичному ключу (это самая быстрая операция выборки). Казалось бы - соблюдай эти условия и все будет работать. Но ведь у нас СУБД. Окей, GRANT на запись отберем у всех. Но ведь СУБД может сложные JOIN-ы. И это никак не ограничить правами. Там могут быть сложные индексы. И рано или поздно найдется разработчик, которые эти возможности захочет использовать))) И в пике производительность упадет даже не в разы, а на порядки. Например, не провели НТ. Или забыли обновить профиль НТ. С кэшом такого по понятным причинам не произойдет. Вывод - у каждого инструмента свое назначение.
4) проблема неконсистентности данных кэш-БД все равно будет. Поэтому перед тем, как добавлять в систему кэш - стоит подумать, провести НТ и еще раз подумать. Возможно где-то есть или планируется архивная реплика БД. Там проблема констистентности данных решается механизмом репликации .Если часть нагрузки на чтение увести на нее - возможно кэш и не нужен.
P.S. Отдельная интересная тема: PostgreSQL показывает, что принцип число процессов ОС = числу ядер - не аксиома)
#rdbmc #cache #arch_compromises
Хабр
Нужен ли нам сейчас кеш-слой перед СУБД
Уже лет 20 существует миф (или не миф), что современный Highload-проект невозможен без кэшей. Они всегда нас выручали, когда не справлялись базы данных. Но с тех пор, как появились первые кэши,...
Всем привет!
Один из достаточно частых вопросов на собеседованиях - расскажите про стримы в Java, их плюсы и минусы. Если говорить о минусах - всегда под вопрос ставится быстродействие. У меня давно было желание его сравнить, но как часто бывает - меня опередили.
Вот неплохая статья про быстродействие стримов: https://habr.com/ru/articles/807647/
Какие выводы я сделал:
1) тот факт, что на небольшом объеме данных цикл forEach опережает любые виды стримов - ни о чем, им можно пренебречь. Как минимум в 99% случаев. Мне сложно представить кейс, когда объем данных невелик, но нужно выиграть миллисекунды. Скорее всего эти миллисекунды, или даже десятки миллисекунд, мы потеряем на сетевом взаимодействии. У нас же микросервисы, а это значит много сетевых вызовов. Если говорить о причинах - понятно, что на малых объемах данных накладные расходы, которые конечно же есть у стримов, играют роль. И еще момент - чем проще кусок кода, выполняющийся внутри стрима, тем больше отношение накладных расходов стримов к полезному действию.
2) parallelStream в большинстве случаев бьет forEach на больших объёмах данных. Почему так тоже понятно - эффект распараллеливание становится выше, чем накладные расходы на определенном объеме данных.
Итог: стримы можно использовать как вариант по умолчанию, т.к. они улучшают читаемость кода. В высоконагруженных приложениях\ больших объёмах данных имеет смысл смотреть в сторону parallelStream, особенно если есть результаты нагрузочного тестирования. Ну и только на каких-то критичных участках кода, имея на руках результаты НТ, имеет смысл переписать все на циклы
#streams #performance #interview_question
Один из достаточно частых вопросов на собеседованиях - расскажите про стримы в Java, их плюсы и минусы. Если говорить о минусах - всегда под вопрос ставится быстродействие. У меня давно было желание его сравнить, но как часто бывает - меня опередили.
Вот неплохая статья про быстродействие стримов: https://habr.com/ru/articles/807647/
Какие выводы я сделал:
1) тот факт, что на небольшом объеме данных цикл forEach опережает любые виды стримов - ни о чем, им можно пренебречь. Как минимум в 99% случаев. Мне сложно представить кейс, когда объем данных невелик, но нужно выиграть миллисекунды. Скорее всего эти миллисекунды, или даже десятки миллисекунд, мы потеряем на сетевом взаимодействии. У нас же микросервисы, а это значит много сетевых вызовов. Если говорить о причинах - понятно, что на малых объемах данных накладные расходы, которые конечно же есть у стримов, играют роль. И еще момент - чем проще кусок кода, выполняющийся внутри стрима, тем больше отношение накладных расходов стримов к полезному действию.
2) parallelStream в большинстве случаев бьет forEach на больших объёмах данных. Почему так тоже понятно - эффект распараллеливание становится выше, чем накладные расходы на определенном объеме данных.
Итог: стримы можно использовать как вариант по умолчанию, т.к. они улучшают читаемость кода. В высоконагруженных приложениях\ больших объёмах данных имеет смысл смотреть в сторону parallelStream, особенно если есть результаты нагрузочного тестирования. Ну и только на каких-то критичных участках кода, имея на руках результаты НТ, имеет смысл переписать все на циклы
#streams #performance #interview_question
Хабр
Еще раз о перформансе стримов в Java
Время от времени я наблюдаю или даже бываю втянутым в спор о перформансе стримов в джаве. Общеизвестно, что стримы это компромисс между перформансом и удобством. Однако я не нашел вменяемого набора...
Всем привет!
Случайно наткнулся на старую статью - 2015 год - про переход с legacy на Service Oriented Architecture ака SOA.
И хочу сказать, что это хороший пример развития истории по спирали)
Что в статье актуально?
Заменяем слово SOA на микросервисы, и в целом все, что касается преимуществ микросервисной архитектуры и стратегии перехода на нее - актуально. Микросервисы = SOA 2.0 )))
REST оставляем, SOAP+XML заменяем на gRPC\GraphQL для тех случаев, когда требуется большая производительность и гибкость соответственно по сравнению с REST. К слову, недостаток производительности и гибкости - это основные проблемы SOAP. Ремарка - знаю места, где SOAP еще жив (интеграция с госорганами), но он в любом случае вымирает.
ESB, трудности реализации асинхронного взаимодействия - все эти задачи взяла на себя Kafka. Прорывной инструмент - быстрый, надежный (обеспечивает дешевую персистентность), opensource, простой с точки зрения разработчика. В т.ч. потому, что нет необходимости разрабатывать логику маппинга сообщений на брокере. Да, он реализует только одну из двух основных моделей асинхронного взаимодействия - Publisher-Subscriber - и не реализует Message Queue. Но понятно, что топиками можно пользоваться как заменой очередей, и в большинстве случаев проблем при этом не будет.
Облачные решения - за 10 лет из вызова превратились в новую реальность)
А вызов сейчас - внедрение AI. Как-то так)
#microservices #ai #cloud #kafka #rest
Случайно наткнулся на старую статью - 2015 год - про переход с legacy на Service Oriented Architecture ака SOA.
И хочу сказать, что это хороший пример развития истории по спирали)
Что в статье актуально?
Заменяем слово SOA на микросервисы, и в целом все, что касается преимуществ микросервисной архитектуры и стратегии перехода на нее - актуально. Микросервисы = SOA 2.0 )))
REST оставляем, SOAP+XML заменяем на gRPC\GraphQL для тех случаев, когда требуется большая производительность и гибкость соответственно по сравнению с REST. К слову, недостаток производительности и гибкости - это основные проблемы SOAP. Ремарка - знаю места, где SOAP еще жив (интеграция с госорганами), но он в любом случае вымирает.
ESB, трудности реализации асинхронного взаимодействия - все эти задачи взяла на себя Kafka. Прорывной инструмент - быстрый, надежный (обеспечивает дешевую персистентность), opensource, простой с точки зрения разработчика. В т.ч. потому, что нет необходимости разрабатывать логику маппинга сообщений на брокере. Да, он реализует только одну из двух основных моделей асинхронного взаимодействия - Publisher-Subscriber - и не реализует Message Queue. Но понятно, что топиками можно пользоваться как заменой очередей, и в большинстве случаев проблем при этом не будет.
Облачные решения - за 10 лет из вызова превратились в новую реальность)
А вызов сейчас - внедрение AI. Как-то так)
#microservices #ai #cloud #kafka #rest
Всем привет!
Возращаясь к тебе legacy.
Давно хотел прочитать книжку Эффективная работа с унаследованным кодом. legacy в жизни разработчика есть всегда (если только он сознательно не ищет только greenfield проекты), поэтому тема полезная. Книга не новая, но судя по отзывам (и по факту как выяснилось) актуальная.
Небольшое введение в тему. Есть 2 способа бороться с легаси - я бы их назвал архитектурный и програмистский. Архитектурный - взять и сделать рядом новую систему, постеменно перетягивая туда функционал и используя такие паттерны как Strangler Application, API Gateway, Decorator, Facade...
Програмисткий - улучшать легаси изнутри, делить его на микросервисы по необходимости и т.д. Это конечно крайности, как правило используется смесь обоих подходов.
Так вот - книга про второй способ. Я ожидал найти там набор практик и паттернов по улучшению легаси. И более того - они там есть. Но главная мысль в книге другая, и она немного неожиданная. Сразу вспомнилась шутка: как только код написан - он уже стал легаси) И так может быть) Если мы даем такое определение легаси - много кода без тестов. Почему? В чем основная проблема легаси? Никто не знает досконально как оно работает, никто не хочет с этим кодом разбираться и, как следствие, его боятся менять. Очевидно, что если кода много и тестов нет - менять его страшно. Бинго. И собственно вся книга о том, как написать недостающие тесты даже если на первый взгляд это кажется очень сложным.
#legacy #book_review
Возращаясь к тебе legacy.
Давно хотел прочитать книжку Эффективная работа с унаследованным кодом. legacy в жизни разработчика есть всегда (если только он сознательно не ищет только greenfield проекты), поэтому тема полезная. Книга не новая, но судя по отзывам (и по факту как выяснилось) актуальная.
Небольшое введение в тему. Есть 2 способа бороться с легаси - я бы их назвал архитектурный и програмистский. Архитектурный - взять и сделать рядом новую систему, постеменно перетягивая туда функционал и используя такие паттерны как Strangler Application, API Gateway, Decorator, Facade...
Програмисткий - улучшать легаси изнутри, делить его на микросервисы по необходимости и т.д. Это конечно крайности, как правило используется смесь обоих подходов.
Так вот - книга про второй способ. Я ожидал найти там набор практик и паттернов по улучшению легаси. И более того - они там есть. Но главная мысль в книге другая, и она немного неожиданная. Сразу вспомнилась шутка: как только код написан - он уже стал легаси) И так может быть) Если мы даем такое определение легаси - много кода без тестов. Почему? В чем основная проблема легаси? Никто не знает досконально как оно работает, никто не хочет с этим кодом разбираться и, как следствие, его боятся менять. Очевидно, что если кода много и тестов нет - менять его страшно. Бинго. И собственно вся книга о том, как написать недостающие тесты даже если на первый взгляд это кажется очень сложным.
#legacy #book_review
Всем привет!
Продолжаю читать книгу "Эффективная работа с унаследованным кодом". Наткнулся на интересную мысль, на первый взгляд подтверждающую тезис: разработка - искусство компромиссов.
Мы все используем библиотеки. Когда нужно написать тест (а книга в основном про то, как упростить написание тестов для legacy) - часто в наш класс передаются библиотечные объекты. И тут могут быть две проблемы:
1) объект-синглтон
2) final объект или объект с методами, которые не возможно переопределить.
Эти две проблемы приводят к одному и тому же - мы не можем создать mock, приходится инициализировать для тестов реальный объект из библиотеки. А он может быть "тяжелым", превращающий модульный тест в интеграционный.
Как вариант решения этой проблемы предлагается:
1) для singleton создавать фасад, который разрешает замену объекта через setter, т.е. по сути нарушать суть паттерна singleton
2) для final методов и объектов - убрать final, объявляя их логическими final в документации.
Оба предложения по сути об одном - нарушаем принципы проектирования на уровне языка, зато делаем возможным тестирование кода.
В целом - "соль" в этом есть. Код без тестов опаснее кода, нарушающего принципы проектирования. Но я бы уточнил, что оба метода - это крайние меры. А по хорошему, если вы разрабатываете код, который кто-то когда-то будет тестировать - надо заранее озаботится о тестируемости, и именно:
1) не создавать singleton самому, использовать для этого IoC контейнер. Spring если библиотека внутренняя, и у вас используется Spring, или CDI аннотации в других случаях. Причем это актуально не только для разработчиков библиотек, а для всех.
2) создавать интерфейсы для классов, вынесенных в клиентское API. Есть интерфейс - всегда можно создать mock в тесте без всяких ухищрений. Я против создания интерфейсов всегда и везде https://t.me/javaKotlinDevOps/235, но Java API - это как раз подходящий случай. Одних интерфейсов конечно же мало, нужно еще и четкое разделение на модель и сервисы. Первые можно использоваться AS IS в тестах, вторые часто приходится мокать. Да, спроектировать все правильно не так-то легко, но как говорится - дорогу осилит идущий.
#book_review #ood #dev_compromises #libraries
Продолжаю читать книгу "Эффективная работа с унаследованным кодом". Наткнулся на интересную мысль, на первый взгляд подтверждающую тезис: разработка - искусство компромиссов.
Мы все используем библиотеки. Когда нужно написать тест (а книга в основном про то, как упростить написание тестов для legacy) - часто в наш класс передаются библиотечные объекты. И тут могут быть две проблемы:
1) объект-синглтон
2) final объект или объект с методами, которые не возможно переопределить.
Эти две проблемы приводят к одному и тому же - мы не можем создать mock, приходится инициализировать для тестов реальный объект из библиотеки. А он может быть "тяжелым", превращающий модульный тест в интеграционный.
Как вариант решения этой проблемы предлагается:
1) для singleton создавать фасад, который разрешает замену объекта через setter, т.е. по сути нарушать суть паттерна singleton
2) для final методов и объектов - убрать final, объявляя их логическими final в документации.
Оба предложения по сути об одном - нарушаем принципы проектирования на уровне языка, зато делаем возможным тестирование кода.
В целом - "соль" в этом есть. Код без тестов опаснее кода, нарушающего принципы проектирования. Но я бы уточнил, что оба метода - это крайние меры. А по хорошему, если вы разрабатываете код, который кто-то когда-то будет тестировать - надо заранее озаботится о тестируемости, и именно:
1) не создавать singleton самому, использовать для этого IoC контейнер. Spring если библиотека внутренняя, и у вас используется Spring, или CDI аннотации в других случаях. Причем это актуально не только для разработчиков библиотек, а для всех.
2) создавать интерфейсы для классов, вынесенных в клиентское API. Есть интерфейс - всегда можно создать mock в тесте без всяких ухищрений. Я против создания интерфейсов всегда и везде https://t.me/javaKotlinDevOps/235, но Java API - это как раз подходящий случай. Одних интерфейсов конечно же мало, нужно еще и четкое разделение на модель и сервисы. Первые можно использоваться AS IS в тестах, вторые часто приходится мокать. Да, спроектировать все правильно не так-то легко, но как говорится - дорогу осилит идущий.
#book_review #ood #dev_compromises #libraries
Telegram
(java || kotlin) && devOps
Всем привет!
В коде я часто вижу раздражающий меня паттерн - интерфейс с одной реализацией.
Почему так делается и когда так делать не стоит?
Для начала - когда полезны интерфейсы:
1) соблюдение принципа инверсии зависимостей, буква D из SOLID. См. ht…
В коде я часто вижу раздражающий меня паттерн - интерфейс с одной реализацией.
Почему так делается и когда так делать не стоит?
Для начала - когда полезны интерфейсы:
1) соблюдение принципа инверсии зависимостей, буква D из SOLID. См. ht…
Всем привет!
Вчера "прогремела" новость по AI агентов, которые через 3 месяца будут писать 90% кода https://habr.com/ru/news/889992/
Что я могу сказать.. галлюцинируют не только модели)))
Что нельзя не отметить:
1) модели в последнее время сильно эволюционировали в целом и в плане написания кода в частности
2) появляется все больше AI агентов, упрощающих внедрение написанного AI кода - убирают Copy-Paste из окна AI чата
3) объем контекста моделей растет, что позволяет загнать туда весь проект типового микросервиса
4) про AI говорят из каждого утюга, наверное скоро не останется разработчиков, которые не изучали AI агенты
Актуален ли вывод в статье учитывая вышесказанное? Конечно же нет.
Да, будут разработчики, возможно они есть и сейчас, 90% кода которых - плод работы AI. Кстати, есть такие среди читателей канала? Отпишитесь, плиз)
Но что не нужно недооценивать:
1) инерцию - новые технологии быстро не внедряются. Даже если это dev уровень - релизить AI помощника для разработки в ПРОМ не надо
2) цену в деньгах или времени - хороший AI стоит денег, или если это open source типа Deepseek - времени выбор подходящего и встраивание его в процесс разработки
3) галлюцинации. AI хорошо работает на типовых кейсах, хуже - на неизвестных. Т.е. галлюцинаций будет много на малоизвестных языках, фреймворках и внутренних платформах (!)
4) негативный эффект от первых попыток. Если AI был опробован год назад и сильно глючил - до следующей попытки внедрения пройдет время, и это не 3 месяца
5) меньший контроль - когда код пишешь сам, то ты его контролируешь полностью. Если, конечно, спать хотя бы 7 часов в день, и тебя не дергают каждые полчаса на встречи) За моделью нужно проверять, проверка - менее приятный процесс по сравнению с написанием, мозг склонен его оптимизировать, что приводит к меньшему контролю.
Вывод - CEO Anthropic плохо представляет реальную разработку, и грешит маркетинговым bullshit-ом((( Хотя он CEO, а не CIO, что немного его оправдывает)
#ai
Вчера "прогремела" новость по AI агентов, которые через 3 месяца будут писать 90% кода https://habr.com/ru/news/889992/
Что я могу сказать.. галлюцинируют не только модели)))
Что нельзя не отметить:
1) модели в последнее время сильно эволюционировали в целом и в плане написания кода в частности
2) появляется все больше AI агентов, упрощающих внедрение написанного AI кода - убирают Copy-Paste из окна AI чата
3) объем контекста моделей растет, что позволяет загнать туда весь проект типового микросервиса
4) про AI говорят из каждого утюга, наверное скоро не останется разработчиков, которые не изучали AI агенты
Актуален ли вывод в статье учитывая вышесказанное? Конечно же нет.
Да, будут разработчики, возможно они есть и сейчас, 90% кода которых - плод работы AI. Кстати, есть такие среди читателей канала? Отпишитесь, плиз)
Но что не нужно недооценивать:
1) инерцию - новые технологии быстро не внедряются. Даже если это dev уровень - релизить AI помощника для разработки в ПРОМ не надо
2) цену в деньгах или времени - хороший AI стоит денег, или если это open source типа Deepseek - времени выбор подходящего и встраивание его в процесс разработки
3) галлюцинации. AI хорошо работает на типовых кейсах, хуже - на неизвестных. Т.е. галлюцинаций будет много на малоизвестных языках, фреймворках и внутренних платформах (!)
4) негативный эффект от первых попыток. Если AI был опробован год назад и сильно глючил - до следующей попытки внедрения пройдет время, и это не 3 месяца
5) меньший контроль - когда код пишешь сам, то ты его контролируешь полностью. Если, конечно, спать хотя бы 7 часов в день, и тебя не дергают каждые полчаса на встречи) За моделью нужно проверять, проверка - менее приятный процесс по сравнению с написанием, мозг склонен его оптимизировать, что приводит к меньшему контролю.
Вывод - CEO Anthropic плохо представляет реальную разработку, и грешит маркетинговым bullshit-ом((( Хотя он CEO, а не CIO, что немного его оправдывает)
#ai
Хабр
CEO Anthropic: через полгода 90% кода будет писать ИИ. Через год — 100%
Выступая на форуме "Council on Foreign Relations", Дарио Амодей, CEO Anthropic, одной из главных AI-компаний в мире, сделал несколько важных заявлений про рост популярности разработки при помощи ИИ в...
Всем привет!
Минутка философии на канале. Если почитать идеологов DevOps, он не про инструменты, а про взаимодействие. Взаимодействие Dev и Ops. А отдельная команда DevOps, если и существует, то для разработки тех самых инструментов, которыми пользуются Dev и Ops. И тогда релизный процесс улучшается, скорость реакции на инциденты растёт.
Рассмотрим обратный случай — типичный, к слову. Есть команда DevOps, она настраивает стенды и пайплайны, которыми пользуются Ops. Какой будет эффект? Вообще говоря, разный, зависит от степени взаимодействия команд. Но вполне может быть, что с появлением команды DevOps процессы только замедлятся. Ops во всём надеются на DevOps. При любой проблеме Ops идёт к DevOps, Dev при этом получает информацию посредством испорченного телефона или вообще не получает. И наоборот, в случае с тестовыми стендами. Грусть, печаль, баги прома.
#devops
Минутка философии на канале. Если почитать идеологов DevOps, он не про инструменты, а про взаимодействие. Взаимодействие Dev и Ops. А отдельная команда DevOps, если и существует, то для разработки тех самых инструментов, которыми пользуются Dev и Ops. И тогда релизный процесс улучшается, скорость реакции на инциденты растёт.
Рассмотрим обратный случай — типичный, к слову. Есть команда DevOps, она настраивает стенды и пайплайны, которыми пользуются Ops. Какой будет эффект? Вообще говоря, разный, зависит от степени взаимодействия команд. Но вполне может быть, что с появлением команды DevOps процессы только замедлятся. Ops во всём надеются на DevOps. При любой проблеме Ops идёт к DevOps, Dev при этом получает информацию посредством испорченного телефона или вообще не получает. И наоборот, в случае с тестовыми стендами. Грусть, печаль, баги прома.
#devops
Всем привет!
Я уже писал про то, что не люблю код, в котором интерфейсы делаются ради интерфейсов. Самый яркий антипаттерн: интерфейс с единственной реализацией, лежащей рядом. Подозреваю, одной из причин такого проектирования является принцип Dependency Inversion - в модели должны быть интерфейсы, а в сервисном слое - их реализации. И они разнесены по разным слоям приложения. Тут вроде все сходится?
Как бы да, но я нашел интересное возражение: https://habr.com/ru/articles/888428/
Как всегда побуду в роли ChatGPT) Суть статьи, а точнее продвигаемого там принципа структурного дизайна в том, что вместо создания интерфейса, любой сложный сервис можно отрефакторить (или спроектировать), выделив 3 метода:
1) чтение - все интеграции по чтению из внешних источников
2) бизнес-логика - тут должны быть чистые классы модели, принимающие на вход только простые типы или коллекции, без побочных эффектов
3) запись результата во внешние источники
2-я часть - это ядро, все остальное - imperative shell. Методы ядра вызываются из imperative shell, зависимости направлены в одну сторону.
Потенциальная проблема - возможно, читать придется много, чтобы загрузить данные для всех условий в бизнес-логике. Решение - дробить бизнес-логику на более мелкие части.
Еще проблема - как отследить, что в метод с бизнес-логикой не передали "побочный эффект". Например, класс, делающий вызов к БД - JPA lazy initialized DTO. Или ссылку на синглтон - Spring bean. Навскидку - только ручное код-ревью. Формально описать проверку объекта на отсутствие побочных эффектов сложно.
Огромный плюс - бизнес-логика всегда легко тестируется, даже без mock-ов.
Еще плюс - код проще.
Вот пример такого рефакторинга: https://www.youtube.com/watch?v=wq9LBouRULs
До чтения статьи, по заголовку, "покушение" на основы чистой архитектуры я воспринял критически. Но после ее прочтения и дальнейших размышлений идея понравилась.
Очевидно, она применима не всегда. Можно описать такую эвристику:
Простой сервис:
1) используем структурный дизайн, четко разделяем чтение с записью от бизнес-логики. С интерфейсами не заморачиваемся.
2) нужна вторая реализация какого-то сервиса - для тестового mock-а, динамической замены в runtime - легко вводим интерфейс с помощью IDE там, где он нужен
Сложный сервис, например:
1) библиотека
2) система с плагинами
3) коробочный продукт с несколькими реализациями под разных клиентов
4) наличие ядра, которое нужно защитить от правок "не доверенными лицами" -
изначально проектируем с интерфейсами в модели и реализациями в сервисах и портах\адаптерах
Принципу KISS - соответствует. Dependency Inversion - как ни странно тоже, т.к. в точной формулировке он звучит так: ядро не должно зависеть от деталей реализации. А структурном дизайне в ядро передаются только простые типы данных и коллекции с ними.
#arch #clean_code #principles
Я уже писал про то, что не люблю код, в котором интерфейсы делаются ради интерфейсов. Самый яркий антипаттерн: интерфейс с единственной реализацией, лежащей рядом. Подозреваю, одной из причин такого проектирования является принцип Dependency Inversion - в модели должны быть интерфейсы, а в сервисном слое - их реализации. И они разнесены по разным слоям приложения. Тут вроде все сходится?
Как бы да, но я нашел интересное возражение: https://habr.com/ru/articles/888428/
Как всегда побуду в роли ChatGPT) Суть статьи, а точнее продвигаемого там принципа структурного дизайна в том, что вместо создания интерфейса, любой сложный сервис можно отрефакторить (или спроектировать), выделив 3 метода:
1) чтение - все интеграции по чтению из внешних источников
2) бизнес-логика - тут должны быть чистые классы модели, принимающие на вход только простые типы или коллекции, без побочных эффектов
3) запись результата во внешние источники
2-я часть - это ядро, все остальное - imperative shell. Методы ядра вызываются из imperative shell, зависимости направлены в одну сторону.
Потенциальная проблема - возможно, читать придется много, чтобы загрузить данные для всех условий в бизнес-логике. Решение - дробить бизнес-логику на более мелкие части.
Еще проблема - как отследить, что в метод с бизнес-логикой не передали "побочный эффект". Например, класс, делающий вызов к БД - JPA lazy initialized DTO. Или ссылку на синглтон - Spring bean. Навскидку - только ручное код-ревью. Формально описать проверку объекта на отсутствие побочных эффектов сложно.
Огромный плюс - бизнес-логика всегда легко тестируется, даже без mock-ов.
Еще плюс - код проще.
Вот пример такого рефакторинга: https://www.youtube.com/watch?v=wq9LBouRULs
До чтения статьи, по заголовку, "покушение" на основы чистой архитектуры я воспринял критически. Но после ее прочтения и дальнейших размышлений идея понравилась.
Очевидно, она применима не всегда. Можно описать такую эвристику:
Простой сервис:
1) используем структурный дизайн, четко разделяем чтение с записью от бизнес-логики. С интерфейсами не заморачиваемся.
2) нужна вторая реализация какого-то сервиса - для тестового mock-а, динамической замены в runtime - легко вводим интерфейс с помощью IDE там, где он нужен
Сложный сервис, например:
1) библиотека
2) система с плагинами
3) коробочный продукт с несколькими реализациями под разных клиентов
4) наличие ядра, которое нужно защитить от правок "не доверенными лицами" -
изначально проектируем с интерфейсами в модели и реализациями в сервисах и портах\адаптерах
Принципу KISS - соответствует. Dependency Inversion - как ни странно тоже, т.к. в точной формулировке он звучит так: ядро не должно зависеть от деталей реализации. А структурном дизайне в ядро передаются только простые типы данных и коллекции с ними.
#arch #clean_code #principles
Хабр
Вам не нужна Чистая архитектура. Скорее всего
Введение Сейчас среди Java/Kotlin команд распространено применение Чистой (ака Гексагональной, ака Луковой — Clean, Hexagonal, Onion) архитектуры для разработки бакэндов прикладных...
Всем привет!
Как можно собрать Docker образ?
Есть плагины для Maven\Gradle, позволяющие использовать всю мощь соответствующих инструментов при сборке.
А есть собственно Docker и команда docker build, собирающая образ на основании Dockerfile. Ну и еще Docker Compose, позволяющий описать, собрать и запустить группу образов, полезный при локальной разработки или если нет k8s.
До какого-то момента возможности Docker по кастомизации процесса сборки были скажем так базовыми.
Но как вы уже догадываетесь - все поменялось.
Появился Docker Bake. Вот хорошая статья на Хабре https://habr.com/ru/articles/886938/
Команда для сборки: docker buildx bake
buildx - это расширенный вариант build, позволяющий выбрать движок для сборки образа.
В последние версии Docker функционал Bake включен по умолчанию.
Основные плюсы с примерами конфигураций:
1) функции
function "tag" {
params = [name, tag]
result = ["${name}:${tag}"]
}
2) группировка образов для сборки одной командой
group "default" {
targets = ["frontend", "api"]
}
target "frontend" {
...
target "api" {
2) наследование конфигурации
target "app-base" {
dockerfile = "Dockerfile"
args = {
BASE_IMAGE = "node:16-alpine"
}
}
target "app-dev" {
inherits = ["app-base"]
...
}
3) кросс-платформенная сборка
target "app-all" {
platforms = ["linux/amd64", "linux/arm64"]
}
4) профили сборки
variable "ENV" {
default = "dev"
}
group "default" {
targets = ["app-${ENV}"]
}
target "app-dev" {
...
target "app-stage" {
..
target "app-prod" {
...
и сборка командой
ENV=prod docker buildx bake
5) матричная сборка - сборка всех возможных комбинаций, указанных в матрице
target "app" {
matrix = {
platform = ["linux/amd64", "linux/arm64"]
version = ["1.0", "2.0"]
}
6) встроенное распараллеливание сборки
7) чтение переменных из файла
// Импорт переменных из JSON-файла
variable "settings" {
default = {}
}
target "app" {
dockerfile = "Dockerfile"
args = {
CONFIG = "${settings.app_config}"
}
}
Ну и главное - декларативность описания процесса сборки, описываем результат, а не действия. За исключением пользовательских функций, конечно)
Кажется, неплохая альтернатива плагинам и хороший апгрейд Docker. Важным плюсом видится встраивание в Docker. Тот же Scaffold - выполняющий другую функцию, но в т.ч. собирающий образы - нужно ставить отдельно, и в IDEA он тянет за собой кучу лишних фичей.
P.S. Docker Compose заменяет только в части сборки. И может с ним интегрироваться.
#docker #gradle #maven
Как можно собрать Docker образ?
Есть плагины для Maven\Gradle, позволяющие использовать всю мощь соответствующих инструментов при сборке.
А есть собственно Docker и команда docker build, собирающая образ на основании Dockerfile. Ну и еще Docker Compose, позволяющий описать, собрать и запустить группу образов, полезный при локальной разработки или если нет k8s.
До какого-то момента возможности Docker по кастомизации процесса сборки были скажем так базовыми.
Но как вы уже догадываетесь - все поменялось.
Появился Docker Bake. Вот хорошая статья на Хабре https://habr.com/ru/articles/886938/
Команда для сборки: docker buildx bake
buildx - это расширенный вариант build, позволяющий выбрать движок для сборки образа.
В последние версии Docker функционал Bake включен по умолчанию.
Основные плюсы с примерами конфигураций:
1) функции
function "tag" {
params = [name, tag]
result = ["${name}:${tag}"]
}
2) группировка образов для сборки одной командой
group "default" {
targets = ["frontend", "api"]
}
target "frontend" {
...
target "api" {
2) наследование конфигурации
target "app-base" {
dockerfile = "Dockerfile"
args = {
BASE_IMAGE = "node:16-alpine"
}
}
target "app-dev" {
inherits = ["app-base"]
...
}
3) кросс-платформенная сборка
target "app-all" {
platforms = ["linux/amd64", "linux/arm64"]
}
4) профили сборки
variable "ENV" {
default = "dev"
}
group "default" {
targets = ["app-${ENV}"]
}
target "app-dev" {
...
target "app-stage" {
..
target "app-prod" {
...
и сборка командой
ENV=prod docker buildx bake
5) матричная сборка - сборка всех возможных комбинаций, указанных в матрице
target "app" {
matrix = {
platform = ["linux/amd64", "linux/arm64"]
version = ["1.0", "2.0"]
}
6) встроенное распараллеливание сборки
7) чтение переменных из файла
// Импорт переменных из JSON-файла
variable "settings" {
default = {}
}
target "app" {
dockerfile = "Dockerfile"
args = {
CONFIG = "${settings.app_config}"
}
}
Ну и главное - декларативность описания процесса сборки, описываем результат, а не действия. За исключением пользовательских функций, конечно)
Кажется, неплохая альтернатива плагинам и хороший апгрейд Docker. Важным плюсом видится встраивание в Docker. Тот же Scaffold - выполняющий другую функцию, но в т.ч. собирающий образы - нужно ставить отдельно, и в IDEA он тянет за собой кучу лишних фичей.
P.S. Docker Compose заменяет только в части сборки. И может с ним интегрироваться.
#docker #gradle #maven
Хабр
Docker Bake: современный подход к сборке контейнеров
Традиционный способ сборки Docker-образов с помощью команды docker build прост и понятен, но при работе с комплексными приложениями, состоящими из множества компонентов, этот процесс может стать...
Всем привет!
Я уже подымал тему готовых архитектурных решений, а точнее их отсутствия в большинстве случаев https://t.me/javaKotlinDevOps/134
Хочу развернуть тему с другой стороны.
Стоит ли тратить силы на поиск целевого архитектурного решения?
Написал эту фразу, и понял, что не всем она может быть понятна) Расшифрую. В больших компаниях ака "кровавый enterprise" есть некий список разрешенных технологий и архитектурных принципов. Оформленный в виде техрадара, карты технологических стеков и сборника архитектурных стандартов. Это и есть целевая архитектура.
Так вот, беда с этим стандартами одна - со временем их становится слишком много, понять - как сделать правильно, чтобы работало годами без переделки - сложно. Нужно на это тратить время: для того, чтобы обойти всех заинтересованных архитекторов, смежные команды, и выработать целевое решение.
Так вот - а надо ли его искать? Несмотря на то, что ответ вроде бы очевиден, хотел бы подсветить несколько потенциальных проблем.
Затрачивая время на поиск и согласование целевого решения мы взамен хотим получить уверенность, что решение с нами останется "на века". Так ли это? Нет, не так. Во-первых мир меняется очень сильно, бизнес задачи меняются вместе с ним. Во-вторых технологии меняются еще сильнее. В-третьих - "кассандр" среди нас мало, и если есть несколько разрешенных технологий - угадать правильную сложно.
К чему это приводит? Мы потратили время на выбор и реализацию "целевки", а через год нам говорят - переделывайте. Отрицание, гнев, фрустрация. Обида на архитекторов. Причем даже если архитектор признает ошибку (и вообще эта ошибка была) - вряд ли он поможет переписать код. Обида на менеджеров - да они издеваются что ли, вечно меняют правила игры, вечная миграция... Желание сменить компанию...
Поэтому видится, что есть более надежный подход.
1) смириться с тем, что все течет, все меняется, и миграции будут всегда
2) искать целевые решение, но всегда держать в уме, что это целевое решение на данный момент
3) разделить весь код на ядро и инфраструктурный код. Ядро стараться писать на чистой Java \ Kotlin, с минимальным использованием фреймворков. Особенно, внутренних, которые еще не доказали свою стабильность. Внешние интеграции закрывать - предохранительный слой (anticorruption layer), шлюзы (gateway), адаптеры.
4) очень важно - уметь и хотеть быстро выпускать релизы, разбивать любые доработки на небольшие инкременты. Это можно сделать как улучшением качества проектирования, увеличением покрытия тестами и автотестами, так и различного рода договоренностями со смежниками, (не забываем, что мы в "кровавом enterprise")
Если вам показывался знакомым последний пункт - то да, это Agile. Или то самое снижение Lead Time (LT), о котором любят говорить менеджеры. И не только говорить) Но в данном случае они правы.
Еще пример - фондовый рынок и диверсификация. Диверсификация считается основным принципом разумного инвестора, и означает, что нельзя "класть все яйца в одну корзину". Т.е. нужно покупать разные классы активов: акции, облигации, вклады, кэш, золото, недвижимость. Причина - сложно угадать, что именно "выстрелит". В случае кода сложно конечно реализовать диверсификацию прямолинейно: часть данных хранить в PostgreSQL, а часть - в Oracle. Да и не нужно. Но предусмотреть возможность замены поставщика - нужно.
#agile #arch #arch_compromisses
Я уже подымал тему готовых архитектурных решений, а точнее их отсутствия в большинстве случаев https://t.me/javaKotlinDevOps/134
Хочу развернуть тему с другой стороны.
Стоит ли тратить силы на поиск целевого архитектурного решения?
Написал эту фразу, и понял, что не всем она может быть понятна) Расшифрую. В больших компаниях ака "кровавый enterprise" есть некий список разрешенных технологий и архитектурных принципов. Оформленный в виде техрадара, карты технологических стеков и сборника архитектурных стандартов. Это и есть целевая архитектура.
Так вот, беда с этим стандартами одна - со временем их становится слишком много, понять - как сделать правильно, чтобы работало годами без переделки - сложно. Нужно на это тратить время: для того, чтобы обойти всех заинтересованных архитекторов, смежные команды, и выработать целевое решение.
Так вот - а надо ли его искать? Несмотря на то, что ответ вроде бы очевиден, хотел бы подсветить несколько потенциальных проблем.
Затрачивая время на поиск и согласование целевого решения мы взамен хотим получить уверенность, что решение с нами останется "на века". Так ли это? Нет, не так. Во-первых мир меняется очень сильно, бизнес задачи меняются вместе с ним. Во-вторых технологии меняются еще сильнее. В-третьих - "кассандр" среди нас мало, и если есть несколько разрешенных технологий - угадать правильную сложно.
К чему это приводит? Мы потратили время на выбор и реализацию "целевки", а через год нам говорят - переделывайте. Отрицание, гнев, фрустрация. Обида на архитекторов. Причем даже если архитектор признает ошибку (и вообще эта ошибка была) - вряд ли он поможет переписать код. Обида на менеджеров - да они издеваются что ли, вечно меняют правила игры, вечная миграция... Желание сменить компанию...
Поэтому видится, что есть более надежный подход.
1) смириться с тем, что все течет, все меняется, и миграции будут всегда
2) искать целевые решение, но всегда держать в уме, что это целевое решение на данный момент
3) разделить весь код на ядро и инфраструктурный код. Ядро стараться писать на чистой Java \ Kotlin, с минимальным использованием фреймворков. Особенно, внутренних, которые еще не доказали свою стабильность. Внешние интеграции закрывать - предохранительный слой (anticorruption layer), шлюзы (gateway), адаптеры.
4) очень важно - уметь и хотеть быстро выпускать релизы, разбивать любые доработки на небольшие инкременты. Это можно сделать как улучшением качества проектирования, увеличением покрытия тестами и автотестами, так и различного рода договоренностями со смежниками, (не забываем, что мы в "кровавом enterprise")
Если вам показывался знакомым последний пункт - то да, это Agile. Или то самое снижение Lead Time (LT), о котором любят говорить менеджеры. И не только говорить) Но в данном случае они правы.
Еще пример - фондовый рынок и диверсификация. Диверсификация считается основным принципом разумного инвестора, и означает, что нельзя "класть все яйца в одну корзину". Т.е. нужно покупать разные классы активов: акции, облигации, вклады, кэш, золото, недвижимость. Причина - сложно угадать, что именно "выстрелит". В случае кода сложно конечно реализовать диверсификацию прямолинейно: часть данных хранить в PostgreSQL, а часть - в Oracle. Да и не нужно. Но предусмотреть возможность замены поставщика - нужно.
#agile #arch #arch_compromisses
Telegram
(java || kotlin) && devOps
Всем привет!
Выпил бокал пива и захотелось немного пофилософствовать)
У меня часть просят готовое решение какой-то проблемы. Это может быть способ интеграции, выбор места для хранения данных, языка программирования, способ разбиения проекта на микросервисы…
Выпил бокал пива и захотелось немного пофилософствовать)
У меня часть просят готовое решение какой-то проблемы. Это может быть способ интеграции, выбор места для хранения данных, языка программирования, способ разбиения проекта на микросервисы…
Всем привет!
Прочитал сегодня хороший пост (английский): https://korshakov.com/posts/death-of-best-practices
Чем же он хорош?
Иллюстрирует 2 мысли, про которые я топлю в своем блоге (и топлю в целом):
1) разработка - искусство компромиссов. Важно не абсолютное следование ... микросервисной архитектуре, принципам Single Responsibility или Dependency Inversion. Нет никакой магии в цифре 80% когда мы говорим о покрытии кода тестами. Денормализация таблиц из той же оперы. Важно выдавать результат, требуемый бизнесов. На код-ревью можно поспорить о принципах, но Pull Request должен быть влит в течение дня
2) быстрые, а следовательно частые релизы - наше все. Или по-менеджерски - Deployment Frequency и Lead Time (а это две грани одной и той же идеи). Это позволяет быстро править баги и уязвимости, адаптироваться к изменениям архитектуры и нормативным требованиям, проводить бета и A\B тестирование, соблюдать сроки выхода фичей.
Что спорно в посте - кликбейтный заголовок. Читать "Чистый код" или "Мифический человеко-месяц" - это не зло. Зло - следовать догматически отдельным идеям из этих книг, не разбираясь, что хотел сказать автор, и не адаптируя их к текущему проекту.
P.S. Тоже что ли кликбейтные заголовки начать делать)
#principles #dev_compomisses
Прочитал сегодня хороший пост (английский): https://korshakov.com/posts/death-of-best-practices
Чем же он хорош?
Иллюстрирует 2 мысли, про которые я топлю в своем блоге (и топлю в целом):
1) разработка - искусство компромиссов. Важно не абсолютное следование ... микросервисной архитектуре, принципам Single Responsibility или Dependency Inversion. Нет никакой магии в цифре 80% когда мы говорим о покрытии кода тестами. Денормализация таблиц из той же оперы. Важно выдавать результат, требуемый бизнесов. На код-ревью можно поспорить о принципах, но Pull Request должен быть влит в течение дня
2) быстрые, а следовательно частые релизы - наше все. Или по-менеджерски - Deployment Frequency и Lead Time (а это две грани одной и той же идеи). Это позволяет быстро править баги и уязвимости, адаптироваться к изменениям архитектуры и нормативным требованиям, проводить бета и A\B тестирование, соблюдать сроки выхода фичей.
Что спорно в посте - кликбейтный заголовок. Читать "Чистый код" или "Мифический человеко-месяц" - это не зло. Зло - следовать догматически отдельным идеям из этих книг, не разбираясь, что хотел сказать автор, и не адаптируя их к текущему проекту.
P.S. Тоже что ли кликбейтные заголовки начать делать)
#principles #dev_compomisses
Chaotic good engineering
Death of Best Practices
And why "clean code" is not the best way to build
Всем привет!
Нашел забавную статью о том, как Java превратить в BrainFuck https://ru.wikipedia.org/wiki/Brainfuck
Статья https://habr.com/ru/articles/886080/
Всегда было ощущение, что это на условном Perl можно написать не очень понятную строку кода, выглядящую прилично, а на самом деле форматирующую диск C:) Ну или на Scala на худой конец. А тут Java.
У меня только один вопрос по первому примеру - где код программы, которая подбирала эти магические числа?
А второй отлично показывает, чем может быть вредно Reflection API. Убирать его конечно не надо, но подумать о защите для системных классов стоило бы.
#java
Нашел забавную статью о том, как Java превратить в BrainFuck https://ru.wikipedia.org/wiki/Brainfuck
Статья https://habr.com/ru/articles/886080/
Всегда было ощущение, что это на условном Perl можно написать не очень понятную строку кода, выглядящую прилично, а на самом деле форматирующую диск C:) Ну или на Scala на худой конец. А тут Java.
У меня только один вопрос по первому примеру - где код программы, которая подбирала эти магические числа?
А второй отлично показывает, чем может быть вредно Reflection API. Убирать его конечно не надо, но подумать о защите для системных классов стоило бы.
#java
Wikipedia
Brainfuck
эзотерический язык программирования, придуманный Урбаном Мюллером в 1993 году
Качественное ли у вас API? А чем докажете?)
Как мы проверяем код на качество? SonarQube, покрытие кода тестами. Если говорить о code style - CheckStyle-ом. Если говорить об уязвимостях - проверка по базам уязвимостей (разные тулы), Checkmarx.
А можно ли как-то проверить API на соответствие лучшим практикам? В частности, OpenAPI как самый типовой на данный момент вариант.
Да - для этого есть Spectral linter https://meta.stoplight.io/docs/spectral/a630feff97e3a-concepts
У него три основных достоинства:
1) это linter и его можно включить в CI pipeline
2) у него есть наборы предустановленных правил, в частности:
а) OpenAPI rules https://meta.stoplight.io/docs/spectral/4dec24461f3af-open-api-rules
б) URL rules https://apistylebook.stoplight.io/docs/url-guidelines - использование kebab-case, не использование get в URL...
в) OWASP rules https://apistylebook.stoplight.io/docs/owasp-top-10 - безопасность, например, использование uuid вместо чисел в идентификаторах
...
3) возможность добавлять свои правила https://meta.stoplight.io/docs/spectral/01baf06bdd05a-create-a-ruleset в том числе наследуясь от существующих
Ну и отдельно отмечу, что есть плагин для IDEA https://plugins.jetbrains.com/plugin/25989-spectral-linter
Итого - штука полезная, настоятельно рекомендую попробовать.
#api #arch #code_quality
Как мы проверяем код на качество? SonarQube, покрытие кода тестами. Если говорить о code style - CheckStyle-ом. Если говорить об уязвимостях - проверка по базам уязвимостей (разные тулы), Checkmarx.
А можно ли как-то проверить API на соответствие лучшим практикам? В частности, OpenAPI как самый типовой на данный момент вариант.
Да - для этого есть Spectral linter https://meta.stoplight.io/docs/spectral/a630feff97e3a-concepts
У него три основных достоинства:
1) это linter и его можно включить в CI pipeline
2) у него есть наборы предустановленных правил, в частности:
а) OpenAPI rules https://meta.stoplight.io/docs/spectral/4dec24461f3af-open-api-rules
б) URL rules https://apistylebook.stoplight.io/docs/url-guidelines - использование kebab-case, не использование get в URL...
в) OWASP rules https://apistylebook.stoplight.io/docs/owasp-top-10 - безопасность, например, использование uuid вместо чисел в идентификаторах
...
3) возможность добавлять свои правила https://meta.stoplight.io/docs/spectral/01baf06bdd05a-create-a-ruleset в том числе наследуясь от существующих
Ну и отдельно отмечу, что есть плагин для IDEA https://plugins.jetbrains.com/plugin/25989-spectral-linter
Итого - штука полезная, настоятельно рекомендую попробовать.
#api #arch #code_quality
docs.stoplight.io
Concepts | Spectral
The power of integrating linting into the design-first workflow, or any workflow which involves API descriptions, is often overlooked. Linting isn't just about validating OpenAPI or JSON Schema documents against specifications. It's for enforcing ... Powered…
С чем проще работать - Maven vs Gradle?
Как ни странно - ответ на этот вопрос не очевиден.
Если говорить о чтении глазами разработчиком - Gradle выглядит попроще т.к. там почти нет boilerplate кода. И тот, и другой инструмент придерживаются принципа convention over configuration, но Maven проигрывает из-за xml.
Но если проект начинает развиваться - что-то может пойти не так) Gradle позволяет легко выстрелить себе в ногу создав очень сложный скрипт деплоя. Причем много кода появляется там, где его не ожидаешь - в build скрипте. И этот код не на Java, т.е. может отличаться от кода проекта. А если добавить сюда multiproject - разбираться в этом становится сложно. Maven выносит весь императивный код в плагины, скрипты сборки чисто декларативные.
И можно глянуть с другой стороны - со стороны tooling, например, той же IDEA. Тут победа на стороне Maven - распарсить xml легко, а вот чтобы понять структуру Gradle проекта - нужно начать его исполнять. Это и дольше, и процесс подвержен ошибками, а в теории и уязвимостям.
Вывод - оба инструмента хороши, имеют свои плюсы и минусы. Рекомендую изучить оба. Я для себя не определился)
#buildtool #maven #gradle #conv_over_conf
Как ни странно - ответ на этот вопрос не очевиден.
Если говорить о чтении глазами разработчиком - Gradle выглядит попроще т.к. там почти нет boilerplate кода. И тот, и другой инструмент придерживаются принципа convention over configuration, но Maven проигрывает из-за xml.
Но если проект начинает развиваться - что-то может пойти не так) Gradle позволяет легко выстрелить себе в ногу создав очень сложный скрипт деплоя. Причем много кода появляется там, где его не ожидаешь - в build скрипте. И этот код не на Java, т.е. может отличаться от кода проекта. А если добавить сюда multiproject - разбираться в этом становится сложно. Maven выносит весь императивный код в плагины, скрипты сборки чисто декларативные.
И можно глянуть с другой стороны - со стороны tooling, например, той же IDEA. Тут победа на стороне Maven - распарсить xml легко, а вот чтобы понять структуру Gradle проекта - нужно начать его исполнять. Это и дольше, и процесс подвержен ошибками, а в теории и уязвимостям.
Вывод - оба инструмента хороши, имеют свои плюсы и минусы. Рекомендую изучить оба. Я для себя не определился)
#buildtool #maven #gradle #conv_over_conf
Не Spring-ом единым...
Появилась еще одна библиотека для Java для работы с LLM, а точнее конкретно с OpenAI. Официальная, от OpenAI
<dependency>
<groupId>com.openai</groupId>
<artifactId>openai-java</artifactId>
<version>0.22.0</version>
</dependency>
На что хотелось бы обратить внимание:
1) OpenAI наконец то "дошла" до Java разработчиков
2) Разработчики библиотеки очень любят method chaining (ссылка на статью с примерами в конце поста). Со стороны даже кажется, что череcчур, можно было бы и по-короче инициализировать библиотеку
3) есть поддержка web-поиска
4) есть неочевидное разделение на Completion API - простые вопросы к LLM, типа "как на Java получить список файлов в каталоге" и Assistants API - "напиши мне микросервис, возвращающий курсы акций на бирже". Почему неочевидное - в моделях я вижу обратную тенденцию к унификации, когда одна модель используется для всех типов задач.
5) Assistants API умеет в File Search и Code Interpreter
И небольшой каталог решений по работе с LLM на Java:
1) Spring AI - https://docs.spring.io/spring-ai/reference
Примеры использования:
hello world https://habr.com/ru/articles/784128/
Более сложные примеры
https://piotrminkowski.com/2025/01/28/getting-started-with-spring-ai-and-chat-model/
https://piotrminkowski.com/2025/01/30/getting-started-with-spring-ai-function-calling/
Telegram bot, OpenAI и Spring AI https://habr.com/ru/companies/dockhost/articles/884876/
2) langchain4j https://github.com/langchain4j/langchain4j Характерно, что проект сделан на основе одноименной Python библиотеки. Поддерживается в Quarkus https://www.baeldung.com/java-quarkus-langchain4j
3) прямая интеграция с OpenAI https://www.baeldung.com/java-openai-api-client
P.S. Возможно Assistants API "жрет" больше токенов, отсюда и разделение
#llm #openai #ai #spring
Появилась еще одна библиотека для Java для работы с LLM, а точнее конкретно с OpenAI. Официальная, от OpenAI
<dependency>
<groupId>com.openai</groupId>
<artifactId>openai-java</artifactId>
<version>0.22.0</version>
</dependency>
На что хотелось бы обратить внимание:
1) OpenAI наконец то "дошла" до Java разработчиков
2) Разработчики библиотеки очень любят method chaining (ссылка на статью с примерами в конце поста). Со стороны даже кажется, что череcчур, можно было бы и по-короче инициализировать библиотеку
3) есть поддержка web-поиска
4) есть неочевидное разделение на Completion API - простые вопросы к LLM, типа "как на Java получить список файлов в каталоге" и Assistants API - "напиши мне микросервис, возвращающий курсы акций на бирже". Почему неочевидное - в моделях я вижу обратную тенденцию к унификации, когда одна модель используется для всех типов задач.
5) Assistants API умеет в File Search и Code Interpreter
И небольшой каталог решений по работе с LLM на Java:
1) Spring AI - https://docs.spring.io/spring-ai/reference
Примеры использования:
hello world https://habr.com/ru/articles/784128/
Более сложные примеры
https://piotrminkowski.com/2025/01/28/getting-started-with-spring-ai-and-chat-model/
https://piotrminkowski.com/2025/01/30/getting-started-with-spring-ai-function-calling/
Telegram bot, OpenAI и Spring AI https://habr.com/ru/companies/dockhost/articles/884876/
2) langchain4j https://github.com/langchain4j/langchain4j Характерно, что проект сделан на основе одноименной Python библиотеки. Поддерживается в Quarkus https://www.baeldung.com/java-quarkus-langchain4j
3) прямая интеграция с OpenAI https://www.baeldung.com/java-openai-api-client
P.S. Возможно Assistants API "жрет" больше токенов, отсюда и разделение
#llm #openai #ai #spring
Хабр
ChatGPT на Java. Пишем «Hello World» на Spring AI
В преддверии Нового Года, начинаем осваивать генеративные сети с помощью привычного всем Java разработчикам фреймворка Spring. Несколько месяцев назад в Spring добавили модуль AI , который упрощает...
Spring Events и транзакции - какие варианты?
Есть такая полезная библиотека как Spring Events https://www.baeldung.com/spring-events. Позволяет логически и\или физически разделять операции внутри сервиса используя событийную модель. Event-drive architecture или паттерн Хореография, но не между микросервисами, а внутри. Но ключевое отличие взаимодействий между микросервисами и внутри микросервиса - внутри микросервиса есть транзакции в БД. Между микросервисами - в теории тоже, используя JTA, но лучше не надо)
Так вот, какие могут быть варианты по работе с транзакциями при использовании Spring Events? Используем Spring Data JPA, есть две операции - создание клиента и генерация для него токена, по бизнесу мы хотим их разделить. Получится как-то так:
1)
public Customer createCustomer(String name) {
final Customer customer = customerRepository.save(new Customer(name));
applicationEventPublisher.publishEvent(new CustomerCreated(customer.getId()));
}
...
@EventListener
public void generateToken(CustomerCreated customerCreated) {
final Long customerId = customerCreated.getId();
final Customer customer = customerJpaRepository.findById(customerId).get();
customer.generateToken();
customerRepository.save(customer);
}
В данном случае выполнение синхронное (режим работы Spring Events по умолчанию), т.е. первая операция ждет пока все подписчики обработают событие. Следовательно, разделение процессов только логическое, что тоже может быть полезно. Обращения к БД выполняются в разных транзакциях, т.к. транзакции не используются)
2)
@Transactional
public Customer createCustomer(String name) {
final Customer customer = customerRepository.save(new Customer(name));
applicationEventPublisher.publishEvent(new CustomerCreated(customer.getId()));
}
...
@EventListener
public void generateToken(CustomerCreated customerCreated) {
final Long customerId = customerCreated.getId();
final Customer customer = customerJpaRepository.findById(customerId).get();
customer.generateToken();
customerRepository.save(customer);
}
Изменения минимальны, добавляем @Transactional на первую операцию, что приводит к тому, что операции выполняются в одной транзакции.
3)
@Transactional
public Customer createCustomer(String name) {
final Customer customer = customerRepository.save(new Customer(name));
applicationEventPublisher.publishEvent(new CustomerCreated(customer.getId()));
}
...
@TransactionalEventListener
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void generateToken(CustomerCreated customerCreated) {
final Long customerId = customerCreated.getId();
final Customer customer = customerJpaRepository.findById(customerId).get();
customer.generateToken();
customerRepository.save(customer);
}
Тут мы добавили 2 аннотации на вторую операцию, т.к. хотим обе операции выполнить в разных транзакциях. @TransactionalEventListener приводит к тому, что событие выполняется после завершения исходной транзакции, а @Transactional(propagation = Propagation.REQUIRES_NEW) открывает новую. Т.е. TransactionalEventListener не выполняет код в родительской транзакции, а синхронизирует выполнение с ней (и у него есть несколько режимов синхронизации). При этом исполнение по прежнему синхронное.
4)
@Transactional
public Customer createCustomer(String name) {
final Customer customer = customerRepository.save(new Customer(name));
applicationEventPublisher.publishEvent(new CustomerCreated(customer.getId()));
}
...
@Async
@EventListener
public void generateToken(CustomerCreated customerCreated) {
final Long customerId = customerCreated.getId();
final Customer customer = customerJpaRepository.findById(customerId).get();
customer.generateToken();
customerRepository.save(customer);
}
...
@Configuration
@EnableAsync
public class AsyncConfig {
}
Есть такая полезная библиотека как Spring Events https://www.baeldung.com/spring-events. Позволяет логически и\или физически разделять операции внутри сервиса используя событийную модель. Event-drive architecture или паттерн Хореография, но не между микросервисами, а внутри. Но ключевое отличие взаимодействий между микросервисами и внутри микросервиса - внутри микросервиса есть транзакции в БД. Между микросервисами - в теории тоже, используя JTA, но лучше не надо)
Так вот, какие могут быть варианты по работе с транзакциями при использовании Spring Events? Используем Spring Data JPA, есть две операции - создание клиента и генерация для него токена, по бизнесу мы хотим их разделить. Получится как-то так:
1)
public Customer createCustomer(String name) {
final Customer customer = customerRepository.save(new Customer(name));
applicationEventPublisher.publishEvent(new CustomerCreated(customer.getId()));
}
...
@EventListener
public void generateToken(CustomerCreated customerCreated) {
final Long customerId = customerCreated.getId();
final Customer customer = customerJpaRepository.findById(customerId).get();
customer.generateToken();
customerRepository.save(customer);
}
В данном случае выполнение синхронное (режим работы Spring Events по умолчанию), т.е. первая операция ждет пока все подписчики обработают событие. Следовательно, разделение процессов только логическое, что тоже может быть полезно. Обращения к БД выполняются в разных транзакциях, т.к. транзакции не используются)
2)
@Transactional
public Customer createCustomer(String name) {
final Customer customer = customerRepository.save(new Customer(name));
applicationEventPublisher.publishEvent(new CustomerCreated(customer.getId()));
}
...
@EventListener
public void generateToken(CustomerCreated customerCreated) {
final Long customerId = customerCreated.getId();
final Customer customer = customerJpaRepository.findById(customerId).get();
customer.generateToken();
customerRepository.save(customer);
}
Изменения минимальны, добавляем @Transactional на первую операцию, что приводит к тому, что операции выполняются в одной транзакции.
3)
@Transactional
public Customer createCustomer(String name) {
final Customer customer = customerRepository.save(new Customer(name));
applicationEventPublisher.publishEvent(new CustomerCreated(customer.getId()));
}
...
@TransactionalEventListener
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void generateToken(CustomerCreated customerCreated) {
final Long customerId = customerCreated.getId();
final Customer customer = customerJpaRepository.findById(customerId).get();
customer.generateToken();
customerRepository.save(customer);
}
Тут мы добавили 2 аннотации на вторую операцию, т.к. хотим обе операции выполнить в разных транзакциях. @TransactionalEventListener приводит к тому, что событие выполняется после завершения исходной транзакции, а @Transactional(propagation = Propagation.REQUIRES_NEW) открывает новую. Т.е. TransactionalEventListener не выполняет код в родительской транзакции, а синхронизирует выполнение с ней (и у него есть несколько режимов синхронизации). При этом исполнение по прежнему синхронное.
4)
@Transactional
public Customer createCustomer(String name) {
final Customer customer = customerRepository.save(new Customer(name));
applicationEventPublisher.publishEvent(new CustomerCreated(customer.getId()));
}
...
@Async
@EventListener
public void generateToken(CustomerCreated customerCreated) {
final Long customerId = customerCreated.getId();
final Customer customer = customerJpaRepository.findById(customerId).get();
customer.generateToken();
customerRepository.save(customer);
}
...
@Configuration
@EnableAsync
public class AsyncConfig {
}
Тут мы включаем асинхронное выполнение событий. Операции выполняются в разных транзакциях и в разных потоках.
Все варианты имеют право на жизнь, главное не забывать как работает Spring Events. Ну и если у нас есть "дешевые" транзации на БД (дешевые по сравнению с распределенными транзакциями), то имеет смысл использовать их по максимуму.
P.S. Что интересно, статья с baeldung.com по запросу Spring Events ранжируется выше официальной документации.
#spring #transactions #event_driven
Все варианты имеют право на жизнь, главное не забывать как работает Spring Events. Ну и если у нас есть "дешевые" транзации на БД (дешевые по сравнению с распределенными транзакциями), то имеет смысл использовать их по максимуму.
P.S. Что интересно, статья с baeldung.com по запросу Spring Events ранжируется выше официальной документации.
#spring #transactions #event_driven
Baeldung
Spring Events | Baeldung
The Basics of Events in Spring - create a simple, custom Event, publish it and handle it in a listener.
OpenAPI для асинхрона - а, пожалуйста
Я думаю все знают, как описать API для REST взаимодействия. OpenAPI давно уже стал стандартом.
Перечислю его основные плюсы:
1) широкое распространение
2) автоматическая генерация документации
3) онлайн редактор Swagger UI
4) генерация серверного и клиентского кода по схеме
5) стандарт покрывает не только собственно содержимое body сообщения, но и описывает всю схему взаимодействия: параметры URL, заголовки включая куки, коды ошибок. Даже адреса серверов, хотя как по мне - это спорный момент.
Но асинхронное взаимодействие, ака Event-Driven Architecture: Kafka, MQ.. - имеют свои особенности. Как минимум это:
1) нет понятия запрос-ответ, вместо этого обмен идет сообщениями
2) другой набор протоколов (хотя http есть и там, и там)
3) другая терминология - есть каналы (топик или очередь), у канала есть свои характеристики
4) в любом взаимодействии нужно описать 3 участников: producer, канал, consumer.
Поэтому появился AsyncAPI. Он достаточно сильно похож на OpenAPI:
1) тот же YAML,
2) похожи (с точностью до сказанного выше) основные блоки, из которых строится API - Info, Servers, Tags, Schemas...
Видно чем вдохновлялись авторы) Как сказано на официальном сайте: "Part of this content has been taken from the great work done by the folks at the OpenAPI Initiative."
И это хорошо.
Стандарт молодой, но уже стал стандартом ))) да, тавтология) Имеет все те же преимущества, что и OpenAPI - см. начало поста.
Вот неплохая статья с примером https://bigdataschool.ru/blog/asyncapi-specification-for-kafka-practical-example.html
Поэтому настоятельно рекомендую для использования.
#api #openapi #asyncapi
Я думаю все знают, как описать API для REST взаимодействия. OpenAPI давно уже стал стандартом.
Перечислю его основные плюсы:
1) широкое распространение
2) автоматическая генерация документации
3) онлайн редактор Swagger UI
4) генерация серверного и клиентского кода по схеме
5) стандарт покрывает не только собственно содержимое body сообщения, но и описывает всю схему взаимодействия: параметры URL, заголовки включая куки, коды ошибок. Даже адреса серверов, хотя как по мне - это спорный момент.
Но асинхронное взаимодействие, ака Event-Driven Architecture: Kafka, MQ.. - имеют свои особенности. Как минимум это:
1) нет понятия запрос-ответ, вместо этого обмен идет сообщениями
2) другой набор протоколов (хотя http есть и там, и там)
3) другая терминология - есть каналы (топик или очередь), у канала есть свои характеристики
4) в любом взаимодействии нужно описать 3 участников: producer, канал, consumer.
Поэтому появился AsyncAPI. Он достаточно сильно похож на OpenAPI:
1) тот же YAML,
2) похожи (с точностью до сказанного выше) основные блоки, из которых строится API - Info, Servers, Tags, Schemas...
Видно чем вдохновлялись авторы) Как сказано на официальном сайте: "Part of this content has been taken from the great work done by the folks at the OpenAPI Initiative."
И это хорошо.
Стандарт молодой, но уже стал стандартом ))) да, тавтология) Имеет все те же преимущества, что и OpenAPI - см. начало поста.
Вот неплохая статья с примером https://bigdataschool.ru/blog/asyncapi-specification-for-kafka-practical-example.html
Поэтому настоятельно рекомендую для использования.
#api #openapi #asyncapi
Курсы Big Data,Arenadata,Greenplum, Kafka и Spark
Swagger для асинхрона: составляем спецификацию AsyncAPI на примере Apache Kafka
Что такое AsyncAPI, зачем документировать спецификацию для EDA-архитектур и как это сделать
Зачем нужен MQ?
По работе передо мной периодически встает данный вопрос - зачем нужен MQ? Нужен ли он?
Поясню. Мы давно и успешно перешли с ESB поверх IBM WebSphere MQ на Kafka. Стало сильно лучше. В первую очередь за счет того, что получить топик Kafka, выпустить сертификаты и настроить ACL сильно проще, чем заказать доработку для на ESB. Да, это проблемы ESB, а не MQ, но их исчезновение все сразу заметили) Второй плюс: появились persistence и возможность повторной вычитки сообщения в случае сбоя - и сильно увеличилась надежность решения. И конечно же Kafka быстрее.
Как итог - Kafka используется везде и всегда. При этом есть понимание, что кроме Kafka есть другие инструменты, реализующие паттерн очередь (queue). Долгое время не мог сформулировать - в каких кейсах нужны очереди?
Ведь паттерн publisher-subscriber, реализованный в Kafka, является более общим, чем очередь. И т.об. очереди - асинхронное взаимодействие с одним producer и одним consumer - вроде бы можно делать в и Kafka. А возможность везде использовать один инструмент - это плюс.
Но если подумать - суть не в реализуемом паттерне. Ключевые отличия у Kafka и RabbitMQ (взял самую известную реализацию очередей для конкретики) другие. Покажу их на примере того, чего Kafka не умеет:
1) Kafka не удаляет сообщение после вычитки. Удаляет позднее, по TTL, вместе с партицией, но это другой алгоритм и другой use case. Т.е. первая потенциальная причина выбора очередей - необходимость гарантировать, что вычитанное одним потребителем, никогда не вычитает другой. Не скажу, что это частый кейс - возможно, требования безопасности.
2) Kafka имеет достаточно ограниченные возможности по маршрутизации. По сути на клиенте можно выбрать топик и партицию по определенному ключу. Вот и вся маршрутизация. Причем это было сделано сознательно, для достижения высокой производительности. Если нужна более сложная маршрутизация - это критерий для выбора очереди вместо Kafka. Тоже кейс не частый, и есть альтернатива в виде реализации маршрутизации на клиенте.
3) невозможно организовать конкурентную вычитку сообщений на consumer - конкуренция ограничена числом партицией. Меня число партицией после создания топика можно, но не нужно, т.к. это приводит к ребалансировке и плохо прогнозируемому падению производительности
4) у Kafka свой протокол. Поэтому если нужна поддержка существующего решения, где используется AMPQ или JMS - это не к Kafka. Особый случай, но упомянуть его надо.
Вот пожалуй и все варианты, когда Kafka не подходит.
P.S. Если знаете еще кейсы - напишите, плиз, в комментариях.
#mq #kafka
По работе передо мной периодически встает данный вопрос - зачем нужен MQ? Нужен ли он?
Поясню. Мы давно и успешно перешли с ESB поверх IBM WebSphere MQ на Kafka. Стало сильно лучше. В первую очередь за счет того, что получить топик Kafka, выпустить сертификаты и настроить ACL сильно проще, чем заказать доработку для на ESB. Да, это проблемы ESB, а не MQ, но их исчезновение все сразу заметили) Второй плюс: появились persistence и возможность повторной вычитки сообщения в случае сбоя - и сильно увеличилась надежность решения. И конечно же Kafka быстрее.
Как итог - Kafka используется везде и всегда. При этом есть понимание, что кроме Kafka есть другие инструменты, реализующие паттерн очередь (queue). Долгое время не мог сформулировать - в каких кейсах нужны очереди?
Ведь паттерн publisher-subscriber, реализованный в Kafka, является более общим, чем очередь. И т.об. очереди - асинхронное взаимодействие с одним producer и одним consumer - вроде бы можно делать в и Kafka. А возможность везде использовать один инструмент - это плюс.
Но если подумать - суть не в реализуемом паттерне. Ключевые отличия у Kafka и RabbitMQ (взял самую известную реализацию очередей для конкретики) другие. Покажу их на примере того, чего Kafka не умеет:
1) Kafka не удаляет сообщение после вычитки. Удаляет позднее, по TTL, вместе с партицией, но это другой алгоритм и другой use case. Т.е. первая потенциальная причина выбора очередей - необходимость гарантировать, что вычитанное одним потребителем, никогда не вычитает другой. Не скажу, что это частый кейс - возможно, требования безопасности.
2) Kafka имеет достаточно ограниченные возможности по маршрутизации. По сути на клиенте можно выбрать топик и партицию по определенному ключу. Вот и вся маршрутизация. Причем это было сделано сознательно, для достижения высокой производительности. Если нужна более сложная маршрутизация - это критерий для выбора очереди вместо Kafka. Тоже кейс не частый, и есть альтернатива в виде реализации маршрутизации на клиенте.
3) невозможно организовать конкурентную вычитку сообщений на consumer - конкуренция ограничена числом партицией. Меня число партицией после создания топика можно, но не нужно, т.к. это приводит к ребалансировке и плохо прогнозируемому падению производительности
4) у Kafka свой протокол. Поэтому если нужна поддержка существующего решения, где используется AMPQ или JMS - это не к Kafka. Особый случай, но упомянуть его надо.
Вот пожалуй и все варианты, когда Kafka не подходит.
P.S. Если знаете еще кейсы - напишите, плиз, в комментариях.
#mq #kafka
Можно ли быстро сделать и запустить single-file прототип на Java?
Как старый джавист я всегда немного с завистью смотрел видео, где человек на Python, PHP, Ruby пишет скрипт, содержащий достаточно сложный код и просто запускает его командой python script.py.
Не сказать, что Java ничего не делает в эту сторону:
1) JShell - позволяет просто запускать Java код без метода main построчно. Работает начиная с Java 9
2) JEP 330: Launch Single-File Source-Code Programs - не надо отдельно вызывать javac. Запуск программы работает через java HelloWorld.java. Работает с Java 11
3) JEP 477 Implicitly Declared Classes and Instance Main Methods - все тоже самое, но теперь не нужно объявлять класс (он создается неявно) и декларация метода main сильно упрощена. В режиме preview с Java 21
Но все это работает с простыми приложениями. А если нужны зависимости? Наш любимый Spring, например, с pom bom и кучей библиотек + Lombok. Да еще в нескольких файлах. Да еще хотелось бы не указывать параметры сборки в командной строке каждый раз, и не плодить лишних shell скриптов.
Когда-то подобная фича была в Spring Boot Cli - да, в Spring Boot и своя консоль. Но фичу выпилили, на мой взгляд зря. И из полезного в Cli остался по сути только аналог Spring Initialzr.
Но я отвлекся)
Кто ищет, тот всегда найдет - встречаем https://www.jbang.dev/documentation/guide/latest/index.html
Как это работает - хорошо проиллюстрировано по ссылке выше.
Я проверил на комбинации Spring Boot + Lombok все работает. Настройки из лежащего рядом application.properties подтягиваются. Единственный момент - были проблемы, если код разнесен по нескольким файлам - не обнаруживалась аннотация @Scheduled. Т.е. реализация multiple source file немного хромает, о чем разработчики предупреждают https://www.jbang.dev/documentation/guide/latest/organizing.html
Зато - все зависимости выкачиваются, код компилируется перед запуском, параметры компиляция настраиваются в файле с исходниками. Если надо - даже выкачивается Java. Принимает на вход java исходники, kotlin, упомянутый выше код для jshell, код внутри markdown (!!!) и можно даже так: jbang --code System.out.println("Hello World!")
Рекомендую к использованию!
#java #prototyping
Как старый джавист я всегда немного с завистью смотрел видео, где человек на Python, PHP, Ruby пишет скрипт, содержащий достаточно сложный код и просто запускает его командой python script.py.
Не сказать, что Java ничего не делает в эту сторону:
1) JShell - позволяет просто запускать Java код без метода main построчно. Работает начиная с Java 9
2) JEP 330: Launch Single-File Source-Code Programs - не надо отдельно вызывать javac. Запуск программы работает через java HelloWorld.java. Работает с Java 11
3) JEP 477 Implicitly Declared Classes and Instance Main Methods - все тоже самое, но теперь не нужно объявлять класс (он создается неявно) и декларация метода main сильно упрощена. В режиме preview с Java 21
Но все это работает с простыми приложениями. А если нужны зависимости? Наш любимый Spring, например, с pom bom и кучей библиотек + Lombok. Да еще в нескольких файлах. Да еще хотелось бы не указывать параметры сборки в командной строке каждый раз, и не плодить лишних shell скриптов.
Когда-то подобная фича была в Spring Boot Cli - да, в Spring Boot и своя консоль. Но фичу выпилили, на мой взгляд зря. И из полезного в Cli остался по сути только аналог Spring Initialzr.
Но я отвлекся)
Кто ищет, тот всегда найдет - встречаем https://www.jbang.dev/documentation/guide/latest/index.html
Как это работает - хорошо проиллюстрировано по ссылке выше.
Я проверил на комбинации Spring Boot + Lombok все работает. Настройки из лежащего рядом application.properties подтягиваются. Единственный момент - были проблемы, если код разнесен по нескольким файлам - не обнаруживалась аннотация @Scheduled. Т.е. реализация multiple source file немного хромает, о чем разработчики предупреждают https://www.jbang.dev/documentation/guide/latest/organizing.html
Зато - все зависимости выкачиваются, код компилируется перед запуском, параметры компиляция настраиваются в файле с исходниками. Если надо - даже выкачивается Java. Принимает на вход java исходники, kotlin, упомянутый выше код для jshell, код внутри markdown (!!!) и можно даже так: jbang --code System.out.println("Hello World!")
Рекомендую к использованию!
#java #prototyping