A bit deeper – Telegram
A bit deeper
204 subscribers
23 photos
2 videos
28 links
Админ: @ilyagulya
Английская версия: @abitdeeper_en
Download Telegram
Слава JetBrains и фиче Local history!
Я случайно удалил папку с проектом который сегодня писал весь день.
Попытался восстановить через всякие тулзы для восстановления файлов - безуспешно.
В итоге попытал удачу:
1. Создал пустую папку проекта заново.
2. Открыл её в IDEA и открыл Local History.
3. Успешно нашёл изменение в котором удаляется весь проект и ревертнул его 🥳
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
UPD: рано радовался, половина файлов пустые 🙂
Видимо это знак - буду разрабатывать игру с нуля на стримах :D
😢9👍2
Недавно приехал мой микрофон из Питера, но оказалось что где-то потерялось крепление к штативу.
Я потратил две недели в попытках найти замену, и сегодня попытки увенчались успехом.
Так что в скором времени буду стримить как я разрабатываю свою игру на Flutter в прямом эфире 🙂
🔥12
Audio
🔥4
Немного про платформу Intellij

Сегодня у меня на работе была небольшая задача - нужно было исправить названия строковых ресурсов в нашем проекте - избавиться от точек.
Было: profile.expand
Стало: profile_expand
Зачем это было нужно: стандартная инспекция Find Usages в Android Studio не умеет понимать что использование R.string.profile_expand в коде это на самом деле использование ресурса profile.expand. Она работает только с названиями ресурсов у которых есть только андерскоры: profile_expand.
Соответственно, задача стояла в том чтобы перелопатить полторы тысячи ресурсов, делать это руками конечно же никакого желания и времени нету.
Также нужно не забывать что нужно не только переименовать ресурсы, но и их использование в xml по всему проекту.
На ум пришла давняя идея - сделать плагин для Intellij который позволит компилировать произвольный код для выполнения каких-то единичных операций прямо в IDE.
И тут я с удивлением обнаружил что такой инструмент давно существует в IDE!
Называется он IDE Scripting Console и получить к нему доступ можно через Cmd + Shift + A и поиск по строке IDE Scripting Console. Можете увидеть пример на скриншоте в первом комментарии к этому посту.

Внутри этого скрипта можно пользоваться всеми апи платформы Intellij которые обычно доступны при разработке плагинов для IDE. Также из скрипта можно получить значение последнего выполненного выражения, его будет видно в логе запуска скрипта.

Таким образом, задача упростилась донельзя:
1. Берём текущий открытый проект:
val project = ProjectManager.getInstance().openProjects.first()

2. Ищем все XML файлы в проекте (по пути отфильтровываем сгенерированные):
val baseDir = VfsUtil.findFile(Paths.get(project.basePath), true)!!  
val psiManager = PsiManager.getInstance(project)
val xmlFiles =
VfsUtil
.collectChildrenRecursively(baseDir)
.asSequence()
.filter { it.extension == "xml" }
.filterNot { it.path.contains("build") }
.mapNotNull { psiManager.findFile(it) as? XmlFile }

3. Переименовываем строковые ресурсы:
xmlFiles  
.filter { it.virtualFile.path.contains("/res/values/") }
.mapNotNull { xmlFile -> xmlFile.rootTag?.findSubTags("string")?.asSequence() }
.flatten()
.mapNotNull { stringTag -> stringTag.getAttribute("name") }
.filter { nameAttribute -> nameAttribute.value?.contains('.') == true }
.forEach {
val oldName = it.value!!
val newName = oldName.replace('.', '_')
WriteCommandAction.runWriteCommandAction(project) {
it.setValue(newName)
}
}

4. Ищем все XML атрибуты в проекте в которых есть значение начинающееся с @string и в котором присутствуют точки:
fun XmlFile.getAllAttributesRecursively() =  
generateSequence(
seed = listOf(element = rootTag!!),
nextFunction = {
val subTags = it.flatMap { it.subTags.toList() }
subTags.ifEmpty { null }
},
)
.flatMap { it.asSequence() }
.flatMap { it.attributes.asSequence() }


