All streams
Search
Write a publication
Pull to refresh
23
12
Григорий Мясоедов @grisha9

Java Developer, Open Source Contributor

Send message

1) тут нет никаких чудес - все зависит от модели которую использует LLM. И как правильно заметили выше делает это с опрделенной степенью вероятности. Основный посыл в том что мы генерим базойвый boilerplate код который гораздо проще доработать руками до нужного состоянии, чем писать руками, даже если LLM не совсем корректно справилась, о чем мы такжу упомянули в статье. Я сделал небольшой пример по вашему сценарию (скрины прикреплю ниже). Так наша дефолтная модель которую можно использовать в персональной подписке (первый месяц бесплатно), увидела что внутри есть вложенные объекты и спросила надо ли сделать для них тоже "ентити".
2) модель используется та которую вы выберете в настройках Explyt плагина. Более подробно можно прочитать тут. Поддержка локальных моделей тоже есть.

Спасибо за пояснение.

а вы зачем-то хвастаетесь что написали промпт для LLM который это тоже делает

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

мы автоматизировали генерацию геттеров и сеттеров

Почему вы заостряете внимаение только на одном моменте? Помимо это мы также генерируем
1) модель по SQL файлам
2) OpenAPI документацию из контроллеров и обратно
3) Конфиги Kafka/Security
4) http запросы из Postman/Curl
5) конвертация пропертей из разных форматов

И если даже говорить о геттерах и сеттерах, применимо к одной из самых популярных технологий на Spring - JPA, то хоть Java, хоть Kotlin - филды никуда не деваются. Или вам нравится писать их руками? Лично мне нет. И LLM прекрасно решает эту проблему также. Как и генерацию модели по SQL файлу. Не все фрейморки также как JOOQ умеют создавать модель по БД.

Тоже самое относится и к DTO. Kotlin филды за вас не напишет.

Не очень понимаю про что ваш коммент.

А так вам AI нагенерит кучу кода который беде лежать в репозитарии и за который придётся нести ответственность :)

А вы точно прочитали статью до конца? Или ограничились вступлением и пошли писать комментарий?

достаточно определить доменый объект и дто по желанию и все без AI

Как раз именно это мы и пытаемся автоматизировать. Практически все наши Actions о которых идет речь в статье это элементарные операции преобразования из одного в другое. И генерация DTO по JPA модели яркое тому подтверждение о чем и рассказано в статье. Чтобы не набирать шаблонный код с нуля каждый раз.
И мы не пытаемся лезть в бизнес логику приложения, пользователь может сам писать ее как хочет, хоть руками с использованием своих любимых библиотек, хоть с помощью нашего AI ассистента.
Поэтому вообще не понятно о чем вы пишите.

а как добавить туда свой плагин?

Спасибо за замечание - линк добавил.
Потомучто в настоящий момент поддержка Quarkus является частью Explyt Spring Plugin.
Почему так - мы постарались объяснить в самом первом абзаце.
И далее тоже - что это позволяет переиспользовать многие из наших "фич" также и для Quarkus

В большинстве моих проектов коллекции лежали в БД, 

Я не пойму Вы это серьезно? Да коллекция повсюду! Не в каждом приложении есть БД, и не всегда взаимодействие идет только с ней, есть еще и внешние рест-сервиса, брокеры сообщений, входные параметры их валидация, конвертация.. да всего не перечислить. Посмотрел Ваш код на гитхаб, открыл самый верхний репозиторий на го и что я там увидел? Правильно тоже коллекции.

Самое смешное мой первый друг также сказал что у него все БД и он все делает на ее стороне. На что я ему пошутил, что теперь придется добавлять базу в каждый проект, чтобы туда выгружать данные и на стороне бд решать проблему filter/map/reduce. Да и есть кейсы когда проще что то вычислить уже по имеющимся данным, чем делать второй запрос или делать страшные вещи проде union или outer join натягивая сову на глобус.

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

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

