Захотел поиграть в Minecraft, но все закончилось исходниками.
Недавно я решил создать свой собственный Minecraft сервер и в качестве ядра выбрал Spigot, это одна из популярных и хорошо оптимизированных реализаций. Но перед тем как приступить к созданию сервера мне захотелось глянуть исходники Spigot, я по быстрому пробежался по основным репозиториям и заметил одну крутую штуку - сам по себе репозиторий Spigot это всего лишь набор Git патчей для другого репозитория CraftBukket.
Проект CraftBukket является полностью готовым ядром, которое можно брать и использовать для создания серверов, поэтому он обязан меняться с выходом новых версий Minecraft'а, а Spigot как я уже упоминал это всего лишь набор Git патчей для CraftBukket'а. В итоге не было никакого смысла создавать два отдельных репозитория и дважды поднимать версию Minecraft'а, намного проще написать небольшой скриптик, который будет скачивать исходники CraftBukket и применять патчи Spigot, для этого как раз используется BuildTools.
Только сейчас дошло что описал принцип fork'ов в действии: берем проект X, че-то меняем и получаем проект Y, если в проекте X поменяется что-то глобальное делаем какой-нибудь git rebase.
P.S. Если вы знаете крутые хостинги для Minecraft серверов, напишите пожалуйста в комментах, буду очень признателен)
Всем хорошей недели!
Недавно я решил создать свой собственный Minecraft сервер и в качестве ядра выбрал Spigot, это одна из популярных и хорошо оптимизированных реализаций. Но перед тем как приступить к созданию сервера мне захотелось глянуть исходники Spigot, я по быстрому пробежался по основным репозиториям и заметил одну крутую штуку - сам по себе репозиторий Spigot это всего лишь набор Git патчей для другого репозитория CraftBukket.
Проект CraftBukket является полностью готовым ядром, которое можно брать и использовать для создания серверов, поэтому он обязан меняться с выходом новых версий Minecraft'а, а Spigot как я уже упоминал это всего лишь набор Git патчей для CraftBukket'а. В итоге не было никакого смысла создавать два отдельных репозитория и дважды поднимать версию Minecraft'а, намного проще написать небольшой скриптик, который будет скачивать исходники CraftBukket и применять патчи Spigot, для этого как раз используется BuildTools.
Только сейчас дошло что описал принцип fork'ов в действии: берем проект X, че-то меняем и получаем проект Y, если в проекте X поменяется что-то глобальное делаем какой-нибудь git rebase.
P.S. Если вы знаете крутые хостинги для Minecraft серверов, напишите пожалуйста в комментах, буду очень признателен)
Всем хорошей недели!
👍6🔥4🤯1🤣1
Всем привет, короче я запилил ванильный сервак на самой свежей версии Minecraft 1.21.4, кто хочет поиграть вступайте в чатик, там будут все подробности:
https://xn--r1a.website/+qXpvPEzDV8QzOTcy
Также в этом месяце я планирую написать на Хабре простенькую статью о том как устроен CoroutineContext и CoroutineScope под капотом, так что хейтеры Minecraft прошу не отписываться)
Всем хорошего дня!
https://xn--r1a.website/+qXpvPEzDV8QzOTcy
Также в этом месяце я планирую написать на Хабре простенькую статью о том как устроен CoroutineContext и CoroutineScope под капотом, так что хейтеры Minecraft прошу не отписываться)
Всем хорошего дня!
❤15😁5👌3
Получение реализации интерфейса по имени класса в Kotlin.
В Kotlin есть возможность написать имя класса вместо реализации интерфейса если интерфейс реализован companion object'ом этого класса:
Если декомпилировать байт-код, сгенерированный для этого примера можно увидить что вместо имени класса подставляется companion оbject реализация:
Если честно я недавно узнал об этом когда в очередной раз залез в исходники корутин, если вы не знали в CoroutineContext'е используется аналогичный механизм для изящного извлечения элементов:
Классы Job и CoroutineDispatcher содержат реализации ключей в своих companion object'ах, а CoroutineContext переопределяет оператор получения значения по ключу (квадратные скобки), поэтому такой код будет работать.
Пишите в комментах ваше мнение и всем хорошего кода!
В Kotlin есть возможность написать имя класса вместо реализации интерфейса если интерфейс реализован companion object'ом этого класса:
interface Key
class Value {
companion object KeyImpl : Key {
...
}
}
// мы можем обратиться к реализации ключа по имени класса
val key1: Key = Value
// полная форма
val key2: Key = Value.KeyImpl
Если декомпилировать байт-код, сгенерированный для этого примера можно увидить что вместо имени класса подставляется companion оbject реализация:
public interface Key {}
public final class Value {
// companion object это статическое поле
// другими словами синглетон класса
public static final KeyImpl KeyImpl = new KeyImpl();
public static final class KeyImpl implements Key {}
}
// в обеих ситуациях используется полная форма
Key key1 = (Key) Value.KeyImpl;
Key key2 = (Key) Value.KeyImpl;Если честно я недавно узнал об этом когда в очередной раз залез в исходники корутин, если вы не знали в CoroutineContext'е используется аналогичный механизм для изящного извлечения элементов:
// вместо использования Job.Key используется имя класса
val job = coroutineContext[Job]
// аналогично с CoroutineDispatcher
val dispatcher = coroutineContext[CoroutineDispatcher]
Классы Job и CoroutineDispatcher содержат реализации ключей в своих companion object'ах, а CoroutineContext переопределяет оператор получения значения по ключу (квадратные скобки), поэтому такой код будет работать.
Пишите в комментах ваше мнение и всем хорошего кода!
🤯20👍12
Всем привет, объявляю конкурс по лучшему дизайну!
Общее описание задания: разработать дизайн для мобильного приложения под Android / iOS, можно сделать как общий дизайн, так и два разных, основная идея приложения - это поиск напарников для игр. В двух словах: пользователь заходит в приложение через Google или другие возможные способы авторизации, заполняет свою анкету: имя, аватарка, возраст, краткое описание, указывает контакты Discord / Telegram / VK, выбирает игры в которые играет, у каждой игры будет свой уникальный набор свойств, это нужно для более специфичной фильтрации, далее пользователь попадает на главную страницу, где отображаются анкеты в вертикальном списке, вверху экрана можно настроить фильтры.
Экраны которые надо сверстать:
1) Экран создания анкеты, указываются основные данные, такие как имя, аватарка, описание, возраст, контакты Telegram / Discord / VK и самая важная часть список игр в которые играет пользователь, для каждой игры можно настроить свой уникальный набор свойств, например для рейтинговых игр это уровень рейтинга и тд, также необязательно заполнение анкеты делать как один экран, можно разделить на несколько и идти по шагам.
2) Основной экран с поиском: вверху набор фильтров который можно раскрыть, тута можете придумывать любые переходы, в качестве фильтров пока можно взять название игры, возраст игрока и накинуть что-нибудь специфичное когда выбираете определенную игру, например если это рейтинговая игра то для такой игры можно добавить уровень рейтинга, игры выбираете на свое усмотрение, какие хотите, также будет сортировка, например по дате последнего захода пользователя.
3) Остальная часть основного экрана: это список анкет, в каждой из которых указывается - сколько времени назад был пользователь в сети, имя, аватарка, краткое описание, возраст, список игр, в списке игр каждый элемент можно раскрыть чтобы посмотреть более конкретные вещи касательно этой игры, опять же какие-то поля можно выкинуть если вы считаете что так будет лучше или наоборот что-то добавить.
Цвета можно использовать любые, редакторы тоже, самое главное это интересные и уникальные дизайны с прикольными фишками и идеями, так что прямо следовать моему описанию экранов не надо, делайте в соответствии со своими творческими взглядами.
Приз: 33 333 рублей.
Прием работ до 22 февраля.
P.S. Если вы хотите проявить себя в качестве собеседующего вступайте в @tech_talk_community, интересная инициатива, возможно в будущем трансформируется в полноценную площадку для проведения собесов.
Присылайте работы в личные сообщения и пишите если что-то непонятно по конкурсу, желаю вам победить)
Общее описание задания: разработать дизайн для мобильного приложения под Android / iOS, можно сделать как общий дизайн, так и два разных, основная идея приложения - это поиск напарников для игр. В двух словах: пользователь заходит в приложение через Google или другие возможные способы авторизации, заполняет свою анкету: имя, аватарка, возраст, краткое описание, указывает контакты Discord / Telegram / VK, выбирает игры в которые играет, у каждой игры будет свой уникальный набор свойств, это нужно для более специфичной фильтрации, далее пользователь попадает на главную страницу, где отображаются анкеты в вертикальном списке, вверху экрана можно настроить фильтры.
Экраны которые надо сверстать:
1) Экран создания анкеты, указываются основные данные, такие как имя, аватарка, описание, возраст, контакты Telegram / Discord / VK и самая важная часть список игр в которые играет пользователь, для каждой игры можно настроить свой уникальный набор свойств, например для рейтинговых игр это уровень рейтинга и тд, также необязательно заполнение анкеты делать как один экран, можно разделить на несколько и идти по шагам.
2) Основной экран с поиском: вверху набор фильтров который можно раскрыть, тута можете придумывать любые переходы, в качестве фильтров пока можно взять название игры, возраст игрока и накинуть что-нибудь специфичное когда выбираете определенную игру, например если это рейтинговая игра то для такой игры можно добавить уровень рейтинга, игры выбираете на свое усмотрение, какие хотите, также будет сортировка, например по дате последнего захода пользователя.
3) Остальная часть основного экрана: это список анкет, в каждой из которых указывается - сколько времени назад был пользователь в сети, имя, аватарка, краткое описание, возраст, список игр, в списке игр каждый элемент можно раскрыть чтобы посмотреть более конкретные вещи касательно этой игры, опять же какие-то поля можно выкинуть если вы считаете что так будет лучше или наоборот что-то добавить.
Цвета можно использовать любые, редакторы тоже, самое главное это интересные и уникальные дизайны с прикольными фишками и идеями, так что прямо следовать моему описанию экранов не надо, делайте в соответствии со своими творческими взглядами.
Приз: 33 333 рублей.
Прием работ до 22 февраля.
P.S. Если вы хотите проявить себя в качестве собеседующего вступайте в @tech_talk_community, интересная инициатива, возможно в будущем трансформируется в полноценную площадку для проведения собесов.
Присылайте работы в личные сообщения и пишите если что-то непонятно по конкурсу, желаю вам победить)
🔥12😁8🫡2
Всем привет, написал еще одну интересную статейку по корутинам - CoroutineContext / CoroutineScope под капотом, после прочтения которой вы сможете ответить на следующие вопросы:
1) Почему корутины нельзя запустить без CoroutineScope?
2) Что такое CoroutineScope и какие есть реализации?
3) Что такое CoroutineContext? На основе какого паттерна построен?
4) Что является ключом в CoroutineContext? Как суммируются его элементы?
5) Как организуется Structured Concurrency?
Также хотел поделиться, недавно замержили мой первый pull request в репозиторий корутин!
https://github.com/Kotlin/kotlinx.coroutines/pull/4341
Пишите в комментах ваше мнение и всем хорошего кода!
1) Почему корутины нельзя запустить без CoroutineScope?
2) Что такое CoroutineScope и какие есть реализации?
3) Что такое CoroutineContext? На основе какого паттерна построен?
4) Что является ключом в CoroutineContext? Как суммируются его элементы?
5) Как организуется Structured Concurrency?
Также хотел поделиться, недавно замержили мой первый pull request в репозиторий корутин!
https://github.com/Kotlin/kotlinx.coroutines/pull/4341
Пишите в комментах ваше мнение и всем хорошего кода!
Habr
Kotlin Coroutines под капотом: CoroutineContext и CoroutineScope
Structured Concurrency это одна из главных фишек Kotlin Coroutines, позволяющая оперировать иерархиями корутин через единый интерфейс, благодаря такой организации можно легко отменить сразу все...
🔥34👍7❤3🥴2😴1
Скоко статей вы написали в этом году?
Anonymous Poll
74%
вообще не пишу статьи
20%
0
2%
1
1%
2
2%
3+
0%
другой ответ (напишите в комментах)
Media is too big
VIEW IN TELEGRAM
Всем привет, решил попробовать записать небольшой пробный видос, в дальнейшем собираюсь сделать плейлист где буду разбирать всякие штуки, неуверен пока насколько хватит энтузиазма, но буду рад если глянете видос и напишите свою оценку в комментах)
P.S. Планирую установить хромакей чтобы убрать задний фон, ну и буду учиться чаще смотреть в камеру)
Всем хорошего кода!
P.S. Планирую установить хромакей чтобы убрать задний фон, ну и буду учиться чаще смотреть в камеру)
Всем хорошего кода!
🔥49😢4❤🔥3
Пару слов про CoroutineScheduler.
Я был уверен что CoroutineDispatcher в JVM реализации использует пул потоков ThreadPoolExecutor из Java, но как всегда бывает, вроде во всем разобрался, а нет нифига, найдется что-то новое и в моем случае это CoroutineScheduler.
1) Все потоки хранятся в одном массиве, как для
2) Потоки создаются лениво, когда это надо, тут важный момент - количество потоков для
3) Все потоки в
4) При выполнении задачи сначала проверяется на каком потоке она выполняется, если на одном из потоков
5) Могут быть ситуации когда
Всем хорошего кода!
Я был уверен что CoroutineDispatcher в JVM реализации использует пул потоков ThreadPoolExecutor из Java, но как всегда бывает, вроде во всем разобрался, а нет нифига, найдется что-то новое и в моем случае это CoroutineScheduler.
CoroutineScheduler - это своего рода аналогия ThreadPoolExecutor, которая хранит и переиспользует потоки, а также распределяет между ними задачи, на этой штуке как раз и построены Dispatchers.Default и Dispatchers.IO, рассмотрим ключевые моменты:1) Все потоки хранятся в одном массиве, как для
Dispatchers.IO, так и для Dispatchers.Default, поэтому в случае бездействия одного из диспатчеров потоки другого могут быть спокойно переиспользованы.2) Потоки создаются лениво, когда это надо, тут важный момент - количество потоков для
Dispatchers.Default будет ограничено количеством ядер процессора, а для Dispatchers.IO потоки будут создаваться пока не достигнут 64 штук (если в системном свойстве не указано другое значение). 3) Все потоки в
CoroutineScheduler представлены абстракцией Worker, у каждого Worker'а есть своя очередь задач, в качестве задачи выступает выполнение корутины, помимо очереди для отдельного Worker'а есть еще две глобальные очереди - одна для CPU задач, другая для IO задач.4) При выполнении задачи сначала проверяется на каком потоке она выполняется, если на одном из потоков
CoroutineScheduler'а то сразу ставится в очередь актуального Worker'а, в противном случае добавляется в глобальную очередь, откуда Worker'ы в дальнейшем ее заберут.5) Могут быть ситуации когда
Worker содержит пустую очередь задач, то есть полностью свободен, в таком случае он попытается украсть задачу либо из глобальных очередей CPU и IO, либо у других Worker'ов, это оптимизация для более эффективного распределения задач.Всем хорошего кода!
👍47🤔3❤1
Цикл while везде решает.
У вас когда нибудь была задача написать функцию, которая делает какой-то запрос и в случае ошибки повторно перезапрашивает данные? Мне недавно попался такой кейс, вроде бы фигня, но решение оказалось настолько простым и изящным, что даже захотелось поделиться им:
Вообще люблю цикл while, сейчас в современной Kotlin разработке его все сложнее встретить, так как чаще используются более высокоуровневые методы такие как forEach например.
P.S. Если вас интересуют более общие темы, связанные с миром IT такие как информационная безопасность или IoT рекомендую канал одного крутого чувака Max Knyazev is typing…
Всем хорошего кода!
У вас когда нибудь была задача написать функцию, которая делает какой-то запрос и в случае ошибки повторно перезапрашивает данные? Мне недавно попался такой кейс, вроде бы фигня, но решение оказалось настолько простым и изящным, что даже захотелось поделиться им:
// опустил возвращаемый тип для простоты
fun fetchPosts(retryCount: Int = 0) {
var currentRetryAttempt = 0
while (currentRetryAttempt <= retryCount) {
try {
// сделать запрос и вернуть че то
} catch (_: Exception) {
// попробовать еще, если осталась попытка
currentRetryAttempt++
}
}
return emptyList()
}
Вообще люблю цикл while, сейчас в современной Kotlin разработке его все сложнее встретить, так как чаще используются более высокоуровневые методы такие как forEach например.
P.S. Если вас интересуют более общие темы, связанные с миром IT такие как информационная безопасность или IoT рекомендую канал одного крутого чувака Max Knyazev is typing…
Всем хорошего кода!
🤣17👍16❤2
Как потоку эффективно дождаться следующих задач?
В одном из предыдущих постов я разбирал как работает корутиновский пул потоков CoroutineScheduler, так вот после того как корутина выполнилась, поток должен дождаться следующей задачи, самый простой способ сделать это - проверять новые задачи в бесконечном цикле:
Новые задачи добавляются в очередь и если она непустая выполняются, проблема такого подхода в том что процессор будет выполнять тысячи или даже сотни тысяч бесполезных проверок каждую секунду.
Чтобы поток не занимался бесполезной работой, а просто дожидался следующих задач была придумана удобная обертка над Unsafe API - LockSupport класс:
Суть идеи в том что метод
P.S. Есть еще полезный метод
Всем хорошего кода!
В одном из предыдущих постов я разбирал как работает корутиновский пул потоков CoroutineScheduler, так вот после того как корутина выполнилась, поток должен дождаться следующей задачи, самый простой способ сделать это - проверять новые задачи в бесконечном цикле:
while(true) {
if (taskQueue.isEmpty()) {
continue
}
val task = taskQueue.poll()
task.run()
}Новые задачи добавляются в очередь и если она непустая выполняются, проблема такого подхода в том что процессор будет выполнять тысячи или даже сотни тысяч бесполезных проверок каждую секунду.
Чтобы поток не занимался бесполезной работой, а просто дожидался следующих задач была придумана удобная обертка над Unsafe API - LockSupport класс:
while (true) {
if (taskQueue.isEmpty()) {
LockSupport.park()
}
val task = taskQueue.poll()
task.run()
}
fun addTask(task: Task) {
taskQueue.push(task)
LockSupport.unpark(this)
}Суть идеи в том что метод
LockSupport.park() переводит текущий поток в состояние бездействия, а метод LockSupport.unpark() наоборот возвращает его из этого состояния, поэтому при отсутствии задач процессор не будет занят лишними инструкциями, если хотите конкретно разобраться во всей этой теме рекомендую глянуть исходники класса CoroutineScheduler,P.S. Есть еще полезный метод
LockSupport.parkNanos() если хотите задать время жизни потока при отсутствии задач, кстати в CoroutineScheduler есть такая логика - гляньте поле idleWorkerKeepAliveNs.Всем хорошего кода!
👍31😁3🔥2
Как устроены LockSupport.park() и LockSupport.unpark() под капотом.
В предыдущем посте я показал механизм приостановки потоков на основе такой штуки как LockSupport, но не рассказал как на самом деле устроен этот механизм.
Покопавшись в исходниках JVM я выяснил что методы
Оба вызова принимают на вход мьютекс, который захватывается когда поток был возобновлен и освобождается когда поток был приостановлен, это дополнительная синхронизация для кода который должен быть атомарно выполнен до приостановки или после возобновления потока.
По итогу происходит вызов планировщика процессов Linux, который либо исключает поток из планирования (pthread_cond_wait), это значит что CPU не будет его выполнять, либо обратно добавляет в очередь планирования (pthread_cond_signal), где поток будет получать определенное количество времени от CPU для своего исполнения.
P.S. В прошлом году я опубликовал статью на Github'е о том как приостанавливается жизненный цикл в Android, так вот, там используется другой системный вызов, он называется epoll, главное его отличие в том что он реагирует на операции ввода-вывода, а не на сигналы.
Всем хорошего кода!
В предыдущем посте я показал механизм приостановки потоков на основе такой штуки как LockSupport, но не рассказал как на самом деле устроен этот механизм.
Покопавшись в исходниках JVM я выяснил что методы
LockSupport.park() и LockSupport.unpark() под капотом обращаются к следующим системным вызовам Linux:void Parker::park(...) {
// специальный системный вызов который приостанавливает поток и ждет пока не будет вызван сигнал
pthread_cond_wait(...)
}
void Parker::unpark() {
// сигнал который снова возобновляет выполнение потока
pthread_cond_signal(...)
}Оба вызова принимают на вход мьютекс, который захватывается когда поток был возобновлен и освобождается когда поток был приостановлен, это дополнительная синхронизация для кода который должен быть атомарно выполнен до приостановки или после возобновления потока.
По итогу происходит вызов планировщика процессов Linux, который либо исключает поток из планирования (pthread_cond_wait), это значит что CPU не будет его выполнять, либо обратно добавляет в очередь планирования (pthread_cond_signal), где поток будет получать определенное количество времени от CPU для своего исполнения.
P.S. В прошлом году я опубликовал статью на Github'е о том как приостанавливается жизненный цикл в Android, так вот, там используется другой системный вызов, он называется epoll, главное его отличие в том что он реагирует на операции ввода-вывода, а не на сигналы.
Всем хорошего кода!
🔥19🤣3
Игровые движки.
В начале 2023 года вышла легендарная игра под названием Atomic Heart, я был просто впечатлен насколько разработчики проработали детали и какие крутые механики они запилили, тогда мне очень сильно захотелось создать свою игру, но к сожалению по каким то неведомым причинам это желание угасло.
С того времени прошло около 2-х лет и совсем недавно мои руки наконец то дотянулись до разработки игр, теперь я хочу поделиться своими личными впечатлениями о движках с которыми столкнулся, моя цель разработать 2D игру с сюжетом и поэтому мне очень важен критерий максимальной поддержки этого типа игр, поехали короче!
1) Unreal Engine 5 - это прям мощнейший комбайн, в котором только чего нет, нюанс только в том что данный движок по большей части ориентирован на 3D игры, а поддержка 2D осуществляется с помощью дополнительных плагинов, да и слишком он мощный для 2D игр, так что мимо.
2) Godot - интересный Open Source проект, можно покопаться в исходниках с целью понять как работают игровые движки и как пишутся свои языки программирования, да у этого движка есть свой язык программирования GDScript, как движок он к сожалению замороченный, мне он показался костыльным короче, ну и как будто не хватает мощи для крутых эффектов и всякого такого(
3) Cocos2D - вроде норм, но я не смог создать скрипт на языке C++, хотя очень сильно хотел написать игру именно на этом языке, в итоге сформировалось ощущение что данный движок поддерживает только Typescript из коробки, да и в целом не понравился концепт этого движка, тоже мимо к сожалению(
4) Unity - только не C# подумал я, но если честно я поменял свое мнение когда начал работать с этим движком, он сочетает в себе мощность и легковесность одновременно и не выглядит костыльным, многие штуки решаются очень просто, а также у него достаточно большое сообщество по сравнению с другими аналогами для 2D игр, короче придется мне полюбить язык от Microsoft(
P.S. Если умеете рисовать персонажей и анимации или есть интересные задумки и идеи пишите в личные сообщения
Всем хорошего кода!
В начале 2023 года вышла легендарная игра под названием Atomic Heart, я был просто впечатлен насколько разработчики проработали детали и какие крутые механики они запилили, тогда мне очень сильно захотелось создать свою игру, но к сожалению по каким то неведомым причинам это желание угасло.
С того времени прошло около 2-х лет и совсем недавно мои руки наконец то дотянулись до разработки игр, теперь я хочу поделиться своими личными впечатлениями о движках с которыми столкнулся, моя цель разработать 2D игру с сюжетом и поэтому мне очень важен критерий максимальной поддержки этого типа игр, поехали короче!
1) Unreal Engine 5 - это прям мощнейший комбайн, в котором только чего нет, нюанс только в том что данный движок по большей части ориентирован на 3D игры, а поддержка 2D осуществляется с помощью дополнительных плагинов, да и слишком он мощный для 2D игр, так что мимо.
2) Godot - интересный Open Source проект, можно покопаться в исходниках с целью понять как работают игровые движки и как пишутся свои языки программирования, да у этого движка есть свой язык программирования GDScript, как движок он к сожалению замороченный, мне он показался костыльным короче, ну и как будто не хватает мощи для крутых эффектов и всякого такого(
3) Cocos2D - вроде норм, но я не смог создать скрипт на языке C++, хотя очень сильно хотел написать игру именно на этом языке, в итоге сформировалось ощущение что данный движок поддерживает только Typescript из коробки, да и в целом не понравился концепт этого движка, тоже мимо к сожалению(
4) Unity - только не C# подумал я, но если честно я поменял свое мнение когда начал работать с этим движком, он сочетает в себе мощность и легковесность одновременно и не выглядит костыльным, многие штуки решаются очень просто, а также у него достаточно большое сообщество по сравнению с другими аналогами для 2D игр, короче придется мне полюбить язык от Microsoft(
P.S. Если умеете рисовать персонажей и анимации или есть интересные задумки и идеи пишите в личные сообщения
Всем хорошего кода!
👍12🔥6❤2
Рутинные тех-таски.
Всем привет, этот пост по большей части для тех кто работает в компаниях где есть такая штука как тех долг, если не шарите эт короче обязанность выполнять определенное количество задач связанных непосредственно с самой разработкой, например что то намутить на CI, отрефачить библиотеку и тд, если прям простыми словами: не токо писать новые фичи, а еще и рефачить их.
Так вот, бывают очень рутинные и бесячие задачи, которые затягиваются на несколько недель и даже месяцев, такие задачи убивают все желание в чем либо разбираться, короче получается фигня полная. Что хочу сказать намного разумнее забить и попытаться съехать с такой задачи и похер какой вы перфекционист по жизни и конечно похер на чувство вины, какой смысл от страданий которые убивают весь кайф от работы? Никакого! Вообще все это наверно относится не только к тех-долгу, но и в целом к любой работе, но думаю вы поняли посыл...
P.S. Если вы не такой нелюбитель разговорного английского как я, а наоборот хотите или даже пытаетесь освоить этот язык, есть очень крутой канал для этого @authenticpigeon, залетайте!
Всем хорошего кода!
Всем привет, этот пост по большей части для тех кто работает в компаниях где есть такая штука как тех долг, если не шарите эт короче обязанность выполнять определенное количество задач связанных непосредственно с самой разработкой, например что то намутить на CI, отрефачить библиотеку и тд, если прям простыми словами: не токо писать новые фичи, а еще и рефачить их.
Так вот, бывают очень рутинные и бесячие задачи, которые затягиваются на несколько недель и даже месяцев, такие задачи убивают все желание в чем либо разбираться, короче получается фигня полная. Что хочу сказать намного разумнее забить и попытаться съехать с такой задачи и похер какой вы перфекционист по жизни и конечно похер на чувство вины, какой смысл от страданий которые убивают весь кайф от работы? Никакого! Вообще все это наверно относится не только к тех-долгу, но и в целом к любой работе, но думаю вы поняли посыл...
P.S. Если вы не такой нелюбитель разговорного английского как я, а наоборот хотите или даже пытаетесь освоить этот язык, есть очень крутой канал для этого @authenticpigeon, залетайте!
Всем хорошего кода!
🥴11😁10👍2🤣1
Вижу негативную реакцию на последний пост, хотел бы уточнить один момент, в особенности это касается тех кто обвиняет меня за написанные в спешке посты ради рекламы, так вот, вы ахерели? Я не делаю рекламу в своем канале, только рекомендую полезные ресурсы, если желаете убедиться спросите у чуваков, чьи каналы были в моих последних рекомендациях: @mainsdorff, @MaxiEnergy, @vla_dos, @Earldev, если действительно настанет момент когда мой канал станет рекламной ерундистикой, прицепите электроды к моей башке и врубите ток на полную мощность!
Что касается качества постов и их полезности, согласен оно упало, к сожалению у меня сейчас нет такого яркого энтузиазма и идей как раньше, наверно весь годовой потенциал был потрачен на статью по отмене корутин, которую я писал на Новогодних каникулах, возможно мне стоит выбрать стратегию: писать что то раз в год, но делать материал супер изящным и крутым...
Также хочу раскрыть посыл предыдущего поста, бывают вещи которые могут отбить любое желание что то делать, в том числе это могут быть долгие и рутинные тех-таски. Согласен что умение работать с такими задачами это весьма полезный навык, но я к сожалению так не могу, если я перестаю видеть результат максимум в течении недели, мое желание что-либо делать, в том числе и развиваться пропадает, вот такой я непрофессионал, это правда)
Всем тех-долга и побольше!
Что касается качества постов и их полезности, согласен оно упало, к сожалению у меня сейчас нет такого яркого энтузиазма и идей как раньше, наверно весь годовой потенциал был потрачен на статью по отмене корутин, которую я писал на Новогодних каникулах, возможно мне стоит выбрать стратегию: писать что то раз в год, но делать материал супер изящным и крутым...
Также хочу раскрыть посыл предыдущего поста, бывают вещи которые могут отбить любое желание что то делать, в том числе это могут быть долгие и рутинные тех-таски. Согласен что умение работать с такими задачами это весьма полезный навык, но я к сожалению так не могу, если я перестаю видеть результат максимум в течении недели, мое желание что-либо делать, в том числе и развиваться пропадает, вот такой я непрофессионал, это правда)
Всем тех-долга и побольше!
Habr
Kotlin Coroutines под капотом: отмена корутин
В прошлой статье я разобрал как работают корутины под капотом, рекомендую ознакомиться прежде чем закапываться дальше. В этой статье мы разберем такую сущность как Job и как на самом деле под капотом...
🔥18🤣10🤝3❤2🙏2
Button из Material Compose под капотом.
В Jetpack Compose есть пакет с Material Design компонентами - androidx.compose.material, там лежат такие штуки как Text, Button, TextField и тд. Так вот, мне стало любопытно как устроены кнопки под капотом, так как часто приходится просто вешать Modifier.clickable на всякие Box, Column и Row, в итоге узнал следующие штуки:
1) Button построен на androidx.compose.material.Surface компоненте
2) В цепочке модификаторов Button есть Modifier.semantics для UI тестов и Accessibility.
3) Переопределены такие вещи как LocalContentAlpha и LocalTextStyle.
Компонент Surface - это простейший Box с примерно такой цепочкой модификаторов:
Получается что Surface делает следующие штуки под капотом:
1) Добавляет кликабельность или другой тип взаимодействия (selectable, toggleable)
2) Обрезает ripple эффект под указанный Shape
3) Добавляет фон с указанным Shape
4) Рисует тень для объемности
В результате имеем компонент, реализующий базовую идею Material Design - объемность, теперь вы сами можете писать такие компоненты.
P.S. Как настроение? Можете поставить циферку от 1 до 10, если лень писать буквы.
Всем хорошего кода!
В Jetpack Compose есть пакет с Material Design компонентами - androidx.compose.material, там лежат такие штуки как Text, Button, TextField и тд. Так вот, мне стало любопытно как устроены кнопки под капотом, так как часто приходится просто вешать Modifier.clickable на всякие Box, Column и Row, в итоге узнал следующие штуки:
1) Button построен на androidx.compose.material.Surface компоненте
2) В цепочке модификаторов Button есть Modifier.semantics для UI тестов и Accessibility.
3) Переопределены такие вещи как LocalContentAlpha и LocalTextStyle.
Компонент Surface - это простейший Box с примерно такой цепочкой модификаторов:
Box(
modifier = Modifier
// надо для Accessibility, чтобы минимальная область клика была 48x48 dp
.minimumInteractiveComponentSize()
// можете делать тень в своих компонентах, это публичный модификатор
.shadow(elevation, shape)
.background(backgroundColor, shape)
// надо для обрезки ripple эффекта при клике, сам использовал такой прием ни раз
.clip(shape)
// вместо clickable могут быть selectable или toggleable
.clickable(...)
) {
content()
}
Получается что Surface делает следующие штуки под капотом:
1) Добавляет кликабельность или другой тип взаимодействия (selectable, toggleable)
2) Обрезает ripple эффект под указанный Shape
3) Добавляет фон с указанным Shape
4) Рисует тень для объемности
В результате имеем компонент, реализующий базовую идею Material Design - объемность, теперь вы сами можете писать такие компоненты.
P.S. Как настроение? Можете поставить циферку от 1 до 10, если лень писать буквы.
Всем хорошего кода!
❤31👍16
AI-ассистенты == забейте на чтение документации.
Всем привет, недавно мне нужно было по быстрому запилить бэкенд на Go, начал как всегда с того что полез в документацию, прочитал нужную тему, вроде все ок, а нет нихера, надо еще посмотреть синтаксис языка, как создаются массивы и всякое такое, глянул, опять ничего не работает, пошел гуглить в интернет, как обычно это могло затянуться на пару часов или даже дней, но...
...Благо я не такой древний и мне знакомы такие термины как ChatGPT, ну и всякая подобная херня в стиле AI ассистентов, поэтому пошел искусственно-интеллектничать, забил один запрос в Google AI ассистент, другой в Cursor AI и получил +- рабочий код в обеих случаях, безусловно одним запросом не обошлось, но буквально за пару минут я увидел целостную картину: как в Go парсится json, как выглядит синтаксис массивов, как с ними работать и тд, короче взглянул на задачу комплексно.
По итогу хочу сказать, что я недооценивал AI, это действительно крутой вспомогательный инструмент, который может сделать заготовку, а после уже можно придать ей красивый и изящный вид, ну или можно обойтись без эстетики и тупо пойти кушать шоколад, AI все (или всех) порешает...
P.S. Как у вас началось лето?
Всем хорошего кода!
Всем привет, недавно мне нужно было по быстрому запилить бэкенд на Go, начал как всегда с того что полез в документацию, прочитал нужную тему, вроде все ок, а нет нихера, надо еще посмотреть синтаксис языка, как создаются массивы и всякое такое, глянул, опять ничего не работает, пошел гуглить в интернет, как обычно это могло затянуться на пару часов или даже дней, но...
...Благо я не такой древний и мне знакомы такие термины как ChatGPT, ну и всякая подобная херня в стиле AI ассистентов, поэтому пошел искусственно-интеллектничать, забил один запрос в Google AI ассистент, другой в Cursor AI и получил +- рабочий код в обеих случаях, безусловно одним запросом не обошлось, но буквально за пару минут я увидел целостную картину: как в Go парсится json, как выглядит синтаксис массивов, как с ними работать и тд, короче взглянул на задачу комплексно.
По итогу хочу сказать, что я недооценивал AI, это действительно крутой вспомогательный инструмент, который может сделать заготовку, а после уже можно придать ей красивый и изящный вид, ну или можно обойтись без эстетики и тупо пойти кушать шоколад, AI все (или всех) порешает...
P.S. Как у вас началось лето?
Всем хорошего кода!
👍29🤔4❤1
Загрузочный кейс с delay().
Недавно в одном моем Pet проекте возникла ситуация при которой анимация прогресса отрабатывала моментально, а мне хотелось сделать красивый переход из состояния загрузки в успешное, без мерцаний и тд.
Простым решением было добавить вызов
Но оно не сильно мне зашло так как мы создаем дополнительное ожидание для пользователя.
Чтобы минимизировать ожидание и одновременно сделать плавный переход я решил выполнить эти функции параллельно:
В таком случае
Пишите в комментах что думаете и всем хорошей недели!
Недавно в одном моем Pet проекте возникла ситуация при которой анимация прогресса отрабатывала моментально, а мне хотелось сделать красивый переход из состояния загрузки в успешное, без мерцаний и тд.
Простым решением было добавить вызов
delay() в код ViewModel:viewModelScope.launch {
delay(200)
val result = useCase.execute()
...
}Но оно не сильно мне зашло так как мы создаем дополнительное ожидание для пользователя.
Чтобы минимизировать ожидание и одновременно сделать плавный переход я решил выполнить эти функции параллельно:
viewModelScope.launch {
// под капотом выполнится на android.os.Handler
val delayDeferred = async {
delay(200)
}
// под капотом выполнится на пуле потоков CoroutineScheduler
val useCaseDeferred = async {
useCase.execute()
}
// в итоге выполнение будет параллельным так как разные потоки
val result = listOf(
useCaseDeferred,
delayDeferred
)
.awaitAll()
.first() as Result
...
}В таком случае
useCase не будет ждать пока выполниться delay(), а начнет выполняться сразу, если даже он завершиться раньше 200 миллисекунд, результат не вернется до тех пор пока не закончит выполняться функция delay(), таким образом мы получим плавный переход из анимации загрузки в успешное состояние с минимальной искусственной задержкой.Пишите в комментах что думаете и всем хорошей недели!
👍42🤔11❤3😁1
Зачем data object если есть просто class?
Бывают ситуации когда вам нужно создать класс без полей с возможностью сравнивать его объекты через
Для навигации Decompose важно чтобы объект был помечен @Serializable и реализовывал
Так что прагматичнее использовать обычный класс и ручками прописать реализацию
По итогу любой объект класса Splash будет эквивалентен при сравнении, а это абсолютно такое же поведение как у data object'ов.
P.S. Как у вас началось лето: насыщенно (1), скучно (2) или продуктивно (3) ? Напишите в комментах циферку.
Всем хорошего кода!
Бывают ситуации когда вам нужно создать класс без полей с возможностью сравнивать его объекты через
equals() метод, например это может пригодиться в навигации Decompose:@Serializable
sealed class Navigation {
// одно из самых ленивых решений просто сделать data object
@Serializable
data object Splash : Navigation()
}
Для навигации Decompose важно чтобы объект был помечен @Serializable и реализовывал
equals() метод, в данном случае data object делает все это, вообще похожий кейс есть в MVI при объявлении событий (Event) и действий (Action), поэтому в вашем приложении может быть очень много data object'ов, а это нехорошо по той причине что вы плодите статические объекты класса, другими словами как только такой объект будет создан он останется в памяти даже если вы покинете место его использования.Так что прагматичнее использовать обычный класс и ручками прописать реализацию
equals() и hashCode() методов:@Serializable
sealed class Navigation {
@Serializable
class Splash : Navigation() {
override fun equals(obj: Any?)
= obj is Splash
override fun hashCode() = 0
}
}
По итогу любой объект класса Splash будет эквивалентен при сравнении, а это абсолютно такое же поведение как у data object'ов.
P.S. Как у вас началось лето: насыщенно (1), скучно (2) или продуктивно (3) ? Напишите в комментах циферку.
Всем хорошего кода!
👍16🤔10🔥3❤1
Первая машина.
Буквально год назад я не интересовался машинами от слова совсем, но в один из прекрасных октябрьских дней 2024 года я скачал игру Forza Horizon 4 и тут понеслось: сначала я просто гулял по городу и разглядывал марки и модели машин, затем начал интересоваться технической стороной, какие бывают двигатели, приводы, топливные системы и всякое такое, ну и все это вылилось в то что я получил права и купил свою первую машину, как раз ей я хотел бы посвятить этот пост.
Те кто шарит уже наверно по фоткам поняли что это легендарное произведение искусства ГАЗ 21 Волга, да она самая и я безмерно восхищен тем что взял ее, более того я пообещал самому себе что ни за какую цену не продам ее, будь это хоть 10 кусков зелени или даже 100, не имеет значения.
Ну а теперь парочку фактов о ней:
1) Такая же большая как и современные внедорожники как по габаритам так и по массе, только в отличии от них у нее нет усилителя руля, парковочных систем, камер и даже боковых зеркал, ну и слабоватые тормоза, поэтому приходится тормозить двигателем и прям владеть габаритами!
2) Механическая коробка передач на руле, это весьма нестандартный способ управления, в добавок данная коробка не имеет синхронизаторов для 1-ой и задней передач, другими словами если вы включили вторую передачу, то на первую будет очень сложно попасть на ходу, в большинстве случаев приходиться полностью останавливаться.
Для сравнения: сейчас большинство новых машин делают на автоматической коробке, а тут не просто механика, а еще нестандартная.
3) Карбюраторный двигатель, чтобы запустить его надо открыть воздушную заслонку (специальная кнопочка в салоне) и накачать топливо в карбюратор, а при прокручивании ключа зажигания еще подгазовывать если двигатель холодный.
Для сравнения: сейчас практически все автомобили ездят на инжекторах, это системы основанные на компьютере, поэтому ничего качать и нажимать не надо, токо повернуть ключик зажигания.
4) Ламповое радио (радио на лампах), это те самые радиоприемники из СССР, которые звучали так что слышно было на других континентах, к сожалению 65 лет назад радиочастоты были другие, поэтому очень сложно что то поймать(
5) Очень мягкая подвеска, форточки в дверях, вместо сидений кожаный диван (впереди могут сидеть 3 человека), который раскладывается в большую кровать, ну и не нужно пристегиваться так как данная машина не предусматривает ремни.
6) Ну и напоследок шикарный стиль по типу американских автомобилей 50-х.
Пишите как вам моя красотка?
Буквально год назад я не интересовался машинами от слова совсем, но в один из прекрасных октябрьских дней 2024 года я скачал игру Forza Horizon 4 и тут понеслось: сначала я просто гулял по городу и разглядывал марки и модели машин, затем начал интересоваться технической стороной, какие бывают двигатели, приводы, топливные системы и всякое такое, ну и все это вылилось в то что я получил права и купил свою первую машину, как раз ей я хотел бы посвятить этот пост.
Те кто шарит уже наверно по фоткам поняли что это легендарное произведение искусства ГАЗ 21 Волга, да она самая и я безмерно восхищен тем что взял ее, более того я пообещал самому себе что ни за какую цену не продам ее, будь это хоть 10 кусков зелени или даже 100, не имеет значения.
Ну а теперь парочку фактов о ней:
1) Такая же большая как и современные внедорожники как по габаритам так и по массе, только в отличии от них у нее нет усилителя руля, парковочных систем, камер и даже боковых зеркал, ну и слабоватые тормоза, поэтому приходится тормозить двигателем и прям владеть габаритами!
2) Механическая коробка передач на руле, это весьма нестандартный способ управления, в добавок данная коробка не имеет синхронизаторов для 1-ой и задней передач, другими словами если вы включили вторую передачу, то на первую будет очень сложно попасть на ходу, в большинстве случаев приходиться полностью останавливаться.
Для сравнения: сейчас большинство новых машин делают на автоматической коробке, а тут не просто механика, а еще нестандартная.
3) Карбюраторный двигатель, чтобы запустить его надо открыть воздушную заслонку (специальная кнопочка в салоне) и накачать топливо в карбюратор, а при прокручивании ключа зажигания еще подгазовывать если двигатель холодный.
Для сравнения: сейчас практически все автомобили ездят на инжекторах, это системы основанные на компьютере, поэтому ничего качать и нажимать не надо, токо повернуть ключик зажигания.
4) Ламповое радио (радио на лампах), это те самые радиоприемники из СССР, которые звучали так что слышно было на других континентах, к сожалению 65 лет назад радиочастоты были другие, поэтому очень сложно что то поймать(
5) Очень мягкая подвеска, форточки в дверях, вместо сидений кожаный диван (впереди могут сидеть 3 человека), который раскладывается в большую кровать, ну и не нужно пристегиваться так как данная машина не предусматривает ремни.
6) Ну и напоследок шикарный стиль по типу американских автомобилей 50-х.
Пишите как вам моя красотка?
❤35🔥20🤣14🤯12🥰2