Heat — это нативный клиент с открытым исходным кодом для iOS и macOS, позволяющий взаимодействовать с самыми популярными LLM-сервисами.
Фичи:
Поддержка популярных LLM-провайдеров (OpenAI, Mistral, Anthropic, Gemini)
Поддержка локальных LLM с открытым исходным кодом с помощью Ollama
Поддержка генерирования изображений (Stable Diffusion и Dall-e)
Поиск и просмотр веб-страниц для повышения точности ответов
Чтение и понимание календаря
Поиск в файловой системе (только для десктопа)
Базовое сохранение данных в памяти
Никаких зависимостей от сервера, кроме доступа к моделям
https://github.com/nathanborror/Heat
#ios
👉 @developer_mobila
Фичи:
Поддержка популярных LLM-провайдеров (OpenAI, Mistral, Anthropic, Gemini)
Поддержка локальных LLM с открытым исходным кодом с помощью Ollama
Поддержка генерирования изображений (Stable Diffusion и Dall-e)
Поиск и просмотр веб-страниц для повышения точности ответов
Чтение и понимание календаря
Поиск в файловой системе (только для десктопа)
Базовое сохранение данных в памяти
Никаких зависимостей от сервера, кроме доступа к моделям
https://github.com/nathanborror/Heat
#ios
👉 @developer_mobila
👍2
Offline-First - это не просто кэширование GET-запросов
Многие путают Offline-Capable (показали кэш, если нет сети) и Offline-First (приложение полностью функционально без сети, сеть - лишь способ синхронизации).
На собеседованиях часто слышу: "Ну, сохраним в Room/Realm, а когда появится сеть - отправим на бэкенд". Звучит просто, пока не натыкаешься на Concurrancy & Conflict Resolution.
Допустим, у нас таск-трекер. Юзер А (в метро) меняет статус задачи на "Done". Юзер Б (в лифте) меняет описание этой же задачи. Оба выходят в онлайн. Что попадет в базу?
Если вы используете стратегию Last Write Wins (LWW), кто-то потеряет данные.
О чем стоит думать при проектировании синхронизации:
1. Optimistic UI: Мы обязаны показать изменение мгновенно. Но как откатить стейт, если сервер вернул 409 Conflict или бизнес-валидацию? Нужен надежный механизм транзакций на клиенте.
2. Queue Management: Очередь запросов должна быть персистентной. Но что, если первый запрос упал? Блокировать всю очередь? Или пропустить и нарушить причинно-следственную связь (causality)?
3. CRDTs (Conflict-free Replicated Data Types): Это "Святой Грааль" распределенных систем.
- Вместо хранения значения, мы храним операции.
- Математика CRDT гарантирует, что независимо от порядка применения операций, итоговое состояние у всех клиентов будет одинаковым (Eventual Consistency).
Практические выводы:
- Не пишите свои велосипеды для синка, если проект сложнее "To-Do листа". Это распределенная система в миниатюре.
- Смотрите в сторону решений, поддерживающих CRDT или дифференциальную синхронизацию "из коробки" (например, PowerSync, Replicache, или старый добрый Couchbase, если позволяет легаси).
- Если пишете сами - всегда версионируйте сущности (Vector Clocks) и проектируйте API так, чтобы сервер мог принимать патчи, а не целиковые объекты.
Offline-First - это не про базу данных на клиенте. Это про умение разруливать энтропию, когда Source of Truth временно недоступен.
#mobile #architecture #systemdesign #offlinefirst
👉 @developer_mobila
Многие путают Offline-Capable (показали кэш, если нет сети) и Offline-First (приложение полностью функционально без сети, сеть - лишь способ синхронизации).
На собеседованиях часто слышу: "Ну, сохраним в Room/Realm, а когда появится сеть - отправим на бэкенд". Звучит просто, пока не натыкаешься на Concurrancy & Conflict Resolution.
Допустим, у нас таск-трекер. Юзер А (в метро) меняет статус задачи на "Done". Юзер Б (в лифте) меняет описание этой же задачи. Оба выходят в онлайн. Что попадет в базу?
Если вы используете стратегию Last Write Wins (LWW), кто-то потеряет данные.
О чем стоит думать при проектировании синхронизации:
1. Optimistic UI: Мы обязаны показать изменение мгновенно. Но как откатить стейт, если сервер вернул 409 Conflict или бизнес-валидацию? Нужен надежный механизм транзакций на клиенте.
2. Queue Management: Очередь запросов должна быть персистентной. Но что, если первый запрос упал? Блокировать всю очередь? Или пропустить и нарушить причинно-следственную связь (causality)?
3. CRDTs (Conflict-free Replicated Data Types): Это "Святой Грааль" распределенных систем.
- Вместо хранения значения, мы храним операции.
- Математика CRDT гарантирует, что независимо от порядка применения операций, итоговое состояние у всех клиентов будет одинаковым (Eventual Consistency).
Практические выводы:
- Не пишите свои велосипеды для синка, если проект сложнее "To-Do листа". Это распределенная система в миниатюре.
- Смотрите в сторону решений, поддерживающих CRDT или дифференциальную синхронизацию "из коробки" (например, PowerSync, Replicache, или старый добрый Couchbase, если позволяет легаси).
- Если пишете сами - всегда версионируйте сущности (Vector Clocks) и проектируйте API так, чтобы сервер мог принимать патчи, а не целиковые объекты.
Offline-First - это не про базу данных на клиенте. Это про умение разруливать энтропию, когда Source of Truth временно недоступен.
#mobile #architecture #systemdesign #offlinefirst
👉 @developer_mobila
👍2❤1
Forwarded from Mobile VK Hub
This media is not supported in your browser
VIEW IN TELEGRAM
Конец года, и снова заканчиваются все подписки 😱
Узнали? Согласны? Не беда — мы как раз разыгрываем промокоды на год от Облака Mail и VK Музыки!
Условия участия простые:
🔹 подпишитесь на наш канал @mobilehubvk
🔹нажмите кнопку «Участвовать»
🔹 дождитесь 30 декабря — в этом посте мы выберем случайным образом 6 победителей
Информацию об организаторе, правилах и призах ищите по ссылке.
Удачи!
Узнали? Согласны? Не беда — мы как раз разыгрываем промокоды на год от Облака Mail и VK Музыки!
Условия участия простые:
🔹 подпишитесь на наш канал @mobilehubvk
🔹нажмите кнопку «Участвовать»
🔹 дождитесь 30 декабря — в этом посте мы выберем случайным образом 6 победителей
Информацию об организаторе, правилах и призах ищите по ссылке.
Удачи!
👍2❤1
👨💻 Как писать чистый код на SwiftUI: вспоминаем паттерны
Легко написать работающий экран на SwiftUI. Сложно написать поддерживаемое приложение. Часто проблема кроется в непонимании того, какие паттерны уже "зашиты" в фреймворк.
В этой статье автор разбирает 5 основных паттернов, которые вы, скорее всего, уже используете, но не называете их своими именами:
🔹 Observer - основа реактивности SwiftUI.
🔹 Builder - магия, которая позволяет писать декларативный UI.
🔹 Adapter - мост в мир UIKit.
🔹 Decorator - суть всех модификаторов.
🔹 Strategy - способ гибкой настройки логики.
Понимание этих концепций поможет не изобретать велосипед, а писать идиоматичный код.
https://medium.com/ios-nest/design-patterns-in-swiftui-9091a4fa722e
#iOS #Engineering #SwiftUI
👉 @developer_mobila
Легко написать работающий экран на SwiftUI. Сложно написать поддерживаемое приложение. Часто проблема кроется в непонимании того, какие паттерны уже "зашиты" в фреймворк.
В этой статье автор разбирает 5 основных паттернов, которые вы, скорее всего, уже используете, но не называете их своими именами:
🔹 Observer - основа реактивности SwiftUI.
🔹 Builder - магия, которая позволяет писать декларативный UI.
🔹 Adapter - мост в мир UIKit.
🔹 Decorator - суть всех модификаторов.
🔹 Strategy - способ гибкой настройки логики.
Понимание этих концепций поможет не изобретать велосипед, а писать идиоматичный код.
https://medium.com/ios-nest/design-patterns-in-swiftui-9091a4fa722e
#iOS #Engineering #SwiftUI
👉 @developer_mobila
👍1
🚀 Что учить мобильному разработчику в 2026 году?
Индустрия не стоит на месте. То, что было «модно» пару лет назад, сегодня - стандарт индустрии, а знание легаси-технологий потихоньку отходит на второй план (но все еще нужно для поддержки).
Мы собрали ключевые фокусы для Junior и Middle разработчиков на этот год. Сверяйте свои планы! 👇
🤖 Android (Kotlin)
🔵 Jetpack Compose: Это уже база. XML верстка уходит в легаси. Если вы еще не перешли на Compose - 2026 год самое время.
🔵 KMP (Kotlin Multiplatform): Главный тренд. Бизнес хочет экономить, и шарить логику между iOS и Android стало стандартом. Учитесь выносить Data и Domain слои в общий модуль.
🔵 Gradle Version Catalogs: Стандарт управления зависимостями.
🍎 iOS (Swift)
🔵 SwiftUI: Как и с Android - это база для новых проектов. UIKit знать нужно (его еще много), но пилить новые экраны лучше декларативно.
🔵 Swift 6 & Concurrency: Разберитесь наконец с
🔵 Смотрим в сторону KMP: Да, iOS-разработчикам тоже полезно понимать, как подключать общие модули на Kotlin. Это повышает вашу ценность на рынке.
🛠 Общее (Must Have)
🔵 AI-ассистенты: Copilot, Cursor или встроенные AI в IDE. Это не «чит», это инструмент ускорения. Учитесь писать правильные промпты для рефакторинга и тестов.
🔵 CI/CD: Понимание, как ваше приложение собирается и летит в стор (GitHub Actions, Fastlane). Не ждите, пока это сделает DevOps, разберитесь сами.
🎓 Совет новичкам: Не пытайтесь выучить всё сразу. Выберите одну киллер-фичу (например, Compose или Concurrency) и углубитесь в нее в этом месяце.
💬 Вопрос: Какую технологию вы поставили себе в план изучить первой в этом году? Пишите в комментарии, обсудим! 👇
#roadmap #карьера #android #ios #тренды2026
👉 @developer_mobila
Индустрия не стоит на месте. То, что было «модно» пару лет назад, сегодня - стандарт индустрии, а знание легаси-технологий потихоньку отходит на второй план (но все еще нужно для поддержки).
Мы собрали ключевые фокусы для Junior и Middle разработчиков на этот год. Сверяйте свои планы! 👇
🤖 Android (Kotlin)
buildSrc и простое перечисление в build.gradle уступают место TOML-файлам.🍎 iOS (Swift)
async/await и Actors. Понимание потокобезопасности отличает Мидла от Джуна.🛠 Общее (Must Have)
🎓 Совет новичкам: Не пытайтесь выучить всё сразу. Выберите одну киллер-фичу (например, Compose или Concurrency) и углубитесь в нее в этом месяце.
💬 Вопрос: Какую технологию вы поставили себе в план изучить первой в этом году? Пишите в комментарии, обсудим! 👇
#roadmap #карьера #android #ios #тренды2026
👉 @developer_mobila
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
💼 Вопрос с собеседования: «Как вы боретесь с утечками памяти?»
Этот вопрос гарантированно зададут на собеседовании и Android, и iOS разработчику. Лид хочет услышать не сухую теорию, а ваши инструменты.
Вот как отличается уровень ответов:
❌ Ответ Джуна:
«Утечка - это когда память не освобождается, забивается, и приложение падает с ошибкой Out Of Memory. Я стараюсь писать чистый код и надеюсь на Garbage Collector (или ARC в iOS)».
👉 Вердикт: Слишком абстрактно. Не понятно, умеет ли кандидат реально находить и чинить проблемы в коде.
✅ Ответ Мидла:
«Утечки чаще всего возникают, когда объекты удерживаются дольше, чем нужно.
Классика жанра:
🤖 Android: Ссылка на
🍎 iOS: Retain Cycle (циклические ссылки), когда два объекта сильно ссылаются друг на друга (часто бывает в кложурах).
Как я их ищу:
1. Инструменты: Не гадаю на кофейной гуще, а запускаю Android Profiler (или библиотеку LeakCanary) / Xcode Instruments (Leaks & Memory Graph).
2. Лечение: Использую
👉 Вердикт: Четкое понимание причины + знание профайлеров + конкретное решение.
💡 Совет: Перед следующим собеседованием запустите свой пет-проект с профайлером. Даже если там нет утечек, вы сможете сказать: «Я проверял свой проект через Instruments/Profiler, потребление памяти стабильное». Это огромный плюс в карму.
Сталкивались с OOM (Out Of Memory) в реальных проектах или пока проносило? 👇
#собеседование #карьера #ios #android #tips
👉 @developer_mobila
Этот вопрос гарантированно зададут на собеседовании и Android, и iOS разработчику. Лид хочет услышать не сухую теорию, а ваши инструменты.
Вот как отличается уровень ответов:
❌ Ответ Джуна:
«Утечка - это когда память не освобождается, забивается, и приложение падает с ошибкой Out Of Memory. Я стараюсь писать чистый код и надеюсь на Garbage Collector (или ARC в iOS)».
👉 Вердикт: Слишком абстрактно. Не понятно, умеет ли кандидат реально находить и чинить проблемы в коде.
✅ Ответ Мидла:
«Утечки чаще всего возникают, когда объекты удерживаются дольше, чем нужно.
Классика жанра:
🤖 Android: Ссылка на
Activity или Context внутри статического поля или долгоживущего фонового потока.🍎 iOS: Retain Cycle (циклические ссылки), когда два объекта сильно ссылаются друг на друга (часто бывает в кложурах).
Как я их ищу:
1. Инструменты: Не гадаю на кофейной гуще, а запускаю Android Profiler (или библиотеку LeakCanary) / Xcode Instruments (Leaks & Memory Graph).
2. Лечение: Использую
WeakReference или [weak self], чтобы разорвать сильную связь».👉 Вердикт: Четкое понимание причины + знание профайлеров + конкретное решение.
💡 Совет: Перед следующим собеседованием запустите свой пет-проект с профайлером. Даже если там нет утечек, вы сможете сказать: «Я проверял свой проект через Instruments/Profiler, потребление памяти стабильное». Это огромный плюс в карму.
Сталкивались с OOM (Out Of Memory) в реальных проектах или пока проносило? 👇
#собеседование #карьера #ios #android #tips
👉 @developer_mobila
👍4❤2
🛠 Хватит писать To-Do листы! Топ бесплатных API для твоего портфолио
Рекрутеры видят сотни «списков задач» и «калькуляторов». Чтобы выделиться, нужно показать работу с сетью, сложным UI, кэшированием и картинками.
Лучший способ это сделать - написать клиент для реального API. Вот подборка бесплатных, стабильных и открытых API, на которых можно построить крутой проект:
🎬 1. The Movie DB (TMDB)
🔵 Что там: Огромная база фильмов, актеров, рейтингов и постеров.
🔵 Чему научишься: Работать со сложными списками (RecyclerView/LazyColumn), пагинацией, поиском и загрузкой изображений (Glide/Coil/Kingfisher).
🔵 Идея: Клон Netflix или «Кинопоиска».
🚀 2. NASA Open APIs
🔵 Что там: Фото дня (APOD), данные о Марсе, астероидах.
🔵 Чему научишься: Работать с красивым медиа-контентом и датами.
🔵 Идея: Приложение «Космос сегодня» с ежедневными уведомлениями.
3. PokéAPI
🔵 Что там: Всё о покемонах. Полностью открытое, не требует ключа (Auth Key).
🔵 Чему научишься: Архитектуре. Данные хорошо структурированы, идеально для тренировки Clean Architecture и маппинга JSON в модели.
🔵 Идея: «Покедекс» с детальной информацией и статами.
📈 4. CoinGecko API
🔵 Что там: Курсы криптовалют в реальном времени.
🔵 Чему научишься: Работать с Websockets (если найдешь) или частым обновлением данных, рисовать графики.
🔵 Идея: Трекер портфеля крипты.
💡 Совет ментора: Не пытайтесь сделать всё сразу. Возьмите один экран (например, список популярных фильмов) и сделайте его идеально: с обработкой ошибок («нет интернета»), скелетоном при загрузке и красивой анимацией. Это ценнее, чем кривое, но большое приложение.
Сохраняй подборку, чтобы не потерять! А какое API вы использовали в своем последнем проекте? 👇
#ресурсы #api #петпроект #ideas #android #ios
👉 @developer_mobila
Рекрутеры видят сотни «списков задач» и «калькуляторов». Чтобы выделиться, нужно показать работу с сетью, сложным UI, кэшированием и картинками.
Лучший способ это сделать - написать клиент для реального API. Вот подборка бесплатных, стабильных и открытых API, на которых можно построить крутой проект:
🎬 1. The Movie DB (TMDB)
🚀 2. NASA Open APIs
3. PokéAPI
📈 4. CoinGecko API
💡 Совет ментора: Не пытайтесь сделать всё сразу. Возьмите один экран (например, список популярных фильмов) и сделайте его идеально: с обработкой ошибок («нет интернета»), скелетоном при загрузке и красивой анимацией. Это ценнее, чем кривое, но большое приложение.
Сохраняй подборку, чтобы не потерять! А какое API вы использовали в своем последнем проекте? 👇
#ресурсы #api #петпроект #ideas #android #ios
👉 @developer_mobila
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
☠️ Баг, который вы не видите, а пользователи ненавидят
Представьте: пользователь заполнил длинную форму регистрации, свернул приложение, чтобы скопировать код из SMS, возвращается... а экран пустой. Данные исчезли. 🤬
Это System-initiated process death. Самая частая причина удаления приложения у пользователей и головная боль разработчиков.
Почему это происходит?
ОС (Android или iOS) всегда не хватает оперативной памяти. Когда ваше приложение уходит в фон, система может «тихо» убить его процесс, чтобы освободить ресурсы для активного окна (например, Камеры).
❌ Ошибка новичка:
«Я храню данные в
Реальность:
✅ Как делать правильно (Level Up):
🤖 Android:
Перестаньте полагаться только на поля класса. Используйте SavedStateHandle.
Это специальный механизм внутри ViewModel, который сохраняет небольшие кусочки данных (ID, поисковый запрос, ввод пользователя) в системный бандл. Система бережно восстановит его даже после смерти процесса.
Гуглить:
🍏 iOS (SwiftUI/UIKit):
В SwiftUI для простых данных (например, выбранная вкладка или текст) используйте обертку
Для сложных данных — сохраняйте их в локальную БД (CoreData/Realm/SwiftData) при каждом изменении, а не при закрытии экрана.
🛠 Как проверить себя (Челлендж на 5 минут):
Не верьте эмулятору. Проверьте свой текущий проект прямо сейчас:
1. Запустите приложение и введите данные в любое поле.
2. Сверните приложение (Home).
3. Android: В настройках разработчика включите опцию «Don't keep activities» (Не сохранять действия).
4. iOS: В Xcode нажмите Debug -> Simulate Memory Warning или остановите дебаг и запустите другое тяжелое приложение.
5. Вернитесь в свое приложение.
Если данные исчезли или случился краш, поздравляю, вы нашли критический баг. Время фиксить!
Знали про SavedStateHandle или по старинке сохраняли всё в базу данных? 👇
#android #ios #bugs #middle #architecture #обучение
👉 @developer_mobila
Представьте: пользователь заполнил длинную форму регистрации, свернул приложение, чтобы скопировать код из SMS, возвращается... а экран пустой. Данные исчезли. 🤬
Это System-initiated process death. Самая частая причина удаления приложения у пользователей и головная боль разработчиков.
Почему это происходит?
ОС (Android или iOS) всегда не хватает оперативной памяти. Когда ваше приложение уходит в фон, система может «тихо» убить его процесс, чтобы освободить ресурсы для активного окна (например, Камеры).
❌ Ошибка новичка:
«Я храню данные в
ViewModel (Android) или в переменной контроллера (iOS), они же живут долго!»Реальность:
ViewModel переживает поворот экрана, но умирает вместе с процессом. Синглтоны тоже сбрасываются.✅ Как делать правильно (Level Up):
🤖 Android:
Перестаньте полагаться только на поля класса. Используйте SavedStateHandle.
Это специальный механизм внутри ViewModel, который сохраняет небольшие кусочки данных (ID, поисковый запрос, ввод пользователя) в системный бандл. Система бережно восстановит его даже после смерти процесса.
Гуглить:
SavedStateHandle, Parcelable.🍏 iOS (SwiftUI/UIKit):
В SwiftUI для простых данных (например, выбранная вкладка или текст) используйте обертку
@SceneStorage. Она автоматически сохраняет и восстанавливает состояние.Для сложных данных — сохраняйте их в локальную БД (CoreData/Realm/SwiftData) при каждом изменении, а не при закрытии экрана.
🛠 Как проверить себя (Челлендж на 5 минут):
Не верьте эмулятору. Проверьте свой текущий проект прямо сейчас:
1. Запустите приложение и введите данные в любое поле.
2. Сверните приложение (Home).
3. Android: В настройках разработчика включите опцию «Don't keep activities» (Не сохранять действия).
4. iOS: В Xcode нажмите Debug -> Simulate Memory Warning или остановите дебаг и запустите другое тяжелое приложение.
5. Вернитесь в свое приложение.
Если данные исчезли или случился краш, поздравляю, вы нашли критический баг. Время фиксить!
Знали про SavedStateHandle или по старинке сохраняли всё в базу данных? 👇
#android #ios #bugs #middle #architecture #обучение
👉 @developer_mobila
👍7🔥2
🛑 Хватит спамить принтами! Дебажим как профи
Признавайтесь, делали так?
У вас есть цикл на 100 элементов, и ошибка вылетает только на 87-м. Вы ставите обычный брейкпоинт и 86 раз яростно жмете «Resume Program» (▶️), проклиная всё на свете, пока не дойдете до нужного состояния.
Или еще хуже:
Есть способ элегантнее, который отличает опытного разработчика от новичка - Conditional Breakpoints (Условные точки останова).
Они останавливают выполнение программы только тогда, когда выполняется определенное условие.
Как это сделать за 5 секунд:
🤖 Android Studio (IntelliJ IDEA):
1. Поставьте обычный красный брейкпоинт.
2. Нажмите на него правой кнопкой мыши.
3. В поле "Condition" напишите условие на языке Kotlin/Java.
Пример:
4. Готово! Студия проигнорирует первые 86 итераций и остановится точно там, где нужно.
🍎 Xcode:
1. Поставьте синий брейкпоинт.
2. Нажмите на него правой кнопкой (или двойной клик) -> "Edit Breakpoint".
3. В поле "Condition" пишите условие на Swift.
Пример:
💡 Бонус-фича для тех, кто не любит останавливаться:
В настройках брейкпоинта уберите галочку Suspend (Остановить) и поставьте галочку Log Message (Evaluate and log).
Теперь IDE будет сама писать в консоль значения переменных при прохождении этой точки, не останавливая приложение. Это те же принты, только вам не нужно пачкать ими код и пересобирать проект!
Какая ваша любимая фишка дебаггера, о которой мало кто знает? Делитесь в комментариях 👇
#productivity #androidstudio #xcode #debug #tips #middle
👉 @developer_mobila
Признавайтесь, делали так?
У вас есть цикл на 100 элементов, и ошибка вылетает только на 87-м. Вы ставите обычный брейкпоинт и 86 раз яростно жмете «Resume Program» (▶️), проклиная всё на свете, пока не дойдете до нужного состояния.
Или еще хуже:
Log.d("TAG", "Я тут")Log.d("TAG", "А теперь тут, значение i = $i")Есть способ элегантнее, который отличает опытного разработчика от новичка - Conditional Breakpoints (Условные точки останова).
Они останавливают выполнение программы только тогда, когда выполняется определенное условие.
Как это сделать за 5 секунд:
🤖 Android Studio (IntelliJ IDEA):
1. Поставьте обычный красный брейкпоинт.
2. Нажмите на него правой кнопкой мыши.
3. В поле "Condition" напишите условие на языке Kotlin/Java.
Пример:
item.id == 87 или user.name.contains("Test") && i > 504. Готово! Студия проигнорирует первые 86 итераций и остановится точно там, где нужно.
🍎 Xcode:
1. Поставьте синий брейкпоинт.
2. Нажмите на него правой кнопкой (или двойной клик) -> "Edit Breakpoint".
3. В поле "Condition" пишите условие на Swift.
Пример:
indexPath.row == 87💡 Бонус-фича для тех, кто не любит останавливаться:
В настройках брейкпоинта уберите галочку Suspend (Остановить) и поставьте галочку Log Message (Evaluate and log).
Теперь IDE будет сама писать в консоль значения переменных при прохождении этой точки, не останавливая приложение. Это те же принты, только вам не нужно пачкать ими код и пересобирать проект!
Какая ваша любимая фишка дебаггера, о которой мало кто знает? Делитесь в комментариях 👇
#productivity #androidstudio #xcode #debug #tips #middle
👉 @developer_mobila
❤3👍2
👆 Почему пользователи ненавидят ваши кнопки (даже если они красивые)
Знакомая ситуация: вы сверстали экран идеально по макету. Иконка «Закрыть» (крестик) - ровно 24x24, как нарисовал дизайнер.
Но пользователи бесятся, тыкая в нее по 5 раз, и не могут попасть.
Это классическая ошибка новичка: путать видимый размер и кликабельную область.
В гайдлайнах (HIG и Material Design) написано кровью:
🔴 Минимальная область нажатия:
🔵 🍎 iOS: 44x44 pt
🔵 🤖 Android: 48x48 dp
Если ваша иконка меньше (например, 24x24), вы обязаны искусственно увеличить область нажатия, не меняя визуал.
Как это сделать грамотно:
🤖 Android (Compose & XML):
🔵 Compose: Используйте модификатор
🔵 XML: Добавьте
🍏 iOS (SwiftUI & UIKit):
🔵 SwiftUI: Распространенная ошибка — вешать
🔵 Плохо:
🔵 Хорошо:
🔵 UIKit: Переопределите метод
💡 Лайфхак:
Включите в настройках разработчика на телефоне «Показывать границы элементов» (Show layout bounds). Если вы видите маленькие прямоугольники вокруг кнопок, это повод для рефакторинга.
Заботьтесь о пальцах своих пользователей! А вы спорите с дизайнерами, когда они рисуют слишком мелкие элементы? 👇
#ux #ui #android #ios #tips #mobile #design
👉 @developer_mobila
Знакомая ситуация: вы сверстали экран идеально по макету. Иконка «Закрыть» (крестик) - ровно 24x24, как нарисовал дизайнер.
Но пользователи бесятся, тыкая в нее по 5 раз, и не могут попасть.
Это классическая ошибка новичка: путать видимый размер и кликабельную область.
В гайдлайнах (HIG и Material Design) написано кровью:
🔴 Минимальная область нажатия:
Если ваша иконка меньше (например, 24x24), вы обязаны искусственно увеличить область нажатия, не меняя визуал.
Как это сделать грамотно:
🤖 Android (Compose & XML):
.minimumInteractiveComponentSize(). Он сам добавит невидимые отступы, чтобы дотянуть размер до 48dp.padding="12dp" к самому ImageView или оберните его в прозрачный контейнер, на который повесьте клик. Не используйте TouchDelegate без крайней нужды, это больно.🍏 iOS (SwiftUI & UIKit):
.onTapGesture на маленькую иконку.Image("close").onTapGesture { ... }Image("close").frame(width: 44, height: 44).contentShape(Rectangle()).onTapGesture { ... } (мы делаем прозрачную рамку вокруг).point(inside:with:) в кнопке, чтобы она ловила касания за своими пределами.💡 Лайфхак:
Включите в настройках разработчика на телефоне «Показывать границы элементов» (Show layout bounds). Если вы видите маленькие прямоугольники вокруг кнопок, это повод для рефакторинга.
Заботьтесь о пальцах своих пользователей! А вы спорите с дизайнерами, когда они рисуют слишком мелкие элементы? 👇
#ux #ui #android #ios #tips #mobile #design
👉 @developer_mobila
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5👏1
🍝 Ваш код похож на спагетти? Синдром «Божественного объекта»
Знакомая картина: открываешь проект, заходишь в
Там и работа с сетью, и валидация полей, и анимации, и сохранение в базу, и даже форматирование даты. В мире разработки это называется God Object (или Massive View Controller).
Почему это плохо?
1. Невозможно тестировать. Как написать юнит-тест на класс, который делает всё?
2. Сложно менять. Поправил верстку — сломалась база данных.
3. Конфликты при слиянии. В команде двое разработчиков полезли в этот файл — здравствуй, merge conflict на полдня.
🚀 Как лечить (Гайд для перехода в Middle):
Если видишь класс больше 300-400 строк, начинай «резню»:
1. ✂️ Всю логику сети - в Repository.
Во View/Activity не должно быть
2. ✂️ Всю бизнес-логику - в UseCases (Интеракторы).
Валидация пароля, подсчет корзины, фильтрация списков - это чистая логика. Выносите её в отдельные классы (
3. ✂️ Сложный UI - в Custom Views / Child ViewControllers.
Если у вас в адаптере списка 500 строк кода настройки ячеек - вынесите ячейку в отдельный класс с методом
💡 Правило одной ответственности (SRP):
Класс должен иметь только одну причину для изменения.
🔵 Если дизайнер поменял цвет кнопок - меняем только View.
🔵 Если бэкенд поменял формат JSON, меняем только DTO/Repository.
🔵 Если эти изменения заставляют вас править один и тот же файл, у вас архитектурная проблема.
🏁 Задание на неделю:
Найдите самый «жирный» класс в своем проекте и попытайтесь вынести из него хотя бы одну функцию в отдельный вспомогательный класс. Ваш код скажет вам спасибо.
Сколько строк в самом большом файле вашего текущего проекта? Пишите честно 👇
#architecture #cleanCode #refactoring #middle #android #ios
👉 @developer_mobila
Знакомая картина: открываешь проект, заходишь в
MainActivity или ProfileViewController, а там... 1500 строк кода. 😱Там и работа с сетью, и валидация полей, и анимации, и сохранение в базу, и даже форматирование даты. В мире разработки это называется God Object (или Massive View Controller).
Почему это плохо?
1. Невозможно тестировать. Как написать юнит-тест на класс, который делает всё?
2. Сложно менять. Поправил верстку — сломалась база данных.
3. Конфликты при слиянии. В команде двое разработчиков полезли в этот файл — здравствуй, merge conflict на полдня.
🚀 Как лечить (Гайд для перехода в Middle):
Если видишь класс больше 300-400 строк, начинай «резню»:
1. ✂️ Всю логику сети - в Repository.
Во View/Activity не должно быть
http-клиентов и JSON-парсинга. Она должна просто сказать: repository.getUsers() и показать спиннер.2. ✂️ Всю бизнес-логику - в UseCases (Интеракторы).
Валидация пароля, подсчет корзины, фильтрация списков - это чистая логика. Выносите её в отдельные классы (
PasswordValidator, CartCalculator).3. ✂️ Сложный UI - в Custom Views / Child ViewControllers.
Если у вас в адаптере списка 500 строк кода настройки ячеек - вынесите ячейку в отдельный класс с методом
bind(data).💡 Правило одной ответственности (SRP):
Класс должен иметь только одну причину для изменения.
🏁 Задание на неделю:
Найдите самый «жирный» класс в своем проекте и попытайтесь вынести из него хотя бы одну функцию в отдельный вспомогательный класс. Ваш код скажет вам спасибо.
Сколько строк в самом большом файле вашего текущего проекта? Пишите честно 👇
#architecture #cleanCode #refactoring #middle #android #ios
👉 @developer_mobila
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1🤡1🥱1
🧹 Убираем за собой: Как не опозориться при Code Review
Знакомая ситуация? Вы работали над фичей, сделали 10 коммитов с названиями:
🔵
🔵
🔵
🔵
🔵
А потом отправляете это в Pull Request. Тимлид открывает историю и… плачет кровавыми слезами. 🩸
Отличное правило хорошего тона: «Ветка может быть грязной, пока она локальна. Но в
Вам нужен Git Interactive Rebase. Это магия, которая позволяет переписать историю.
🛠 Как это сделать (Консоль / IDE):
Допустим, вы хотите объединить последние 5 мелких коммитов в один красивый.
1. Пишем в терминале:
2. Откроется редактор со списком ваших коммитов. Перед каждым стоит слово
3. Меняем команды:
🔵 Оставляем
🔵 У остальных меняем
🔵 Если хотите переименовать - используйте
4. Сохраняем и закрываем. Git предложит написать одно общее сообщение для нового «супер-коммита».
5. Отправляем на сервер:
💡 Результат:
Вместо 5 мусорных записей у вас одна красивая:
Коллеги на ревью скажут спасибо:
✅ Проще читать изменения.
✅ Если баг - проще откатить один коммит, чем искать в куче мелких.
А вы используете Rebase или предпочитаете честную историю со всеми «фиксами»? 👇
#git #teamwork #middle #tips #tools #bestpractices
👉 @developer_mobila
Знакомая ситуация? Вы работали над фичей, сделали 10 коммитов с названиями:
initwipfix crashfix typoaaaaa rabotay plsА потом отправляете это в Pull Request. Тимлид открывает историю и… плачет кровавыми слезами. 🩸
Отличное правило хорошего тона: «Ветка может быть грязной, пока она локальна. Но в
main должен уйти чистый и атомарный код».Вам нужен Git Interactive Rebase. Это магия, которая позволяет переписать историю.
🛠 Как это сделать (Консоль / IDE):
Допустим, вы хотите объединить последние 5 мелких коммитов в один красивый.
1. Пишем в терминале:
git rebase -i HEAD~52. Откроется редактор со списком ваших коммитов. Перед каждым стоит слово
pick.3. Меняем команды:
pick у самого первого (верхнего) коммита.pick на squash (или s) - это значит «сплющить» этот коммит с предыдущим.reword.4. Сохраняем и закрываем. Git предложит написать одно общее сообщение для нового «супер-коммита».
5. Отправляем на сервер:
git push --force (Осторожно! Делайте это только в своей ветке, пока никто другой в ней не работает).💡 Результат:
Вместо 5 мусорных записей у вас одна красивая:
Feature: Added dark mode implementation.Коллеги на ревью скажут спасибо:
✅ Проще читать изменения.
✅ Если баг - проще откатить один коммит, чем искать в куче мелких.
А вы используете Rebase или предпочитаете честную историю со всеми «фиксами»? 👇
#git #teamwork #middle #tips #tools #bestpractices
👉 @developer_mobila
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1
🔐 Вы только что подарили хакерам доступ. Где НЕЛЬЗЯ хранить ключи
Классическая история: вы пишете пет-проект, используете API (например, ChatGPT или Firebase), и пишете прямо в коде:
Потом
А утром ваш ключ заблокирован, или с карты списали деньги за чужой трафик.
🤖 Реальность: Боты сканируют публичные репозитории GitHub на наличие строк, похожих на ключи, за секунды после публикации. Удалить коммит не поможет, он уже в кеше у злоумышленников.
Как делать правильно (Middle Way):
Секреты никогда не должны попадать в систему контроля версий (Git). Они должны жить только локально на вашем компьютере.
🤖 Android:
Используйте файл
1. Откройте
2. В
3. В коде используйте:
🍏 iOS:
Вариантов много, но самый простой для старта:
1. Создайте файл
2. Сразу же добавьте его в
3. Запишите ключ туда.
4. В настройках проекта (Build Settings) подключите этот конфиг или считывайте файл программно.
🛡 Золотое правило:
Если вы клонируете свой проект на чистый ноутбук, он не должен собраться сразу. Он должен попросить вас создать локальный файл с ключами. Это не баг, это безопасность.
Признавайтесь, случалось случайно комитить пароли или токены? 👇
#security #android #ios #git #tips #middle #safety
👉 @developer_mobila
Классическая история: вы пишете пет-проект, используете API (например, ChatGPT или Firebase), и пишете прямо в коде:
val apiKey = "sk-proj-12345..."Потом
git push, и вы идете спать.А утром ваш ключ заблокирован, или с карты списали деньги за чужой трафик.
🤖 Реальность: Боты сканируют публичные репозитории GitHub на наличие строк, похожих на ключи, за секунды после публикации. Удалить коммит не поможет, он уже в кеше у злоумышленников.
Как делать правильно (Middle Way):
Секреты никогда не должны попадать в систему контроля версий (Git). Они должны жить только локально на вашем компьютере.
🤖 Android:
Используйте файл
local.properties. Он по умолчанию добавлен в .gitignore.1. Откройте
local.properties и добавьте: MY_API_KEY="ваш_ключ".2. В
build.gradle (app) считайте его и прокиньте в код:
defaultConfig {
buildConfigField("String", "API_KEY", gradleLocalProperties(rootDir).getProperty("MY_API_KEY"))
}
3. В коде используйте:
BuildConfig.API_KEY.🍏 iOS:
Вариантов много, но самый простой для старта:
1. Создайте файл
Secrets.xcconfig (или .plist).2. Сразу же добавьте его в
.gitignore.3. Запишите ключ туда.
4. В настройках проекта (Build Settings) подключите этот конфиг или считывайте файл программно.
🛡 Золотое правило:
Если вы клонируете свой проект на чистый ноутбук, он не должен собраться сразу. Он должен попросить вас создать локальный файл с ключами. Это не баг, это безопасность.
Признавайтесь, случалось случайно комитить пароли или токены? 👇
#security #android #ios #git #tips #middle #safety
👉 @developer_mobila
👍5🔥2
Холодный старт (Cold Start) и как не заставлять пользователя ждать.
🕓 Правило 3 секунд: Почему ваше приложение удаляют сразу после установки
Знаете ли вы, что 53% пользователей закрывают и удаляют приложение, если оно грузится дольше 3 секунд?
Новички часто совершают одну и ту же ошибку: «Напихаю-ка я инициализацию всей аналитики, рекламы, базы данных и сетевых клиентов в самый старт, чтобы потом всё было готово».
В итоге пользователь видит белый экран или зависшее лого на 5 секунд. Это Холодный старт (Cold Start) - момент, когда система создает процесс вашего приложения с нуля.
🛑 Главные убийцы скорости:
1. Тяжелый
Если вы инициализируете 15 библиотек в главном потоке (Main Thread) до того, как покажется первый экран - вы тормозите запуск.
2. Фейковые Сплэш-экраны.
Никогда (слышите, никогда!) не делайте
🚀 Как ускорить запуск (Чек-лист Мидла):
✅ Ленивая загрузка (Lazy Init):
Инициализируйте тяжелые библиотеки (например, чаты поддержки или карты) только тогда, когда пользователь реально открывает нужный экран, а не при старте.
✅ Фоновые потоки:
Если библиотеку нужно загрузить сразу, делайте это в
✅ Правильный Splash Screen:
🔵 🤖 Android: Используйте официальный
🔵 🍎 iOS: Сделайте
🛠 Как измерить:
Не считайте «на глаз»!
🔵 Android: В логах (Logcat) ищите строку
🔵 iOS: В Xcode зайдите в Product -> Profile -> App Launch. Instruments покажут каждый миллисекунду задержки.
А вы следите за временем запуска или надеетесь на мощные смартфоны пользователей? 👇
#performance #optimization #android #ios #coldstart #middle
👉 @developer_mobila
🕓 Правило 3 секунд: Почему ваше приложение удаляют сразу после установки
Знаете ли вы, что 53% пользователей закрывают и удаляют приложение, если оно грузится дольше 3 секунд?
Новички часто совершают одну и ту же ошибку: «Напихаю-ка я инициализацию всей аналитики, рекламы, базы данных и сетевых клиентов в самый старт, чтобы потом всё было готово».
В итоге пользователь видит белый экран или зависшее лого на 5 секунд. Это Холодный старт (Cold Start) - момент, когда система создает процесс вашего приложения с нуля.
🛑 Главные убийцы скорости:
1. Тяжелый
Application.onCreate (Android) / didFinishLaunching (iOS).Если вы инициализируете 15 библиотек в главном потоке (Main Thread) до того, как покажется первый экран - вы тормозите запуск.
2. Фейковые Сплэш-экраны.
Никогда (слышите, никогда!) не делайте
Thread.sleep(2000) или таймер на стартовом экране, «чтобы пользователь успел разглядеть логотип». Это бесит.🚀 Как ускорить запуск (Чек-лист Мидла):
✅ Ленивая загрузка (Lazy Init):
Инициализируйте тяжелые библиотеки (например, чаты поддержки или карты) только тогда, когда пользователь реально открывает нужный экран, а не при старте.
✅ Фоновые потоки:
Если библиотеку нужно загрузить сразу, делайте это в
Coroutines (Dispatchers.IO) или DispatchQueue.global(). Главный поток должен заниматься только отрисовкой UI.✅ Правильный Splash Screen:
androidx.core:core-splashscreen. Он нативен, красив и работает мгновенно, пока грузится ваш процесс.LaunchScreen.storyboard максимально легким. Никакого кода, только статика.🛠 Как измерить:
Не считайте «на глаз»!
Displayed. Там система сама пишет: ActivityManager: Displayed com.app/.StartActivity: +850ms.А вы следите за временем запуска или надеетесь на мощные смартфоны пользователей? 👇
#performance #optimization #android #ios #coldstart #middle
👉 @developer_mobila
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1
💉 Dependency Injection: Зачем усложнять, если можно просто написать
Когда новичок видит код с кучей аннотаций
❌ Код Джуна (Hard dependency):
В чем проблема?
Представьте, что вы строите дом. Этот код как если бы вы вмуровали кофемашину прямо в стену кухни.
1. Хотите заменить кофемашину на новую? Придется ломать стену (переписывать код класса).
2. Хотите протестировать кухню, не варя кофе? Не получится, машина там намертво.
✅ Код Мидла (Dependency Injection):
В чем суть?
Вы говорите: "Мне для работы нужна база данных. Дайте мне её, я не хочу сам её создавать".
Это как розетка. Вы не вмуровываете технику в стену, вы просто втыкаете вилку. Сегодня это дешевый чайник (тестовая база), завтра мощная кофемашина (реальный сервер).
🛠 Инструменты (Что учить):
🤖 Android:
• Hilt (Dagger): Стандарт от Google. Мощный, проверяет ошибки при компиляции, но сложный в настройке.
• Koin: Service Locator (технически не совсем DI, но решает те же задачи). Простой, пишется на чистом Kotlin, но ошибки могут вылезти в рантайме. Идеально для старта.
🍏 iOS:
• Swinject: Классика DI контейнеров.
• Swift Native: В современных проектах часто используют просто Factory Pattern или передачу зависимостей через
💡 Совет:
На собеседовании на вопрос "Что такое DI?" не начинайте рассказывать про даггер.
Скажите просто: "Это принцип, когда объекты не создают свои зависимости сами, а получают их извне. Это нужно для тестируемости и гибкости кода". Это ответ уровня Senior.
А что используете вы в своих проектах? 👇
#architecture #di #hilt #koin #ios #android #middle #patterns
👉 @developer_mobila
new?Когда новичок видит код с кучей аннотаций
@Inject или модулей, у него возникает вопрос: "Зачем всё это? Я же могу просто создать объект внутри класса!"❌ Код Джуна (Hard dependency):
class UserRepository {
// Мы "приварили" конкретную базу данных к репозиторию
private val database = SQLiteDatabase()
fun getUser() { ... }
}
В чем проблема?
Представьте, что вы строите дом. Этот код как если бы вы вмуровали кофемашину прямо в стену кухни.
1. Хотите заменить кофемашину на новую? Придется ломать стену (переписывать код класса).
2. Хотите протестировать кухню, не варя кофе? Не получится, машина там намертво.
✅ Код Мидла (Dependency Injection):
class UserRepository(private val database: Database) {
// Мы просим дать нам ЛЮБУЮ базу данных через конструктор
}
В чем суть?
Вы говорите: "Мне для работы нужна база данных. Дайте мне её, я не хочу сам её создавать".
Это как розетка. Вы не вмуровываете технику в стену, вы просто втыкаете вилку. Сегодня это дешевый чайник (тестовая база), завтра мощная кофемашина (реальный сервер).
🛠 Инструменты (Что учить):
🤖 Android:
• Hilt (Dagger): Стандарт от Google. Мощный, проверяет ошибки при компиляции, но сложный в настройке.
• Koin: Service Locator (технически не совсем DI, но решает те же задачи). Простой, пишется на чистом Kotlin, но ошибки могут вылезти в рантайме. Идеально для старта.
🍏 iOS:
• Swinject: Классика DI контейнеров.
• Swift Native: В современных проектах часто используют просто Factory Pattern или передачу зависимостей через
init, без сторонних библиотек. Это самый чистый путь.💡 Совет:
На собеседовании на вопрос "Что такое DI?" не начинайте рассказывать про даггер.
Скажите просто: "Это принцип, когда объекты не создают свои зависимости сами, а получают их извне. Это нужно для тестируемости и гибкости кода". Это ответ уровня Senior.
А что используете вы в своих проектах? 👇
#architecture #di #hilt #koin #ios #android #middle #patterns
👉 @developer_mobila
👍5
🏎 Гонка потоков: Баг, который исчезает, когда вы пытаетесь его найти
Представьте ситуацию: у вас на банковском счете 100$. Вы и ваша жена одновременно (в одну миллисекунду) пытаетесь снять 10$ через разные банкоматы.
В теории должно остаться 80$.
На практике, из-за Race Condition, может остаться 90$. Банк потерял деньги. 💸
Почему так происходит?
Даже простая операция
1. Считать текущее значение (100).
2. Прибавить единицу (101).
3. Записать новое значение (101).
Если два потока начнут выполнять шаг 1 одновременно, они оба "увидят" 100. Оба прибавят 1 и запишут 101. Одно действие потеряется навсегда.
🐛 Heisenbug (Гейзенбаг):
Самое страшное в гонках то, что они часто исчезают, когда вы начинаете дебажить (добавляете
🛡 Как защититься (Инструменты Мидла):
🤖 Android (Kotlin):
🔵 Atomic-типы: Для простых счетчиков используйте
🔵 Mutex (для Coroutines): Это "светофор" для корутин.
• StateFlow: Позволяет безопасно обновлять состояние UI, избегая гонок.
🍏 iOS (Swift):
• Actors (Swift 5.5+): В 2026 году это стандарт. Акторы автоматически защищают свое изменяемое состояние. Вам не нужны ручные блокировки.
• Serial Queues (GCD): Старая добрая очередь, где задачи выполняются строго по одной.
💡 Совет: Если у вас в приложении есть переменная
Сталкивались с багами, которые невозможно повторить на устройстве разработчика? 👇
#concurrency #multithreading #android #ios #kotlin #swift #bugs
👉 @developer_mobila
Представьте ситуацию: у вас на банковском счете 100$. Вы и ваша жена одновременно (в одну миллисекунду) пытаетесь снять 10$ через разные банкоматы.
В теории должно остаться 80$.
На практике, из-за Race Condition, может остаться 90$. Банк потерял деньги. 💸
Почему так происходит?
Даже простая операция
count++ (увеличение счетчика) для процессора - это три действия:1. Считать текущее значение (100).
2. Прибавить единицу (101).
3. Записать новое значение (101).
Если два потока начнут выполнять шаг 1 одновременно, они оба "увидят" 100. Оба прибавят 1 и запишут 101. Одно действие потеряется навсегда.
🐛 Heisenbug (Гейзенбаг):
Самое страшное в гонках то, что они часто исчезают, когда вы начинаете дебажить (добавляете
print или брейкпоинты), так как это меняет тайминги выполнения потоков.🛡 Как защититься (Инструменты Мидла):
🤖 Android (Kotlin):
AtomicInteger или AtomicBoolean. Они гарантируют атомарность операций.
val mutex = Mutex()
mutex.withLock {
// Код здесь выполняется только одним потоком за раз
count++
}
• StateFlow: Позволяет безопасно обновлять состояние UI, избегая гонок.
🍏 iOS (Swift):
• Actors (Swift 5.5+): В 2026 году это стандарт. Акторы автоматически защищают свое изменяемое состояние. Вам не нужны ручные блокировки.
actor BankAccount {
var balance = 100
func withdraw(amount: Int) { balance -= amount }
}
• Serial Queues (GCD): Старая добрая очередь, где задачи выполняются строго по одной.
💡 Совет: Если у вас в приложении есть переменная
var, которую меняют из разных фоновых потоков, это бомба замедленного действия. Заверните её в Atomic, Mutex или Actor.Сталкивались с багами, которые невозможно повторить на устройстве разработчика? 👇
#concurrency #multithreading #android #ios #kotlin #swift #bugs
👉 @developer_mobila
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1