Так я поэтому и задал вопрос, про создание массивов после каждой операции, и те библиотеки что вы показали, именно так и делают - грузят память. А в c#/java/kotlin такой проблемы нет по дефолту в sdk! Все уже давно как я писал отлажено и оптимизировано. Java вообще всегда создает stream и не создает лишних списков там где это не надо, в котлин можно управлять этим поведением. И основная область применения у jvm стека также как и у го это бэкэнд, и она тоже хорошо с этим справляется, большинство банков используют этот стек.

Даже не знаю, что на это ответить. В теории - да, это звучит логично. На практике - нет, не сталкивался. 

Вот честно, не знаю даже что опять и думать) Вот взять мой реальный случай с двумя друзьями описанный выше, первый показал мне свои утилитные файлы хелперы, которые копирует из проекта в проект (все по канонам го), другой реализовал “ручками” с мапой и проходом по циклу. Даже тут мимо… Я не первый день живу и вижу как пишут код, чем больше свободы, тем больше проблем. А го как раз из за своей “бедноты” дает больше возможностей написать код по разному. 

Это как пример - заставить разные бригады собирать каркасные дома, или вывалить перед ними кучу кирпичей и сказать стройте. Ну очевидно же те кто будет строить из более крупных и готовых блоков, построят +- одинаковые и проверенные временем решения, где во втором случае каждый сам себе художник. (Понятное дело, тут тоже надо знать меру (в разнообразии элементов) и не “свалиться” в kotlin, о чем я также писал выше)

В общем мне кажется наша дискуссия зашла в тупик. Идеальных языков не бывает. Я не хочу сказать что го плохой язык, но у него также есть свои слабые стороны, очень бедная сдк и синтаксис. А у меня такое ощущение что Вы хотите мне доказать обратное что он идеален и приводите странные аргументы с Бд и что все пишут на го одинаково, с чем я категорически не согласен.

P.S. Вот лично я не ничего против не имею про исключения в го, ну есть у них такой подход - ок. Обработка исключений как по мне это всегда более бизнес специфичный кейс.

С интерфейсами мне тоже все понятно, что есть метод куда нужно передать разные объекты, по месту создается нужный интерфейс который покрывает все возможные вариации входных типов и вуаля “утиная” типизация в действии.

В целом мне достаточно того что я у Вас услышал вскользь “грустные нотки” и про тернарные операторы и про конвейерные операции, но лично я не хочу писать на “Pascal” и иметь проблемы о которых писал выше. Но в любом случае спасибо Вам за дискуссию. я все)

Заранее извиняюсь, но продолжим душную дискуссию)

Не спрашивали знакомых гоферов? Неужели все гоферы мазохисты и любят писать кучу лишнего кода?

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

И таких случаев на практике оказывается достаточно мало (ну, по крайней мере в типовых Go-шных проектах вроде утилит и бэкенда)

Я вот в бытность бэкендером регулярно использовю Stream API java/kotlin и почти любая операция с коллекциями это обращение к ним, хотя может быть проблема во мне) Да и весь код который я вижу по работе и не только - аналогично.

Нет, сильная сторона - это как раз ясность и читабельность кода.

Опять же, я не был бы столь категоричен, т.к. на многих докладах/конференциях отмечается, что реализация многопоточности в го из коробки на “зеленых” тредах, да к тому же еще в 2010 году, является во многом эталонной и не приводит к “раскраске” кода async/await и как следствие хорошо утилизирует ресурсы. В идеале конечно хотелось бы увидеть статью от кого то из крупных маркетплейсов или соц.сетей почему они выбрали го, и мне кажется не в последнюю очередь из за ресурсов, купить 1000 или 1100 серверов, как по мне большая разница в текущих реалиях.

Я не против синтаксического сахара. Я очень даже "за". И мне его в Go не хватает. НО. У него есть цена, и я не уверен, что готов её заплатить в Go

Я же не призываю сделать из go kotlin) Я и сам считаю что kotlin даже в чем то переборщил, вот например в данный момент я переписываю kotlin код за молодыми и дерзкими, где использовано все что только можно из языка и лямбда в лямбде и лямбдой погоняет) И для командной разработки backend если бы я сейчас выбирал язык то остановился бы на java, как нечто среднем. 

