Kotlin
2.16K subscribers
299 photos
140 videos
18 files
436 links
Подборки полезного материала по Kotlin. По всем вопросам @evgenycarter
Download Telegram
⌨️ 🤖 Хочешь прокачаться в backend-разработке? Но справишься ли ты с тестом по Kotlin?

🏆 Пройди тест из 10 вопросов, проверь свой уровень знаний и приходи учиться на онлайн-курс «Kotlin Backend Developer. Professional» от OTUS!

На курсе:

✔️ Разработаете monolith, микросервисы и serverless с помощью Kotlin и фреймворков Spring, Ktor и бессерверных библиотек.
✔️ Освоите корутины для асинхронных и многопоточных задач, а также WebSocket, RabbitMQ, Kafka для транспорта.
✔️ Научитесь строить хранилища на Postgres, Cassandra, ArcadeDb и интегрировать OpenAPI с любым фронтендом.

🎫
Курс можно приобрести в рассрочку

➡️ Пройди тест и присоединяйся к группе: https://vk.cc/cRE8JF

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
Джедайские техники Kotlin: inline-функции и reified-типы

Kotlin радует лаконичным синтаксисом и мощными фичами, но некоторые из них остаются недооценёнными. Сегодня поговорим про две джедайские техники Kotlin, о которых многие слышали, но не все используют в полной мере: это inline-функции и reified-типы.

https://habr.com/ru/companies/otus/articles/970264/

✍️ @kotlin_lib
👍4
Building Responsive Applications with RxKotlin with Sarp Remzi Aksu

Этот доклад посвящён принципам реактивного программирования и показывает, как RxKotlin можно использовать для управления асинхронными операциями, обработки потоков данных и построения реактивной архитектуры. Также мы рассмотрим стратегии интеграции RxKotlin с другими возможностями и библиотеками Kotlin, обеспечивая чистый и поддерживаемый код. По итогам сессии участники получат прочное понимание реактивного программирования с RxKotlin и смогут создавать высокоотзывчивые и надёжные приложения.


https://www.youtube.com/watch?v=Og2vqfPkvm4

✍️ @kotlin_lib
👍1
This media is not supported in your browser
VIEW IN TELEGRAM
🤖 Как сделать свой оператор Flow и не сломать логику приложения

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

❗️ Разберём подходы, которые помогают писать читаемый и поддерживаемый асинхронный код. Урок будет полезен Android-разработчикам уровня junior+, которые уже знакомы с Flow и хотят разобраться, как расширять его под реальные задачи.

🗓 8 декабря, 20:00 МСК. Открытый урок проходит в преддверии старта курса «Android Developer. Professional». Регистрация открыта: https://vk.cc/cS2KQn

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
Ktor Server Fundemantals. Часть 1

Освойте разработку бэкенда на Ktor с использованием Kotlin! Эта серия материалов охватывает основы Ktor, маршрутизацию, обработку запросов, аутентификацию и другие ключевые концепции, которые помогут вам эффективно создавать надежные серверные приложения.

источник

✍️ @kotlin_lib
👍3🥰1
This media is not supported in your browser
VIEW IN TELEGRAM
Маленький экран — серьёзный вызов!

В VK мобильные разработчики создают опыт, который помещается в карман, но работает на миллионах устройств. Узнайте об их подходах к сложным задачам и ключевых результатах. По ссылке — ролики и даже вакансии!
Debounce vs Sample в Kotlin Flow

Ну что ж, пора снова погрузиться в мир Flow! Сегодня мы выносим на первый план два недооценённых инструмента: debounce и sample.

Про debounce многие из вас уже слышали, а вот про sample — гораздо реже. И, если быть честными, некоторые вообще используют debounce неправильно. Так что сейчас мы разложим всё по полочкам и сделаем эти концепции предельно понятными. Погнали! 🔥

https://proandroiddev.com/debounce-vs-sample-in-kotlin-flow-a89b4a94c893

