Convention Plugins
Итак, будет больше одного фича модуля, а значит собираться они будут похожим образом. Нужно избежать бойлерплейта. И вот как сейчас выглядит
В отдельных модулях бывают дополнительные зависимости. Но всё же — несколько строк, вместо ~50 с
Бывают в виде kts скриптов или в виде kotlin/java файлов. Без них — копипаст в каждом модуле. Один раз забыл обновить
Получилась иерархия, как на скриншоте.
Все модули получают нужную конфигурацию за одну строку.
Вот немного полезных материалов по теме, от Т-Банка:
Статья раз, Статья два
Кстати, написание самих плагинов — хороший пример задачи для AI: есть образец в виде
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
Итак, будет больше одного фича модуля, а значит собираться они будут похожим образом. Нужно избежать бойлерплейта. И вот как сейчас выглядит
build.gradle.kts любого feature-модуля в проекте:
plugins {
alias(libs.plugins.jazari.feature)
}
android {
namespace = "money.jazari.feature.login"
}
В отдельных модулях бывают дополнительные зависимости. Но всё же — несколько строк, вместо ~50 с
compileSdk, версией Java, Compose BOM, всеми зависимостями Hilt, KSP, desugaring и прочим. Это convention plugins.Бывают в виде kts скриптов или в виде kotlin/java файлов. Без них — копипаст в каждом модуле. Один раз забыл обновить
compileSdk в одном месте — и привет. Получилась иерархия, как на скриншоте.
FeaturePlugin — это буквально:
class FeaturePlugin : BaseProjectPlugin() {
override fun apply(target: Project) {
AndroidLibraryPlugin().apply(target)
HiltPlugin().apply(target)
ComposePlugin().apply(target)
}
}
Все модули получают нужную конфигурацию за одну строку.
Вот немного полезных материалов по теме, от Т-Банка:
Статья раз, Статья два
Кстати, написание самих плагинов — хороший пример задачи для AI: есть образец в виде
build.gradle.kts, нужно отрефакторить, чтобы собиралось также. Особенно помогает, когда есть gradle апи, перенос которых в плагин не самый очевидный. Тут AI справился без вопросов и без помощи извне→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
👍4
Нужно ли выносить внешние зависимости в отдельные модули?
Многие архитектурные паттерны рекомендуют это делать. На практике — зависит.
Если отгораживаться модулями от всех зависимостей, появляются дополнительные абстракции, маппинги и модели. Архитура усложняется, поэтому обычно для этого нужна веская причина.
Например, Android SDK — тоже внешняя зависимость для нашего кода. Но мы же не изолируем всё подряд без необходимости.
У нас таких случаев нашлось два: пуши и саппорт. Оба — внешние SDK, которые могут меняться или подключаться по-разному в разных приложениях.
С саппортом получился показательный кейс. Параллельно с модуляризацией мы переезжали с Intercom на HelpCrunch. Каждый SDK был вынесен в отдельный модуль, поэтому оба работали одновременно, а переключение было возможно прямо на проде — без страха что что-то сломается.
Когда миграция завершилась, удаление Intercom выглядело как удаление одной строки из
Все остальные внешние зависимости оставили как есть. Изолировать всё подряд ради соблюдения паттернов кажется избыточным.
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
Многие архитектурные паттерны рекомендуют это делать. На практике — зависит.
Если отгораживаться модулями от всех зависимостей, появляются дополнительные абстракции, маппинги и модели. Архитура усложняется, поэтому обычно для этого нужна веская причина.
Например, Android SDK — тоже внешняя зависимость для нашего кода. Но мы же не изолируем всё подряд без необходимости.
У нас таких случаев нашлось два: пуши и саппорт. Оба — внешние SDK, которые могут меняться или подключаться по-разному в разных приложениях.
С саппортом получился показательный кейс. Параллельно с модуляризацией мы переезжали с Intercom на HelpCrunch. Каждый SDK был вынесен в отдельный модуль, поэтому оба работали одновременно, а переключение было возможно прямо на проде — без страха что что-то сломается.
Когда миграция завершилась, удаление Intercom выглядело как удаление одной строки из
build.gradle.kts.Все остальные внешние зависимости оставили как есть. Изолировать всё подряд ради соблюдения паттернов кажется избыточным.
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
👍2
Модуляризация закончена.
Вынесли в отдельные модули ui kit, data, models, domain и другие общие части. В итоге получилось: 15 core-модулей, 6 feature-модулей и domain. Часть фич осталась в монолите — их можно выделить позже, если появится необходимость
Модуляризация заняла 100+ коммитов. Отдельная часть работы — исправление нарушений слоёв, которые накопились в монолите
Какие части помог сделать AI?
🤖 AI для выбора архитектуры
AI может проанализировать проект, учесть предпочтения по архитектуре, найти узкие места и предложить варианты. Если оставить его наедине с кодом — думаю, он даже успешно всё отрефакторит
Но есть важный нюанс: ответственность за архитектуру несём мы, а не AI
Поэтому мы сделали так:
• сами спроектировали будущую архитектуру, понимая её плюсы и минусы
• обсудили решение с AI, попросили найти риски и наложить его на проект
• доработали архитектуру после обсуждения
Цена ошибки тут слишком высокая, чтобы делегировать решение целиком
🤖 AI для рефакторинга
А вот здесь AI оказался очень полезен: составить план, подсветить проблемные зависимости, двигать файлы, помогать с переносом кода. Это реально экономит много времени
👉 Главный вывод: полноценная модуляризация одного приложения — часто преждевременная оптимизация
Но структуру будущих модулей стоит закладывать сразу, даже внутри монолита:
app/feature/login/
app/feature/registration/
app/domain/
Тогда при росте проекта границы уже понятны: переносишь папку — получаешь модуль. А нарушения этих границ потом стоят десятков лишних коммитов (но AI помогает)
Модуляризация выполнена. Общие feature-модули готовы. Новое приложение почти готово?
Ага, конечно 🙂
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
Вынесли в отдельные модули ui kit, data, models, domain и другие общие части. В итоге получилось: 15 core-модулей, 6 feature-модулей и domain. Часть фич осталась в монолите — их можно выделить позже, если появится необходимость
Модуляризация заняла 100+ коммитов. Отдельная часть работы — исправление нарушений слоёв, которые накопились в монолите
Какие части помог сделать AI?
AI может проанализировать проект, учесть предпочтения по архитектуре, найти узкие места и предложить варианты. Если оставить его наедине с кодом — думаю, он даже успешно всё отрефакторит
Но есть важный нюанс: ответственность за архитектуру несём мы, а не AI
Поэтому мы сделали так:
• сами спроектировали будущую архитектуру, понимая её плюсы и минусы
• обсудили решение с AI, попросили найти риски и наложить его на проект
• доработали архитектуру после обсуждения
Цена ошибки тут слишком высокая, чтобы делегировать решение целиком
А вот здесь AI оказался очень полезен: составить план, подсветить проблемные зависимости, двигать файлы, помогать с переносом кода. Это реально экономит много времени
👉 Главный вывод: полноценная модуляризация одного приложения — часто преждевременная оптимизация
Но структуру будущих модулей стоит закладывать сразу, даже внутри монолита:
app/feature/login/
app/feature/registration/
app/domain/
Тогда при росте проекта границы уже понятны: переносишь папку — получаешь модуль. А нарушения этих границ потом стоят десятков лишних коммитов (но AI помогает)
Модуляризация выполнена. Общие feature-модули готовы. Новое приложение почти готово?
Ага, конечно 🙂
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🧹 Небольшая история из-под капота compose-bom.com
Поймал любопытный кейс. Google выпустил Compose BOM 2026.05.01, но потом тихо убрал его из официального BOM-маппинга. Причина — рассогласование версий: runtime в этом BOM — 1.10.6, тогда как всё остальное уже 1.11.x.
Хитрость в том, что артефакты в Maven неизменны — поэтому 2026.05.01 так и лежит там навсегда, хотя Google уже «отозвал» его и заменил исправленным 2026.06.00 (там runtime подняли до 1.11.2, чтобы всё совпадало).
Получался релиз-призрак: в Maven есть, в официальном маппинге — нет 🤷
Теперь коллектор такие отозванные версии аккуратно пропускает, чтобы в changelog попадало только то, что Google реально поддерживает.
=====
👉 Напоминаю, что это бесплатный инструмент: показывает дифф между двумя версиями Compose BOM и собирает release notes библиотек в одном месте. Адаптирован для AI агентов с помощью llms.txt
Пользуйтесь, делитесь с коллегами — буду рад, если пригодится 🙌
🔗 compose-bom.com
#JetpackCompose #AndroidDev #Kotlin #ComposeBOM #Android
Поймал любопытный кейс. Google выпустил Compose BOM 2026.05.01, но потом тихо убрал его из официального BOM-маппинга. Причина — рассогласование версий: runtime в этом BOM — 1.10.6, тогда как всё остальное уже 1.11.x.
Хитрость в том, что артефакты в Maven неизменны — поэтому 2026.05.01 так и лежит там навсегда, хотя Google уже «отозвал» его и заменил исправленным 2026.06.00 (там runtime подняли до 1.11.2, чтобы всё совпадало).
Получался релиз-призрак: в Maven есть, в официальном маппинге — нет 🤷
Теперь коллектор такие отозванные версии аккуратно пропускает, чтобы в changelog попадало только то, что Google реально поддерживает.
=====
👉 Напоминаю, что это бесплатный инструмент: показывает дифф между двумя версиями Compose BOM и собирает release notes библиотек в одном месте. Адаптирован для AI агентов с помощью llms.txt
Пользуйтесь, делитесь с коллегами — буду рад, если пригодится 🙌
🔗 compose-bom.com
#JetpackCompose #AndroidDev #Kotlin #ComposeBOM #Android
👍4
This media is not supported in your browser
VIEW IN TELEGRAM
Модули готовы. Следующая цель — запустить второе приложение.
Создали новый app-модуль. Нужно добавлять зависимости. DI-граф для нового приложения не возникает из воздуха — кто-то должен всё забиндить. И тут мы поступили максимально по-варварски: взяли
В итоге — 301 строка. Примерно 60% одинаковые.
И
Трейдоф здесь честный.
С одной стороны — дублирование. Добавил что-то в одном приложении — не забудь обновить второе.
С другой — абстракции не бесплатны. Разница между приложениями реальная, и любая «общая база» быстро начинает обрастать исключениями.
Технический долг? И да, и нет.
Зависит от того, сколько проблем это реально создаст. Иногда copy-paste — лучший архитектурный выбор. Главное — понимать цену переделки, если она понадобится.
Осталось склеить фичи между собой.
Один модуль = одна фича. Значит, фичи не знают друг про друга. Навигация живёт в `app`-модуле.
Каждая фича предоставляет extension на
Одна и та же фича, но возможно разное поведение.
В `app`-модуле приходится явно прописывать все переходы. Плюс это или минус — решайте сами 😉
И вот оно — приложение запустилось.
На видео самая первая версия: без анимаций, с кривой тёмной темой, временными заглушками вместо онбординга и главного экрана. Почти ничего нет из того, что запланировано — но сколько радости, потому что ОНО РАБОТАЕТ!!
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
Создали новый app-модуль. Нужно добавлять зависимости. DI-граф для нового приложения не возникает из воздуха — кто-то должен всё забиндить. И тут мы поступили максимально по-варварски: взяли
AppModule.kt из Jazari Money на 400 строк, скопировали в Jazari Global и начали удалять лишнее.В итоге — 301 строка. Примерно 60% одинаковые.
И
AppModule — только самый наглядный пример. Копировалось всё, что живёт на уровне `app`-модуля: конфигурация, инициализаторы, навигация. Сценарий везде одинаковый: копируешь, удаляешь лишнее, добавляешь чего не хватилоТрейдоф здесь честный.
С одной стороны — дублирование. Добавил что-то в одном приложении — не забудь обновить второе.
С другой — абстракции не бесплатны. Разница между приложениями реальная, и любая «общая база» быстро начинает обрастать исключениями.
Технический долг? И да, и нет.
Зависит от того, сколько проблем это реально создаст. Иногда copy-paste — лучший архитектурный выбор. Главное — понимать цену переделки, если она понадобится.
Осталось склеить фичи между собой.
Один модуль = одна фича. Значит, фичи не знают друг про друга. Навигация живёт в `app`-модуле.
Каждая фича предоставляет extension на
NavGraphBuilder:
fun NavGraphBuilder.createLoginScreen(
navController: NavController,
onTermsClick: () -> Unit = {},
onPrivacyPolicyClick: () -> Unit = {},
)
feature:login не знает, что делать после клика на T&C. Это просто callback, который реализует `app`-модуль. Jazari Money передаёт свою навигацию. Jazari One — свою.Одна и та же фича, но возможно разное поведение.
В `app`-модуле приходится явно прописывать все переходы. Плюс это или минус — решайте сами 😉
И вот оно — приложение запустилось.
На видео самая первая версия: без анимаций, с кривой тёмной темой, временными заглушками вместо онбординга и главного экрана. Почти ничего нет из того, что запланировано — но сколько радости, потому что ОНО РАБОТАЕТ!!
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
❤4
Android & Coffee с Васей
🧹 Небольшая история из-под капота compose-bom.com Поймал любопытный кейс. Google выпустил Compose BOM 2026.05.01, но потом тихо убрал его из официального BOM-маппинга. Причина — рассогласование версий: runtime в этом BOM — 1.10.6, тогда как всё остальное…
Google удалил Compose BOM 2026.06.00 и переопубликовал 2026.05.01, с поправленной runtime зависимостью. Теперь всё чинно.
Если мигрируете — изменения можно посмотреть на https://compose-bom.com/ (или натравите агента — сайт llm-friendly)
Если мигрируете — изменения можно посмотреть на https://compose-bom.com/ (или натравите агента — сайт llm-friendly)
Blueprint Compose Preview
Библиотека от Gus Ward, позволяющая показать Blueprint экрана на Compose.
Достаточно обернуть экран в composable
Есть режим
И удобно, когда дизайнер говорит "вроде тут не 32 пикселя, а 33"
⭐️ Github: https://github.com/GusWard/Blueprint-Compose-Preview
#android #androiddev #jetpackcompose #compose #mobiledev #kotlin #ui #uidesign #androidlibrary
Библиотека от Gus Ward, позволяющая показать Blueprint экрана на Compose.
Достаточно обернуть экран в composable
BlueprintPreview и добавить идентификаторы к некоторым элементам. Удобно для проверки вёрстки и поиска проблем с отступами без запуска приложения.Есть режим
showInternalItems, когда показываются все возможные элементы. Для превью экрана это чересчур (3й скрин), но может пригодиться для превью отдельных компонентов дизайн системыИ удобно, когда дизайнер говорит "вроде тут не 32 пикселя, а 33"
#android #androiddev #jetpackcompose #compose #mobiledev #kotlin #ui #uidesign #androidlibrary
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Один логин?
Приложение собрано. Открываем первую же фичу — логин. Первый экран: ввод номера телефона.
В Jazari Money страна одна — UK. Флаг захардкожен, поменять нельзя. В Jazari One пользователь может сменить код страны прямо в интерфейсе, аудитория глобальная.
Уже здесь — дилемма. Экран ввода телефона в двух приложениях отличается, но не полностью. Различия постарались убрать по максимуму, но от них никуда не деться. Варианта два:
— два отдельных экрана, каждый со своим поведением
— один экран с if'ами
Первый вариант чище концептуально: никаких if-ов, каждое приложение получает свой экран. Но слишком большая часть — вёрстка, валидация телефона, отправка OTP — была бы продублирована.
Вот тут дублировать уже не хочется, потому что расходы на поддержку кажутся большей проблемой, чем при поддержке DI модулей.
Итак, решение — один модуль, одна вьюмодель, одна вьюха, но есть отличия в вёрстке и логике. Как это выразить?
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
Приложение собрано. Открываем первую же фичу — логин. Первый экран: ввод номера телефона.
В Jazari Money страна одна — UK. Флаг захардкожен, поменять нельзя. В Jazari One пользователь может сменить код страны прямо в интерфейсе, аудитория глобальная.
Уже здесь — дилемма. Экран ввода телефона в двух приложениях отличается, но не полностью. Различия постарались убрать по максимуму, но от них никуда не деться. Варианта два:
— два отдельных экрана, каждый со своим поведением
— один экран с if'ами
Первый вариант чище концептуально: никаких if-ов, каждое приложение получает свой экран. Но слишком большая часть — вёрстка, валидация телефона, отправка OTP — была бы продублирована.
Вот тут дублировать уже не хочется, потому что расходы на поддержку кажутся большей проблемой, чем при поддержке DI модулей.
Итак, решение — один модуль, одна вьюмодель, одна вьюха, но есть отличия в вёрстке и логике. Как это выразить?
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
👍4🔥1
Один логин, разное поведение
В Jazari Money при логине нельзя поменять код страны, в Jazari One — можно. Как это сделать?
Вот несколько способов, как сделать фичи настраиваемыми под разные бренды
1️⃣ — общий интерфейс
Но когда отличия накапливаются, на каждое заводить по флагу или другому полю — представьте сколько их будет.
При этом в
Получается примерно так:
Минус: фича знает про то, что бренды есть.
Плюс: фича требует минимум настройки и уже может работать с другим брендом.
2️⃣ Поле
3️⃣ Еще один вариант — конфигурация конкретной фичи вместо общей конфигурации приложения:
Каждая фича — свой конфиг.
Самая чистая абстракция. Но и кода вокруг неё больше.
Пока у нас не white-label и мы не поставляем SDK, большого смысла в таком решении для фич я не вижу. Но это хорошо работает для инфраструктурных модулей с понятной настройкой — например, параметров пушей или Network слоя.
---
В проекте в итоге используются все три подхода — в разных местах и по разным причинам.
Кажется, это и есть ответ: универсального решения нет.
С поведением разобрались. Что с UI?
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
В Jazari Money при логине нельзя поменять код страны, в Jazari One — можно. Как это сделать?
Вот несколько способов, как сделать фичи настраиваемыми под разные бренды
1️⃣ — общий интерфейс
AppVariant. Каждое приложение биндит свою реализацию через DI, а feature-модуль просто спрашивает у него что нужно.
interface AppVariant {
val brand: Brand
val supportEmail: String
// ...
}
brand — универсальное поле, которое позволяет писать if'ы. Более правильным решением было бы завести отдельные поля:
interface AppVariant {
val canChangeCountry: Boolean
val defaultCountry: Country?
val supportEmail: String
// ...
}
Но когда отличия накапливаются, на каждое заводить по флагу или другому полю — представьте сколько их будет.
При этом в
Jazari Money никогда не предвидится выбора другой страны, а дефолтная страна всегда будет UK. То есть абстрагировать здесь сомнительно, хоть и можно. Проверка бренда, пусть и не такая чистая, зато проще.Получается примерно так:
phoneState = when (appVariant.brand) {
// всегда UK
Brand.Money -> PhoneCountry(flag = flag_uk, code = "+44", iso = "GB", canChangeCountry = false)
// выбранная страна состояния
Brand.Global -> loginStorage.savedCountry()
}
Минус: фича знает про то, что бренды есть.
Плюс: фича требует минимум настройки и уже может работать с другим брендом.
2️⃣ Поле
supportEmail в AppVariant — другое дело. Оно используется в нескольких местах, присутствует в обоих приложениях и имеет разные значения. Здесь уже есть смысл сделать поле вместо if'ов по всем модулям.3️⃣ Еще один вариант — конфигурация конкретной фичи вместо общей конфигурации приложения:
data class EnterPhoneConfig(
val canChangeCountry: Boolean,
val defaultCountry: Country?,
)
Каждая фича — свой конфиг.
AppVariant не разрастается хаотично.Самая чистая абстракция. Но и кода вокруг неё больше.
Пока у нас не white-label и мы не поставляем SDK, большого смысла в таком решении для фич я не вижу. Но это хорошо работает для инфраструктурных модулей с понятной настройкой — например, параметров пушей или Network слоя.
---
В проекте в итоге используются все три подхода — в разных местах и по разным причинам.
Кажется, это и есть ответ: универсального решения нет.
С поведением разобрались. Что с UI?
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
🔥3
This media is not supported in your browser
VIEW IN TELEGRAM
🤯 Новый One UI от Samsung
За такое нужно увольнять без выходного пособия. И дизайнера, и разработчика.
У меня уже дёргается глаз от этой анимации.
Что думаете?
#android #ux #samsung #oneui
За такое нужно увольнять без выходного пособия. И дизайнера, и разработчика.
У меня уже дёргается глаз от этой анимации.
Что думаете?
#android #ux #samsung #oneui
💯2
This media is not supported in your browser
VIEW IN TELEGRAM
Прикольная пасхалка от Google Play консоли
Один логин, разный UI
В Jazari Money дизайн-системы как артефакта почти не существовало — она была в чертогах разума, но несколько компонентов всё же просочились в Figma.
Android жил на Material-токенах, iOS придумал свои. Тёмная тема была только в iOS приложении силами и энтузиазмом iOS команды. Не потому что не знали как нужно: качественная дизайн система — отдельная большая работа. Легко сделать плохо и заиметь еще бОльший долг.
Дизайнер приносит дизайн Jazari One. Конечно, с мыслью о переиспользовании — но сразу появились отличия: только тёмная тема, другие цвета с другой семантикой, новые токены типографики, кнопки нарисованы заново.
Три варианта: копировать экраны, добавлять if-ы или привести к одному виду.
Копировать — больно: отличия в деталях, а поддерживать придётся почти каждый экран. Поэтому стандартизировали токены, привели кнопки к единому виду и волевым решением перевели Jazari Money на новые токены. В большой компании такое не позволишь — в стартапе это задача на пару дней.
За счёт этого получилось достаточно абстрагировать дизайн-систему. Оставшиеся детали — лобзиком через if'ы с помощью
Так условный
Сейчас
🤖 Переезд на новые токены целиком выполнил AI — на вход получил только ссылку на Figma и указания: как мапить и что тема теперь будет своя, а не Material. Тюнинг компонентов if'ами был ручным, потому что мы сами продолжали их активно менять.
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
В Jazari Money дизайн-системы как артефакта почти не существовало — она была в чертогах разума, но несколько компонентов всё же просочились в Figma.
Android жил на Material-токенах, iOS придумал свои. Тёмная тема была только в iOS приложении силами и энтузиазмом iOS команды. Не потому что не знали как нужно: качественная дизайн система — отдельная большая работа. Легко сделать плохо и заиметь еще бОльший долг.
Дизайнер приносит дизайн Jazari One. Конечно, с мыслью о переиспользовании — но сразу появились отличия: только тёмная тема, другие цвета с другой семантикой, новые токены типографики, кнопки нарисованы заново.
Три варианта: копировать экраны, добавлять if-ы или привести к одному виду.
Копировать — больно: отличия в деталях, а поддерживать придётся почти каждый экран. Поэтому стандартизировали токены, привели кнопки к единому виду и волевым решением перевели Jazari Money на новые токены. В большой компании такое не позволишь — в стартапе это задача на пару дней.
За счёт этого получилось достаточно абстрагировать дизайн-систему. Оставшиеся детали — лобзиком через if'ы с помощью
Brand в CompositionLocal:
@Composable
fun JazariTheme(
brand: Brand,
...
) {
CompositionLocalProvider(
LocalBrand provides brand,
content = content,
)
}
Так условный
JazariButton может выбирать реализацию по бренду:
@Composable
private fun getContainerColor(type: ButtonType) = when (type) {
ButtonType.Primary -> when (LocalBrand.current) {
Brand.Money -> JazariTheme.colorScheme.accentGreen
Brand.Global -> Color.Transparent
}
// ...
}
Сейчас
LocalBrand.current встречается в коде 54 раза. Много, но все отличия между приложениями сразу видны. Но те же 54 места превратились бы в 54 настраиваемых параметра. Это уже не абстракция — это другой проект.🤖 Переезд на новые токены целиком выполнил AI — на вход получил только ссылку на Figma и указания: как мапить и что тема теперь будет своя, а не Material. Тюнинг компонентов if'ами был ручным, потому что мы сами продолжали их активно менять.
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
👍2
Claude может сам настроить мониторинг токенов
Claude Code и другие coding-ассистенты умеют отдавать телеметрию через OpenTelemetry — токены, latency, события агента.
Подключается к Grafana или любому OTEL совместимому коллектору. Есть бесплатный облачный вариант, можно поднять своё.
Пригождается когда упираешься в лимиты или хочешь понять, куда реально уходят токены.
Ну и просто прикольно видеть, что потратил 500 баксов на токены, а подписка стоит $100
https://code.claude.com/docs/en/agent-sdk/observability
#claude #claudecode #ai #devtools #observability
Claude Code и другие coding-ассистенты умеют отдавать телеметрию через OpenTelemetry — токены, latency, события агента.
Подключается к Grafana или любому OTEL совместимому коллектору. Есть бесплатный облачный вариант, можно поднять своё.
Пригождается когда упираешься в лимиты или хочешь понять, куда реально уходят токены.
Ну и просто прикольно видеть, что потратил 500 баксов на токены, а подписка стоит $100
https://code.claude.com/docs/en/agent-sdk/observability
#claude #claudecode #ai #devtools #observability
❤1
Про то, как AI не смог
Jazari One — приложение со стейблкоинами. Один из важных типов —
Нужно было расширить тип, чтобы он умел работать и с фиатом, и с токенами.
Вопрос был один: как определить, что перед нами — фиат или токен? AI решил проверять длину строки: USD — три символа, USDT — четыре. Звучит правдоподобно ровно до момента, когда вспоминаешь про BTC, SOL, ETH или стейблкоин DAI.
Следующая идея от AI — делегировать Java:
Тут сразу две проблемы:
• исключение — это слишком медленно. Выбросить исключения в разы или десятки раз медленнее возврата результата
• на Android есть нюанс: ICU добавляет некоторые трёхсимвольные криптовалюты — в частности, ETH и BTC — как «настоящие» валюты, просто с
🫴 Финальное решение — явно фильтровать по numericCode (на скрине), который соответствует ISO 4217:
Набор фиатных валют строится один раз, лениво. ETH и BTC учтены. Определение типа валюты — O(1)
Три попытки ушло у AI, чтобы написать одну функцию. Не забывайте проверять за AI
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
Jazari One — приложение со стейблкоинами. Один из важных типов —
Money, работает поверх java.util.Currency. Но старая реализация не подходит: вызов Currency.getInstance("USDT") просто бросил бы исключение.Нужно было расширить тип, чтобы он умел работать и с фиатом, и с токенами.
sealed interface MoneyCurrency {
val currencyCode: String
data class Fiat(val currency: Currency) : MoneyCurrency { ... }
data class Token(val symbol: String) : MoneyCurrency { ... }
}
Вопрос был один: как определить, что перед нами — фиат или токен? AI решил проверять длину строки: USD — три символа, USDT — четыре. Звучит правдоподобно ровно до момента, когда вспоминаешь про BTC, SOL, ETH или стейблкоин DAI.
Следующая идея от AI — делегировать Java:
fun fromCode(code: String): MoneyCurrency {
return try {
Fiat(Currency.getInstance(code))
} catch (e: IllegalArgumentException) {
Token(code)
}
}
Currency.getInstance() знает все ISO 4217 коды. Не знает — значит, токен. Выглядит элегантно.Тут сразу две проблемы:
• исключение — это слишком медленно. Выбросить исключения в разы или десятки раз медленнее возврата результата
• на Android есть нюанс: ICU добавляет некоторые трёхсимвольные криптовалюты — в частности, ETH и BTC — как «настоящие» валюты, просто с
numericCode == -1. Поэтому Currency.getInstance("ETH") не бросает исключение, и ETH молча стал бы фиатом.🫴 Финальное решение — явно фильтровать по numericCode (на скрине), который соответствует ISO 4217:
private val fiatCurrencies: Map<String, Currency> by lazy {
Currency.getAvailableCurrencies()
.filter { it.numericCode > 0 }
.associateBy { it.currencyCode }
}
fun fromCode(code: String): MoneyCurrency {
val currency = fiatCurrencies[code]
return if (currency != null) Fiat(currency) else Token(code)
}
Набор фиатных валют строится один раз, лениво. ETH и BTC учтены. Определение типа валюты — O(1)
Три попытки ушло у AI, чтобы написать одну функцию. Не забывайте проверять за AI
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
👍5
Media is too big
VIEW IN TELEGRAM
💳 Экран карт — возможно, один из самых сложных экранов в банковских приложениях с точки зрения UX
Когда говорим о картах, мы чаще всего представляем обычные карточки, которыми расплачиваемся в магазинах. Даже виртуальные карты повторяют эту ассоциацию: их нет в реальном мире, но их рисуют как настоящие карты.
Поэтому отображение карт в приложении часто пытаются сделать осязаемым:
• складывают их в виде кошелька, чтобы их можно было "доставать" жестами
• добавляют 3d модели, чтобы карта выглядела сочно (так сделано, например, в iOS приложении Jazari)
• добавляют всяческие анимации
С другой стороны, вокруг карт есть целая цифровая экосистема:
• транзакции
• управление картой: пин, заморозка, показ деталей, закрытие
• разные бонусные программы
• возможность взаимодействия с кошельками Google Wallet, Apple Pay и другими
• лимиты
• и много чего еще
При сложении этих двух больших частей вместе получается бесконечное количество возможных UX решений. И всё это нужно программировать👨💻
Такие неоднозначные случаи часто спрашивают на собесах. Для примера, на видео:
— есть два разных горизонтальных скролла: свайп между самими картами и скролл внутри контента выбранной карты
— можно проскроллить вертикально, при этом карты должны остаться на экране
— есть показ деталей карты — его решили сделать прямо поверх карты, для этого нужно учитывать все требования выше
✏️ Го обсудим, как бы вы верстали экран как на видео?
Когда говорим о картах, мы чаще всего представляем обычные карточки, которыми расплачиваемся в магазинах. Даже виртуальные карты повторяют эту ассоциацию: их нет в реальном мире, но их рисуют как настоящие карты.
Поэтому отображение карт в приложении часто пытаются сделать осязаемым:
• складывают их в виде кошелька, чтобы их можно было "доставать" жестами
• добавляют 3d модели, чтобы карта выглядела сочно (так сделано, например, в iOS приложении Jazari)
• добавляют всяческие анимации
С другой стороны, вокруг карт есть целая цифровая экосистема:
• транзакции
• управление картой: пин, заморозка, показ деталей, закрытие
• разные бонусные программы
• возможность взаимодействия с кошельками Google Wallet, Apple Pay и другими
• лимиты
• и много чего еще
При сложении этих двух больших частей вместе получается бесконечное количество возможных UX решений. И всё это нужно программировать
Такие неоднозначные случаи часто спрашивают на собесах. Для примера, на видео:
— есть два разных горизонтальных скролла: свайп между самими картами и скролл внутри контента выбранной карты
— можно проскроллить вертикально, при этом карты должны остаться на экране
— есть показ деталей карты — его решили сделать прямо поверх карты, для этого нужно учитывать все требования выше
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1