Но конструкции типа filter/map/reduce уже настолько прочно вошли в текущую жизнь, и уже так хорошо изучены и отлажены, что даже в java(которую часто ругают за медленное развитие) уже существуют более 10 лет, то странно ждать там подвоха. Тот же underscore помню использовали на фронте еще в 2010, когда в JS еще не завезли этих операций. А го получается вообще как будто голый язык, где грубо говоря нет ничего кроме циклов, условий и структур. Поэтому я и сравнил его с Pascal и го-код мне очень напоминает институтские лабы на Pascal) Я не говорю что надо добавить все, но такие базовые вещи очень напрашиваются. И основная стезя го это всеже не геймдев/железо/операционки где производительность особенно важна.

Go прекрасен по синтаксису! То качество, которое Вы подразумеваете, не находится в категориях хорош/плох

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

Про простоту го, которая обманчива, как выразился мой второй друг. Получается что го очень простой, но простой с точки зрения компилятора, т.к. мало ключевых слов и конструкций по сравнению с другими языками (и по моему тернарного оператора там тоже нет… ), из за этого каждый будет “рисовать так как он видит” и мы увидим больше разнообразие решений, одних и тех же типовых задач - что на мой взгляд не есть хорошо. И когда я вижу типовой код на стримах я сразу улавливаю суть, в то время как с го приходить больше вчитываться в код. Те же исходники kubernetes уже давно стали притчей во языцех.

Хорошо, что в Golang есть библиотеки которые решают данные проблемы.
Но перед тем как постить свой пост, я интереса ради поинтересовался у знакомых гофферов... и ответ был одинаков - у нас так не принято, все пишем руками или создаем утилитные функции.
И убедился что в стандартном golang sdk таких функций нет.
Вообще такую фразу "у нас так в го не принято" я слышал много где) да и видел код реальных проектов Golang на гитхабе, которые пестрят разными утилитными файлами и хелперами, которые как я понимаю кочуют из проекта в проект копипастой и код похож на старый добрый Pascal.

Я конечно могу ошибаться, поправте меня если я не прав, но те примеры которые вы скинули, они создают после каждой операции новый массив, и как я понял такого понятия как стримминг элементов коллекции в go нет, в отличии от скажем c#/java/kotlin, что сильно нагружает GC.

Но я не хочу сказать что go плохой, каждый язык призван для решения своей задачи, как я написал выше сильная сторона go это хорошая утилизация ресурсов, иначе его бы не выбирали скажем крупные маркетплейсы. И в место того чтобы появлялись статьи которые рассказывали про то как мы после перехода на go сэкномили на железе и прочих ресурсов в датацентрах например, регулярно появляются статься как я перешел на go c c#/java/kotlin и пр. и мне нравится набирать "километры" кода и читать их. Извините, но я не могу в это поверить, по синтаксису он не так хорош как языки что я привел выше и на которых я имею опыт.

Выскажу свое мнение про Go...
Для начала скажу что писать на языке в 2025 году, где нет типовых операция типа filter/map/reduce и прочее это очень больно. Возьмем простой пример где у нас есть коллекция юзеров и нам над отфильтровать их например по росту, а потом сгруппировать по нему же. Как это будет выглядеть примерно выглядеть на JS/C#/Java/Kotlin/Rust и пр.:

users.filter { it.height > 100 }.groupBy { it.height }

А как это будет выглядеть на Go?
Я не готов набирать столько текста и тем более читать на экране столько портянок с кастомной фильтрацией и группировкой. По моему это никак не вяжется с вашим первым принципом наглядностью. Где каждый будет реализовывать эти операции по своему, а джуны еще наверняка и сделают типовые ошибки для новичков при группировке, забыв проинициализировать маппу для группировки пустой коллекцией и словят NPE.

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

Но опять же в 2025 году, это уже не является чем то уникальным, в отличии от 2015 года)

Почему вы реализуете quicksort по разному? Если сделать аналогичную реализацию на Java, то все будет примерно также как и на Python