✍️ @kotlin_lib
👍2
Kotlin: val != Immutable? 🤔

Многие новички (и не только) живут с убеждением, что ключевое слово val гарантирует неизменяемость данных. Но так ли это на самом деле?

В недавней статье на ProAndroidDev разбирают популярное заблуждение: val - это read-only (доступ только для чтения), но никак не immutable (неизменяемость).

Вот два кейса, когда ваш «неизменяемый» val может измениться:

1️⃣ Изменяемость самого объекта
val гарантирует только то, что ссылка на объект останется той же. Но если объект внутри изменяемый - его состояние можно менять без проблем.


val list = mutableListOf(1, 2, 3)
list.add(4) // Ссылка та же, содержимое изменилось


2️⃣ Кастомные геттеры
Это самый коварный момент. Свойство val может возвращать разные значения при каждом обращении, если у него переопределен get().


val random: Int
get() = Random.nextInt()


В статье также приводят интересную статистику: в опросе 41% разработчиков ответили, что считают val именно immutable, что технически неверно.

По-настоящему неизменяемым объект становится только тогда, когда он состоит из примитивов или других неизменяемых объектов (например, Data Class, где все поля val и нет ссылок на мутабельные типы).

https://proandroiddev.com/the-val-property-immutable-in-kotlin-2e4cf49207d0

✍️ @kotlin_lib
👍3🤡3🫡1
SourceCraft обновился — теперь всё ещё проще, быстрее и безопаснее

🤖 ИИ-обновления помогают тестировать код: улучшенный поиск уязвимостей и генерация описаний к изменениям теперь встроены в платформу.
🔧 Для команд: поддержка Gitlab CI/CD YAML, обновлённая система релизов, web-интерфейс для решения конфликтов в PR и управление командами в одном окне.
🔒 Для безопасности: новый дэшборд уязвимостей по всей организации, страница Code Scanning с результатами SAST, rescan и список уязвимых библиотек в SCA. Платформа прошла оценку соответствия ФЗ-152, PCI DSS и ГОСТ 57580.

А еще, обновлён UI для CI/CD и добавлены Telegram-уведомления.

Расскажем в подробностях и ответим на вопросы в канале
2👍1
🩸 Value Classes: Когда «оптимизация» убивает перформанс

Мы привыкли думать, что value class - это серебряная пуля для Type Safety без оверхеда. Обернули Int в UserId, и в рантайме это просто int, верно?

Не всегда. Есть сценарии, где value class начинает вести себя хуже, чем обычный data class, порождая скрытый боксинг на ровном месте.

Рассмотрим классический кейс: попытка написать обобщенный обработчик.


@JvmInline
value class UserId(val id: Int)

fun <T> handle(item: T) {
// Какая-то логика
println(item)
}

fun main() {
val uid = UserId(42)
handle(uid) // <--- Здесь происходит магия (плохая)
}



Что происходит под капотом?

В момент вызова handle(uid) компилятор сталкивается с проблемой. Функция handle ожидает T (который в JVM стирается до Object), а UserId в скомпилированном виде - это примитив int.

Чтобы передать int туда, где ожидается Object, JVM обязана его упаковать.

1. Создается экземпляр-обертка UserId в куче (heap allocation).
2. Этот объект передается в функцию.
3. Если внутри функции мы снова кастуем его к конкретному типу, происходит анбоксинг.

Еще хуже: Интерфейсы

Если ваш value class реализует интерфейс, и вы работаете с ним через ссылку на этот интерфейс - вы гарантированно получаете боксинг.


interface Identity {
fun raw(): Int
}

@JvmInline
value class GroupId(val id: Int) : Identity {
override fun raw() = id
}

fun process(id: Identity) { ... } // 100% боксинг при вызове



Почему это важно?

Если вы используете value classes в горячих циклах (hot paths) или высоконагруженных стримах, думая, что экономите память, использование их в качестве дженериков или через интерфейсы приведет к обратному эффекту:

