Хочу поделиться своими разочарованием и восхищением дня. Вчера начал писать нового бота, нацеленного на более широкую и игровую аудиторию, раз уж сложные и полезные боты оказываются слишком непонятыми у широкой аудитории, и выбирал для него технологический стек. Я очень хотел попробовать Kotlin Native, поскольку сам язык мне очень симпатичен и в целом хотелось бы найти что-то среднее между Go и Rust'ом. То есть мой идеал — это:
1️⃣ компилируемый в статический бинарь
2️⃣ типизированный и выразительный язык
3️⃣ с лаконичным современным синтаксисом и без лишних усложнений,
4️⃣ со сборщиком мусора,
5️⃣ с первоклассной поддержкой от компаний, IDE и сообщества, с богатой экосистемой.
К сожалению, от Котлина опять пришлось отказаться по ряду причин:
1️⃣ первая же библиотека в Гугле для создания ботов в Тг — это по сути просто мапинги датаклассов;
2️⃣ при этом без собранных артефактов под Винду в Maven Central (да, сборка тут происходит ужасно медленным после Go и Cargo Gradle'ом и артефакты под каждую платформу грузятся в привычный для джавистов репозиторий) ;
3️⃣ виндовый таргет у Котлин Нейтив — это не нативная поддержка, а MinGW;
4️⃣ клиент Ktor'а требует для своей работы сторонних движков: либо заточенных под конкретную платформу, либо якобы универсальный CIO, под который не нашёлся артефакт для моей платформы 😀;
5️⃣ очевидно, инструментал и удобство хуже, чем у настоящих нативных языков, потому что приоритет для Мультиплатформы и Нейтива — это мобильная разработка под Android и iOS (где, вероятно, он себя чувствует куда лучше, но под мои цели — под бэк — увы, не подходит);
6️⃣ gRPC тоже идёт лесом.
Так что пришлось вернуться обратно в мир Раста и в очередной раз офигеть с мощи библиотеки Teloxide. В ней не так просто разобраться, потому что примеров не очень много, манера использования системы типов и макросов достаточно недружелюбны к новичкам. Но когда всё-таки путём проб и ошибок, чтения кода и комментариев, доходишь до того, что задумал автор, остаётся только удивляться и восхищаться.
Вот свежий пример: мне нужно было пробросить в хэндлеры объект пула подключений к СУБД. Как это сделать? Статическая глобальная переменная? Захват нарушает сигнатуру. А оказалось, что всё очень просто: достаточно было вспомнить, что вообще-то dptree, на которой построен Телоксид. реализует классический DI-контейнер. То есть нам достаточно просто положить нужные объекты в DependencyMap при создании диспетчера:
let mut dispatcher = Dispatcher::builder(bot, handler)
.dependencies(deps![establish_database_connection().await?])
.build();
Библиотека его сама завернёт в Arc и будет клонировать ссылку для… прямой передачи в аргументы хэндлера! Причём их вовсе не обязательно использовать, если они не нужны. Да, с помощью мощной системы типов и магии макросов в статически типизированном языке можно писать хэндлеры, принимая только необходимые аргументы, что более характерно для динамических интерпретируемых языков типа Питона!
Ну а ещё я в очередной раз убедился, что сложные ORMы всегда проигрывают в простоте использования и надёжности у простых решений, когда Cargo Check напрочь повесил комп в попытке осознать магию Diesel. Всё-таки SQLx + refinery — наше всё!