public static List<Integer> quicksort(List<Integer> arr) {
      if (arr.size() <= 1) {
          return arr;
      }
      var pivot = arr.get(arr.size() / 2);
      var left = arr.stream().filter(x -> x < pivot).toList();
      var middle = arr.stream().filter(x -> x.equals(pivot)).toList();
      var right = arr.stream().filter(x -> x > pivot).toList();
      var result = new ArrayList<>(quicksort(left));
      result.addAll(middle);
      result.addAll(quicksort(right));
      return result;
}

  public static void main(String[] args) {
      System.out.println(quicksort(List.of(3, 6, 8, 10, 1, 2, 1)));
  }

Почему для Python вы не делаете обработку ошибок, но делаете ее для Java хотя могли бы просто добавить ошибку в сигнатуру Java метода, что сильно уменьшило объем кода?

И как правильно вам уже указали в комментариях, такой код в продакшен никто не пишет, а для объективнсости надо сравнивать именно продакшен код.

Имея опыт работы на трех языках Java/Kotlin/Python, могу сказать что сильнее всего объем кода сокращает Kotlin, благодаря null safety и оператору elvis (?:), а также богатой библиотеки встроенных функций для работы с коллекциями и для трансформации значений. И работая на Python мне больше всего не хватало того что перечислил выше, особенно elvis.

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

По итогу статья содержит ложные посылы и содержит ссылки на неактуальные материалы, когда еще в Java даже Stream API не было. И несет больше вреда чем пользы, особенно для неокрепших умов, начинающих разработчиков.

Спасибо за статью и доклад на Joker 2024 - было интересно.
Хотел воспользоваться вашей библиотекой для патчинга байт кода, но нашел ее только в вашем репозитории SPYT.
Она доступна в каком либо общедоступном репозитории чтобы ее можно подключить как зависимость в билд тулзе? (Maven/Gradle)
Есть ли какие то готовые примеры по ее использованию помимо доклада?

Вопрос не ко мне, но попробую ответить)
Подобная "кастомизация" это обычная практика чтобы повлияеть на процесс сборки. Собственно для этого maven plugins и extensions и предназначены. И это не вина Maven, а проблема конкретной IDE. Сообсвенно это и побудило меня написать свой плагин. Переезд на Gradle это уж очень радикальное решение. Кстати Gradle IDEA plugin также использует Gradle таск для получения модели, как и я в своем плагине)

Да и для меня лично Maven намного проще и легковеснее и как ни странно работает быстрее для моих проектов. Так синк проекта на 100 модулей занимает 4сек. Тогда как Gradle на скрине выше 4 модуля синхронизировал 2 сек, а мой другой проект, где всего то около 20 модулей, он синхронизирует за 10 сек.

И как это решает проблему синхронизации доступа к данным?

В данной реализации volatile не нужен и в нем нет никакого смысла. Код и так корректно синхронизирован и все изменения переменной происходят под локами.

Интересная проблема. Мавен плагин, отработал как надо и вернул все зависимости что есть. Проблема была в интеграции с IDEA. Т.к. она не зависит от билд тулзов и может работать вообще без них, то надо было настроить определенные "политики" для работы с зависимостями. Я про это не знал, но благодаря вашему issue настроил как в bundled Maven plugin. Мавен возращает для каждого модуля все зависимости полностью с учетом транзитивных, а IDEA по умолчанию "докидывает" зависимости от дочерних модулей - и для мавен это не надо и приводило к jar hell в вашем примере. После фикса ваш пример у меня успешно отработал.

Поправил пока в beta канале https://plugins.jetbrains.com/plugin/22370-easy-maven/versions/beta

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

Здравствуйте. Спасибо за обратную связь. Буду признателен если сможете найти время и завести issue по проблеме с опциональными зависимостями.
Я правильно понимаю, что это связано с параметром <optional> у dependency?

"Может так оказаться", "совсем небезосновательная стратегия", "из теории", "может в другой момент"... все ежели да кабы.
Вы можете мне не поверить, но я сам за мир во всем мире, но к сожалению, не из теории, а из практики я такого, да и не только я, пока не встречал. И как уже писал в самом начале, вся тысячилетняя история челеовечества говорит об этом: покорение Америки европейцами, Индии, Китая - опиумные войны, а теперь и покорение Европы США.

Information

Rating
557-th
Location
Рязань, Рязанская обл., Россия
Date of birth
Registered
Activity

Specialization

Specialist
Lead
Java
SQL
Database
Android development