Pull to refresh

Comments 16

jOOQ выглядит хорошо, но есть ощущение, что ресурсов или альтернативного пути развития не хватает -- сложен для простых случаев.

Не понял мысль. Джук тем и хорош, что позволяет кодить в разных стилях. Хочешь - через DSL в стиле JDBC-темплейтов. Хочешь - через рекорды в стиле JPA. С ним и OLTP и OLAP элементарно пишется. Плюс фреймворк следует дао "явное лучше неявного".

Варианты: Spring Boot, Quarkus.

А тем временем ktor уже продакшн-реди. Лично я выберу ktor для следующего случая написания простой крудошлепки с классической трехслойной архитектурой.

Не понял мысль. Джук тем и хорош, что позволяет кодить в разных стилях. Хочешь - через DSL в стиле JDBC-темплейтов. Хочешь - через рекорды в стиле JPA. С ним и OLTP и OLAP элементарно пишется. Плюс фреймворк следует дао "явное лучше неявного".

Да, тут очень кратко. У меня есть 2 более развернутые заметки: https://stepin.name/technoblog/033-kotlin-orm/ и https://stepin.name/technoblog/037-jooq/ .

Чтобы не читать: Jooq мне в целом нравится. Поддержка реактивности и Котлина в нем еще недоделана (хотя и есть, ощущение беты по фичам, не по стабильности). Больше всего не нравятся все nullable-поля в рекордах -- политика партии. В целом, предпочитаю Spring Data Repository для большинства случаев (когда хватает просто методов без всяких запросов и аннотаций) и jOOQ для сложных случаев (т.к. позволяет полностью использовать возможности БД).

ktor

Он выглядит неплохо, но мне пока что непонятны его преимущества. Spring дефолт и все знают. Quarkus быстрый и эффективный, поддерживается RedHat, но его уже догнал Spring. Если просто другой синтаксис, то не очень интересно. При переходе всегда дополнительные проблемы и нужно понимать из-за чего страдать).

JOOQ: Поддержка реактивности и Котлина в нем еще недоделана

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

Отличный шаблон! Спасибо.

Я бы только для тестов вместо JUnit взял kotest и testcontainers. Тесты на Kotest выглядят примерно так.

Для логирования очень рекомендую посмотреть в сторону kotlin-logging - так вы не будете привязаны к log4j и сможете использовать любой движёк (я предпочитаю logback с логами JSON).

Если берете GraphQL (отличный, кстати, выбор), то стоит задуматься о Schema-First подходе. Тут вместо стандартного Spring Boot Starter'а стоит посмотреть в сторону GraphQL Java Kickstart - он предлагает концепцию резолверов для Schema-First и у него из коробки можно сконфигурировать Playground. Пример Schema-First сервиса на Kotlin можете посмотреть здесь.

Спасибо за комментарий).

kotest:

  • я недавно смотрел какой-то репозитарий с ним, и Idea не понимала, что это тесты. Возможно, это как-то решается, но не занимался.

  • так как на проектах часто не один, то обычно лучше использовать более стандартные технологии

  • я когда-то занимался Rails и он напоминает https://rspec.info/ (что хорошо). В общем, да, нужно на практике попробовать будет получаться лучше или нет.

testcontainer в примере есть.

kotlin-logging: у текущего api такое же и в проде настроено, чтобы JSON был. Так что, в принципе, ничего не поменяется ни как писать логи, ни по функционалу (JSON). За ссылку спасибо -- если что-то пойдет не так, то можно и на нее перейти.

Schema First (и в частности для GraphQL):

Тут у меня как раз противоположный опыт, предпочитаю что-то типа swagger: делаю контроллер на Котлине, а схема генерируется динамически. Это никак не мешает обсуждать схему, т.к. чтобы ее сгенерировать реализацию писать не нужно: просто код контроллера. В коде быстрее и удобнее писать: привычный редактор со всеми вспомогательными штуками, медленнее в коде точно не получается. Более того, можно какой-нить встроенный UI (типа swagger ui) использовать и сделать какие-нибудь заглушки с данными сразу. Если из самого кода Котлина информации не хватает, то можно добавить аннотациями. Так что на любое совещание могу принести схему.

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

Так что я в раздумьях как лучше для Spring Boot GraphQL написать генератор схемы. Проще всего kapt и сохранять в файловую систему -- тогда не будет требоваться изменений на стороне Spring Boot GraphQL. Лучше всего динамически как в OpenAPI (найти схему через рефлексию и передать ее в Spring Boot GraphQL), но нужно будет разбираться во внутренностях Spring Boot GraphQL, чтобы интегрироваться. Посмотрим когда до этого руки дойдут.

Исключением является SQL (тут schema first с генерацией jOOQ рекордов, но, к сожалению, пока что без генерации JPA entity -- руки не дошли поразбираться что сейчас есть для этого), т.к. он гораздо сложнее OpenAPI/GraphQL и крайне важен для производительности.