val allXmlAttributes = xmlFiles.flatMap { xmlFile ->
xmlFile
.getAllAttributesRecursively()
.filter { it.value!!.startsWith("@string/") }
.filter { it.value!!.contains('.') }
}

5. Заменяем точки в этих атрибутах на underscore:
allXmlAttributes.forEach {  
WriteCommandAction.runWriteCommandAction(project) {
it.setValue(
it.value!!.replace('.', '_')
)
}
}

Вот таким нехитрым способом я смог безопасно выполнить нетривиальный рефакторинг в проекте.
Пользуйтесь!
🔥20👍5👏3
Привет, друзья! 👋

Как вы возможно помните, почти 4 месяца назад мне пришла в голову идея создать IT-сообщество в Алматы.
Думал, буду делиться с вами новостями по ходу дела, но что-то не сложилось 😅
Так что сейчас просто расскажу, как всё идёт на текущий момент.

Я пообщался с Алексеем Гладковым (@mobiledevnews), и договорился что открою локальное сообщество Mobile Broadcast в Алматы. Утрясли все вопросы и я приступил к делу.

Для начала я познакомился с программным директором местной площадки, в которой можно бесплатно проводить мероприятия (бывшая Точка Кипения в Алматы - Qaynar Bulaq). Это был очень интересный опыт, дама невероятно заряженная, всё пыталась зазвать меня в кучу других активностей помимо сообщества. 😃
Мы с ней договорились добавить в расписание регулярные встречи моего сообщества по субботам.

Следующим шагом было создание Алматинского чатика, и тут понеслось! 🚀
Как только объявили о создании, сразу пришло 60 человек. Я прорекламировал чатик в местных IT-сообществах, и сейчас у нас уже 113 участников, здорово же!

Закономерно, пока что основную часть сообщества составляют Android разработчики. 😁
Сначала думал, буду проводить каждую неделю, но оказалось не так просто. 😅
Сейчас встречаемся раз в 2 недели, в самый раз.
В прошлую субботу была уже десятая, юбилейная!

В общем, опыт получился очень позитивный! 😊
Благодаря сообществу я познакомился с интересными людьми, теперь мы общаемся не только на встречах, ходим в кафешки, лазим в горы, играем в настолки.
А сами мероприятия проводить - совсем не сложно, даже в удовольствие!

Главное - это сильно помогло в эмиграции. Теперь я понимаю что самый лучший вариант как не остаться замкнутым в своём пузыре - взять всё в свои руки и начать искать людей с которыми будешь проводить досуг. Организовывать всё самому, потому что за тебя это никто не сделает.

Далее были мысли сделать какое-то подобие митапа, как только соберусь с силами - займусь этим.
Как говорится, Stay tuned!
22🔥5👍4👏1
Всем привет!
Давно ничего не писал, куча дел.
Наткнулся на прекрасный новый канал на ютубе где разработчик из Испании пишет видосы про разного рода low-level разработку.
Очень рекомендую ознакомиться, достаточно простой и при этом увлекательный видос о том как он писал свою собственную базу данных с нуля для того чтобы разобраться как оно работает под капотом.
Разбирает из каких частей состоит БД с архитектурной точки зрения, как данные хранятся на диске, как происходят запросы в базу данных, какие алгоритмы и структуры данных применяются.
https://youtu.be/5Pc18ge9ohI
🔥11👍76
Публичные выступления

Недавно выступал на митапе Bereke Bank с докладом о том как я коммитил в Kotlin.
Это мой первый опыт публичного выступления, поэтому конечно же были все сопутствующие проблемы:
- Потные ладошки и достаточно нервное состояние последние недели перед докладом
- Сбивался в самых неожиданных местах

По пути примерно понял план по которому мне комфортно готовить выступление:
1. Записываю тезисы того о чём я делаю доклад. В этот раз я сначала начал писать прям полноценно речь, вышло очень много текста которым я по факту практически не воспользовался. Так что тезисов достаточно.
2. Сразу же начинаю делать презентацию. Делаю упор на то чтобы презентация была достаточно подробная и чтобы она вела мой разговор. У меня нет шпаргалок или Speaker Notes в презентации. Я использую тот же материал который видят слушатели для того чтобы продолжать разговор.
3. Делаю 5-6 прогонов рассказа доклада по презентации. В процессе примерно понимаю как идёт рассказ, какие слайды не на своём месте, каких слайдов не хватает, какие лишние и так далее.