🖤GC Pressure: Вы создаете короткоживущие объекты-обертки тысячами.
🖤Снижение производительности: Аллокация + боксинг/анбоксинг стоят дороже, чем передача ссылки на обычный объект.

Как лечить?

1. Избегайте интерфейсов на value classes, если критична производительность.
2. Специализируйте функции. Вместо fun <T> handle(t: T) пишите перегрузки для конкретных value типов, если это возможно.
3. Ждите Project Valhalla. Настоящие примитивные классы в JVM решат эту проблему фундаментально, но пока мы живем с ограничениями Type Erasure.

Итог: value class идеален для доменной модели и сигнатур функций, но будьте предельно осторожны, как только они попадают в полиморфный контекст.

#kotlin #performance #jvm #senior

✍️ @kotlin_lib
Please open Telegram to view this post
VIEW IN TELEGRAM
👍42
💀 ThreadLocal в мире Coroutines: Цена магии

Все знают: ThreadLocal привязан к потоку. Корутины могут прыгать между потоками. Это конфликт.
Большинство знает решение: asContextElement().
Но немногие задумываются, как именно это работает и почему злоупотребление этим механизмом может просадить пропускную способность сервиса.

Проблема: M:N Threading

В мире корутин один и тот же бизнес-процесс может начать выполняться на Thread-1, приостановиться (IO), и продолжить на Thread-2.
Если вы положили данные в ThreadLocal (например, RequestID для логирования) и не передали их в контекст корутины - после саспенда вы эти данные потеряете. Или, что хуже, прочитаете "грязные" данные от другой корутины, которая использовала этот поток ранее.

Решение: ThreadContextElement

Kotlin предлагает мост: ThreadLocal.asContextElement(value).
Выглядит просто, но под капотом происходит постоянное перекладывание данных.


val myTL = ThreadLocal<String>()

launch(Dispatchers.Default + myTL.asContextElement("foo")) {
println(myTL.get()) // "foo"
delay(10) // Suspend -> поток освобождается
println(myTL.get()) // "foo" (хотя поток может быть уже другим)
}



Что происходит в DispatchedContinuation?

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

1. Mount (updateThreadContext): Перед выполнением блока кода значение из контекста корутины принудительно устанавливается в ThreadLocal текущего потока. Старое значение потока запоминается.
2. Execution: Код корутины выполняется.
3. Unmount (restoreThreadContext): Как только корутина снова саспендится или завершается, в ThreadLocal потока возвращается старое значение.

Это гарантирует, что мы не загрязняем потоки пула.

📉 Скрытый оверхед (Performance Penalty)

Это не бесплатно. Если у вас в стеке корутины 5 элементов ThreadContextElement (MDC, SecurityContext, Tracing, TenantId и т.д.), и ваша корутина делает 100 саспендов (например, частые мелкие IO или yield()), то 100 раз произойдет цикл:
Save Old State -> Set New State -> Run -> Restore Old State.

На высоконагруженных системах (High Throughput) это создает ощутимое давление, так как эти операции часто включают работу с ThreadLocalMap, что не так быстро, как доступ к регистрам.

Best Practices для Senior-разработчика

1. Не используйте ThreadLocal как шину данных. Передавайте явные параметры в функции (context receivers в будущем помогут).
2. Ограничьте Scope. Используйте withContext(myTL.asContextElement()) только вокруг тех участков кода, где это действительно нужно (например, вызов легаси библиотеки, зависящей от ThreadLocal), а не на уровне всего GlobalScope или корневой корутины.
3. MDC Integration. Для логирования лучше использовать специализированные библиотеки, которые умеют эффективно работать с контекстом, или копировать контекст только на границах системы, а не таскать его везде.

Вывод: asContextElement - это костыль для совместимости с Thread-bound миром. В чистом Coroutine-мире данные должны течь через аргументы или CoroutineContext, но не через ThreadLocal.

#kotlin #coroutines #concurrency #jvm #senior

✍️ @kotlin_lib
2👍2