Наверное, для меня OpenAPI/GraphQL вторичны: если что-то Котлин не может, то это проблема OpenAPI/GraphQL, а не Котлина. А для SQL наоборот.

kotest: я недавно смотрел какой-то репозитарий с ним, и Idea не понимала, что это тесты.

Тут в Idea нужно установить плагин Kotest

да, нужно попробовать kotest, может будет лучше

В схеме крайне важна актуальность, а на практике, если пишут схему вручную, то она часто с опечатками (невалидная) и устаревшая.

У меня по GraphQL схеме автоматически генерируются DTO'шки и интерфейсы Kickstart резолверов. Интерфейсы резолверов имплементирует сервер - соответственно у меня схема в принципе не может быть невалидной, потому что по схеме генерируется код. В этом собственно вся прелесть подхода schema first. Из дополнительных бонусов - можно все согласовать с фронтендерами ДО того, как написал GraphQL сервис. Потому что разработка начинается с написания схемы. А схему можно согласовать со всеми заинтересованными лицами. Сразу упрощается коммуникация.

Генерация -- это хорошо, но еще лучше без нее (как в openapi), т.к. ее либо руками нужно запускать, либо она отнимает время при каждой сборке. Плюс, сложности при внесении изменений. Например, какое-то вычислимое поле в DTO сделать или что-то такое.

Из дополнительных бонусов - можно все согласовать с фронтендерами ДО того, как написал GraphQL сервис. Потому что разработка начинается с написания схемы.

Вот тут я чувствую свое бессилие в объяснении позиции. Этот аргумент часто употребляется, но, как по мне, это не отличается.

Да, начинается со схемы. Но где ее писать? Я предпочитаю в IDE в виде Котлин-кода. Писать код и получить из него схему не дольше. Тут я говорю про OpenAPI и GraphQL в Quarkus, в Spring ситуация с GraphQL другая, т.к. подход не поддерживается. Так же этом может быть точнее, особенно если какие-то классы с данными уже есть.

Далее можно обсуждать спеку в формате GraphQL. Обычно ее приношу я. Изменения после совещания легко отследить и внести -- обычно никаких проблем на данном этапе нет.

В принципе, если бы мне какие-нибудь бизнес-аналитики приносили GraphQL-спеку, то да, я бы генерировал из нее код. Разово или на постоянной основе зависит от того обновляли бы они его с компьютерной (а не человеческой) точностью или нет.

Ну, спор Code First vs Schema First это как война остроконечников и тупоконечников - вопрос скорее религиозный :) У каждого тут свои предпочтения :)

Да, начинается со схемы. Но где ее писать?

Я пишу в идее в файлах с расширением graphqls. Идеевский GraphQL плагин подерживает подсветку синтаксиса в таких файлах и автокомплит. Выглядит это примерно так (тут схема расположена в одном файле, но можно и по нескольким файлам ее раскидать). Потом с помощью Kobby плагина генерирую весь необходимый код - и клиентскую и серверную часть. В "боевых" проектах я обычно выношу API в отдельный проект - в нем схема и сгенерированные Kotlin клиент и DTO'шки с интерфейсами резолверов для сервера. Проект собираю в jar и деплою в мавеновский репозиторий. А потом проект с API подключаю как зависимость и к серверу и к клиенту. Если изменился API - то клиент об этом узнает на этапе компиляции, а не в рантайме.

Я такой подход к разработке практикую последние 2 года. За это время я еще не написал ни одной DTO'шки вручную :) DTO'шки за меня Kobby пишет :)

От спрингбута уже плохеет если честно. 7 лет назад сменили Java на kotlin. И через год весь этот спринг, и его Бут из стека ушли в небытие. Для экосистемы kotlin полно микро фреймворков и di. Мы используем. Ktor и kodein. Короче тут не про то как выстроить экосистему ориентированную на kotlin и его специфику, а скорее как впихнуть kotlin в этот жутковатый и полный мемов про оверинжениринг шаблон со спрингами и прочим

Спасибо за комментарий и что поделились опытом).

Короче тут не про то как выстроить экосистему ориентированную на kotlin и его специфику

Да, не было цели взять Kotlin + всё, что только для него написано, и посмотреть как это будет. Выбор компонентов кратко описан.

От спрингбута уже плохеет если честно. 7 лет назад сменили Java на kotlin. И через год весь этот спринг, и его Бут из стека ушли в небытие. Для экосистемы kotlin полно микро фреймворков и di. Мы используем. Ktor и kodein. ... а скорее как впихнуть kotlin в этот жутковатый и полный мемов про оверинжениринг шаблон со спрингами и прочим