Я изначально не хотел заучивать речь, потому что ни разу в своей жизни не видел ситуации в которой это звучит хорошо и натурально. И, судя по всему, это было очень правильным решением, потому что в процессе репетиций я всё же выработал какое-то понимание как выкручиваться из каких-то ситуаций к которым я не готовился. 😄

В целом, я скорее доволен результатом. Публика была прекрасная, всё прошло сильно лучше чем у меня в голове. 😄

Уже подался со следующим докладом на несколько конференций, спешно готовлю его к началу августа, чтоб попасть в программу конференции. 😄

Видео можно посмотреть тут: https://youtu.be/BmA0etcopeQ?t=2099
🔥221
Я всё ещё тут

Давно ничего не писал, много чего произошло за это время 😄
Пришлось искать новую работу, и очень удачно получилось попасть на позицию релиз-инженера в inDrive.
Я наконец-то больше не Android разработчик. Очень давно хотел уйти из мобилок, и кажется это начало происходить.
Теперь я могу гордо называть себя Developer Productivity Engineer 😎
В новой роли я занимаюсь автоматизацией релизных процессов, рулю мобильным CI/CD и в скором времени буду заниматься билд инфраструктурой.
Испытательный срок подходит к концу, так что я потихоньку буду возвращаться в былое русло, у меня накопилось много всего о чём можно написать.
На затравку:
➡️ Как я за 2 часа написал антиспам бота при помощи AI и он теперь успешно обслуживает 4 крупных чата. А также как я собираюсь его монетизировать
➡️ Делаем консольные утилиты из JVM приложений при помощи GraalVM
➡️ Как я участвовал в CTF внутри inDrive и какие были задачи
➡️ Как я вкатился в совершенно новую для меня область при помощи claude.ai меньше чем за месяц и теперь AI инструменты являются для меня очень важной частью рабочего процесса
➡️ Планы по развитию сообщества разработчиков из Алматы во что-то большее, возможно онлайновое и международное

И ещё много всего, как по мне, довольно интересного. 🙂
Не теряйте!
🔥235👍2
🔍 Кейс-репорт: Когда Groovy решил поиграть в прятки с переменными

Поймал сегодня забавный баг в gradle-скриптах на Groovy. Спешу поделиться, чтобы вы тоже посмеялись (или поплакали) 😅

Суть в чем: объявляем переменную enableInstabug в build.gradle, используем её в разных местах. Смотрим код:

// Объявляем переменную
boolean enableInstabug = Boolean.valueOf(project.properties["enableInstabug"])

// В android блоке всё работает нормально
android {
defaultConfig {
manifestPlaceholders.readExtStoragePermMaxSdkVersion = enableInstabug ? "32" : "28"
}
}

// А в методе - сюрприз! 🎉
def applyInstabugIfNeeded() {
if (enableInstabug) { // Читает "false" как строку из gradle.properties
apply plugin: 'instabug-apm'
// ...
}
}


В чем прикол? Оказывается, в Groovy методы не захватывают переменные из внешнего скопа, в отличие от лямбд.

А почему никто не заметил? Потому что:
1. В скоупе метода переменная отсутствует - внутри Gradle неизвестные переменные "магически" резолвятся из gradle.properties если там есть свойство с таким же названием как переменная.
2. Метод читает свойство заново из gradle.properties - получает строку "false"
3. В условии if эта строка превращается в boolean по правилам Groovy - любая непустая строка считается true (привет JavaScript 😭)
4. Profit! 🎉 Код "работает", но совсем не так, как мы думали

Решения два:
1️⃣ Передавать переменную в метод как параметр:
def applyInstabugIfNeeded(boolean shouldEnableInstabug) { ... }


2️⃣ Использовать closure вместо метода:
def applyInstabugIfNeeded = {
if (enableInstabug) { ... }
}


Мораль: Gradle-скрипты на Groovy - как коробка шоколадных конфет: никогда не знаешь, что внутри. И да, они тоже могут испортить тебе день 🍫
🔥9😁6😱2💯1