Какую фичу вы считаете самой лучшей в Kotlin? (Обязательно пиши в комментариях почему именно она)
Anonymous Poll
17%
data class/object
13%
sealed class/interface
20%
extention function/property
34%
Nullable типы
3%
inline функции (с reified или без)
1%
companion object
2%
delegated property
2%
delegate в классах
1%
Другая (пиши в комментариях)
7%
Не участвую
Для меня ключевой фичёй языка Kotlin является - Nullable типы (Null-safety)
Почему?Это позволило сделать систему типов более строгой, избавиться от проверок на null или наоборот принуждает их выполнить! После опыта Java именно проблема с null была самой большой (известная как “Billion Dollar Mistake”)!
Выделить отдельную фичу невероятно трудно, но я это делал именно по ценности для конечного продукта и его стабильности. Все возможности Kotlin как набор звуков - соединив их вместе, получаешь прекрасную музыку. Только как и с любым музыкальным инструментом в раках дилетанта может получиться что-то страшное и пугающее 🤬
Почему?
Выделить отдельную фичу невероятно трудно, но я это делал именно по ценности для конечного продукта и его стабильности. Все возможности Kotlin как набор звуков - соединив их вместе, получаешь прекрасную музыку. Только как и с любым музыкальным инструментом в раках дилетанта может получиться что-то страшное и пугающее 🤬
Традиционный релиз, который ждут многие, чтобы переходить на новую версию языка. Релиз содержит исправление ошибок и улучшения
#kotlin
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Что нового:
👉 Обновленный дизайн
👉 Упростили настройку проекта
👉 Превью проекта, который будет сгенерирован
#kotlin #ktor
Please open Telegram to view this post
VIEW IN TELEGRAM
Что бы вы изменили в это коде и почему?
fun PersonDto?.toPerson(): Person? =
if (this == null) {
null
} else {
Person(
name = name,
surname = surname,
age = age
)
}
Kotlin Multiplatform Broadcast
Что бы вы изменили в это коде и почему? fun PersonDto?.toPerson(): Person? = if (this == null) { null } else { Person( name = name, surname = surname, age = age ) }
Не делайте single-expression функции, если она занимает у вас больше 1 строки
Пример кода из поста выше читается очень сложно из-за многострочного if/else, который используется как выражения для функции чтобы не писать тело. Правило просто - в функции больше одной строки, то точно объявляете тело {}
Исключения бывают, о них ниже
Код и поста станет выглядеть так
Пример кода из поста выше читается очень сложно из-за многострочного if/else, который используется как выражения для функции чтобы не писать тело. Правило просто - в функции больше одной строки, то точно объявляете тело {}
Исключения бывают, о них ниже
Код и поста станет выглядеть так
fun PersonDto?.toPerson(): Person? {
if (this == null) {
return null
} else {
return Person(
name = name,
surname = surname,
age = age
)
}
}
Когда полезно использовать single-exression fun
Есть удобные кейсы, когда многострочные single-expression функции могут быть полезны. Все они связаны с вызовом функции/инструкции с телом, например
Есть удобные кейсы, когда многострочные single-expression функции могут быть полезны. Все они связаны с вызовом функции/инструкции с телом, например
fun a() = when(...) {
// Позволяет сделать exhausted when,
// через обязательный возврат значений в каждой ветке
// Предпочитаю с каждом case делать только одну строчку,
// все что больше - переношу в функции и вызываю её
// С if-else так красиво не выглядит, но тоже можно
}
fun b() = buildList {
// билдер функция коллекции
}
fun c(...) = with(...) {
// Изменил this в блоке кода
}
Смысл делать расширения для Nullable типа бывает очень редко. В примере, что я привёл вам выше произошло только усложнения кода и добавления дополнительной инструкций т.к. null вернет null. Операторы для работы с Null safety (
?.
и ?:
) прекрасно справляются с этимКак понять стоит ли делать расширение для Nullable функции - объясните себе нестандартное поведение для null значения либо функция имеет суть только в случае Nullable типа
Обновленный код будет выглядеть так:
fun PersonDto.toPerson(): Person {
return Person(
name = name,
surname = surname,
age = age
)
}
val personDto: Person? = ...
val person: Person? = personDto?.toPerson()
Please open Telegram to view this post
VIEW IN TELEGRAM
Используйте trailing comma при работе с аргументами
trailing comma полезная фича, чтобы сделать историю в VCS боле красивой. Давайте на примере:
теперь мне надо добавить новое свойство и задавать его
После таких изменений в VCS отразиться изменения в 2 строчках - номер 4 и 5. Если же изначально я использовал trailing comma везде, то изменение было бы только в одной строке - 5.
Другой пользы от trailing comma фичи я не знаю, а вы можете поделиться в комментариях
UPD: в IDE ещё удобно менять порядок передачи именованных аргументов в многострочном вызове функции
trailing comma полезная фича, чтобы сделать историю в VCS боле красивой. Давайте на примере:
Person(
name = name,
surname = surname,
age = age // Без необязательной запятой после последнего аргумента
)
теперь мне надо добавить новое свойство и задавать его
1 Person(
2 name = name,
3 surname = surname,
4 age = age, // Добавил запятую для отделения инструкций
5 id = id
6)
После таких изменений в VCS отразиться изменения в 2 строчках - номер 4 и 5. Если же изначально я использовал trailing comma везде, то изменение было бы только в одной строке - 5.
Другой пользы от trailing comma фичи я не знаю, а вы можете поделиться в комментариях
UPD: в IDE ещё удобно менять порядок передачи именованных аргументов в многострочном вызове функции
Какой подход вы предпочитаете для маппинга моделей ? (пишите в комментариях почему)
Anonymous Poll
63%
fun PersonDto.toPerson(): Person
5%
fun Person.from(PersonDto): Person
4%
fun Person(PersonDto): Person
16%
interface Mapper<IN, OUT> { fun map(IN): OUT }
2%
Генерация кода маппинга
3%
Другой подход
8%
Не участвую в опросе
Вы используете Decompose?
Anonymous Poll
12%
Да, в KMP проекте
8%
Да, в проекте под одну платформу
19%
Что это?
53%
Нет
1%
Не пишу код
8%
Не участвую в опросе
Пример (EN,8М) автоматизации генерации классов UI модели на основе параметров Composable функциb. Используется KSP для генерации кода
🔗 Ссылка без VPN
#kotlin #compose #ksp
🔗 Ссылка без VPN
#kotlin #compose #ksp
Не стоит использовать CoroutineScope, отвязанный от приложения
Порой в коде встречается ситуация, когда для запуска корутины в репозитории или каком-либо менеджере разработчики создают CoroutineScope:
Но есть вариант хуже:
0️⃣ CoroutineScope не должен создаваться для запуска только одной корутины. ‼️
1️⃣ При создании
2️⃣ CoroutineScope должен быть связан с каким-либо жизненным циклом объекта. Вся суть scope заключается в том, чтобы отменять операции, когда они больше не нужны. Например, viewModelScope привязан к жизни ViewModel. В Android приложениях я всегда создаю Scope, связанный с Android Application классом, - AppScope. Либо использовать AppScope в классах, где нужен scope, либо сделать scope, который будет связан с другим CoroutineScope приложения.
Создать дочерний Scope можно следующим образом:
3️⃣ Вам точно нужен запуск корутины? Или подойдет suspend функция? Определитесь, почему асинхронный код должен работать независимо от вызывающего его кода и не иметь возможности получения информации об окончании работы через suspend. Также можно возвращать объект Job (хотя это спорная практика, на мой взгляд).
4️⃣ Не используйте ‼️ Это наследие старых корутин, когда ещё не было structured concurrency.
Что можете посоветовать вы авторам подобного кода, помимо почитать документацию и курсы? Пишите в комментариях.
#kotlin #coroutines
Порой в коде встречается ситуация, когда для запуска корутины в репозитории или каком-либо менеджере разработчики создают CoroutineScope:
class MyRepository(...) {
private val scope = CoroutineScope()
fun doWork(...) {
scope.launch { /* длительная работа */ }
}
}
Но есть вариант хуже:
class MyRepository(...) {
fun doWork(...) {
CoroutineScope(...).launch { /* длительная работа */ }
}
}
CoroutineScope
следует добавить Job (или SupervisorJob), а также CoroutineDispatcher
, который будет использоваться по умолчанию.Создать дочерний Scope можно следующим образом:
fun CoroutineScope.childScope(
context: CoroutineContext = EmptyCoroutineContext
): CoroutineScope {
return CoroutineScope(
coroutineContext
+ SupervisorJob(parent = coroutineContext[Job])
+ context
)
}
GlobalScope
. Что можете посоветовать вы авторам подобного кода, помимо почитать документацию и курсы? Пишите в комментариях.
#kotlin #coroutines
Please open Telegram to view this post
VIEW IN TELEGRAM
Вышел Coil 3.1.0 - популярный загрузчик картинок с поддержкой KMP
👉 Улучшили производительность AsyncImage: скорость работы стала лучше на 25-40%, а потребление памяти - на 35-48%
👉 FakeImage теперь deprecated
👉 Появился ColorImage - полезен для возвращения фейковых значений в тестах и для Compose превью
👉 coil-compose-core больше не зависит от
🛠 Множество других исправлений и улучшений API
#kmp #android #compose
👉 Улучшили производительность AsyncImage: скорость работы стала лучше на 25-40%, а потребление памяти - на 35-48%
👉 FakeImage теперь deprecated
👉 Появился ColorImage - полезен для возвращения фейковых значений в тестах и для Compose превью
👉 coil-compose-core больше не зависит от
Dispatchers.Main.immedate
, что позволило исправить баги в работе Paparazzi и Roborazzi🛠 Множество других исправлений и улучшений API
#kmp #android #compose
Используете runBlocking в продакшен коде приложений (не тесты)?
Anonymous Poll
32%
Да
57%
Нет
3%
Не знаю
7%
Не участвую в опросе