Я не пользовался ни Ktor, ни kodein. Возможно, из-за привычки не вижу проблем со спрингом и прочим. Можете раскрыть свою мысль чем стек Ktor и kodein лучше?

В идеале, конечно, форкнуть репозитарий и показать как это будет. Тогда можно будет "пощупать", понять плюсы/минусы. Мы же все-таки про код, а не теории. Конечно, я понимаю, что это наверняка займет несколько дней, поэтому вероятность не очень большая.

Да что тут особо рассказывать. Чтобы еще и не холиварить. Я лично много на чем успел пописать и поработать, поэтому не было ничего что я бы считал данностью как бы такой, дефолтной. И когда основной стек был Java использовали Spring, потому что по сравнению с Java EE и с его ужасными шаблонами, большими этими сервлет-серверами - Spring был как глоток свежего воздуха. Сам настраиваешь контейнера там, есть на все шаблоны там, готовые бины, все как-то магически заводится.

Потом в какой-то момент просыпаешься ночью в холодном поту и думаешь "а нафига я подключаю NHibernate или JPA чтобы прочитать из базы пару запросов? " и такой голос шепчет "а как же поддержка всех 100500 видов баз, нужен универсальный ORM, а для этого нужна еще специальная конфигурация и мигратор и вот же - на тебе Spring в нем это все есть" - вроде успокаиваешься. Потом у тебя в стоке приложение начинает стартовать по минуте, потом подсасывать на AutoScan столько всего ненужного из всех библиотек, что нет столько в мире аннотаций, чтобы все это понять и задизейблить.

И потом например просто для развлекухи открываешь в стоке ну там гошку и на ванильной гошке пишешь рубленными мазками то же самое, только без всяких ентерпрайз-наворотов и памяти так раз в 100 меньше и на диске без половины интернета. И снова понимаешь, что в чем-то засада и вспоминаешь, что когда до этого работал не с Java/EE/Spring, то вроде как-то спокойно все писалось без 10 уровней якобы обоснованно существующих прокладок. Понимаешь, что без всяких ORM больших спокойно кастовал рекордсеты в структуры, что все равно все время дооплетать до неузнаваемости приходится все эти штатные мидлвары для MVC на спринге. И понимаешь, что ну какой-то бойлерплейт ради бойлерплейта а на флаге написано, что это якобы солиднейший SOLID.

И когда перевели все на Kotlin (как язык) сначала тоже был просто Kotlin а остальное что было на тот момент Maven/Spring и все остальное что всегда в таких случаях тогда была. Ну а где язык - начинаешь смотреть - а что там по экосистеме, а что по библиотекам, куда вообще ветер дует. Ну и совершенно другой стек начинает вырисовываться гораздо ближе по духу к тому что можно видеть в go, - более рубленный ООП без "факторок для создания факторок производящих билдеры", никаких "аспектов", явно управляемые контейнеры зависимостей, микрофреймворки с ручной настройкой для REST/gRPC - и как некогда радовались переходя с EE на Spring, так потом радовались когда и это марево рассеялось )))

Рассеивай не рассеивай. Kotlin все же стал развиваться больше для андроида, чем в Native и в этой своей ипостаси не является конкурентом ни GO ни Rust ни плюсам, пока непонятной успешности эксперимент, а Java не стала лучше - как требовала полинтернета для сборки и немеряно гигабайтищ памяти - так и требует, "микросервисы" получаются совсем не "микро". В итоге как бы мне не нравислся Kotlin как язык - а он у меня шесть лет уже топ 1, очень много новой разработки уже на Golang, хотя Go как язык конечно менее выразительный, хотя тоже не противный, своя прелесть в нем есть. Но экосистема, скорость и прозрачность сборки... Golang-у наверное сейчас нет равных если честно.... А тема все та же - прямые, понятные, рубленные решения в лоб и полный контроль над тем что происходят по факту удобнее любых навороченных средств с 10 слоями прокладок.

В целом, я поддерживаю стремление к простоте. И от JEE на Rails переходил, и на Golang программировал, и на Python FastAPI.

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

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

При этом, вполне возможно, есть подходы и лучше. Чтобы собрать обратную связь это и публиковалось. Например, тот же Ktor предлагается несколькими людьми. Но у меня с ним опыта нет, а замена Spring -- это практически весь шаблон переделать. Если мы при этом ничего не потеряем (читаемость и кол-во кода приложения и всю дополнительную функциональность, которая уже заложена в шаблоне), а только приобретем более быстрый старт и меньший размер на диске и в памяти -- я двумя руками "За". Но хотелось бы такое увидеть не от неофита в Ktor фреймворке и его окружении (меня), а от человека, который это уже использует года, т.к. наверняка есть моменты в конфигурации и лучших практиках, которые можно показать в шаблоне. Если же это окажется примерно то же самое или хуже, то переходить нет смысла.

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

Sign up to leave a comment.

Articles