☠️ Баг, который вы не видите, а пользователи ненавидят
Представьте: пользователь заполнил длинную форму регистрации, свернул приложение, чтобы скопировать код из 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
❤3👍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
👍5❤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
👍6🔥3
Холодный старт (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
👍6
💉 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
👍6
🏎 Гонка потоков: Баг, который исчезает, когда вы пытаетесь его найти
Представьте ситуацию: у вас на банковском счете 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
🤖 Хватит быть «человеком-компилятором» на Code Review
Вам знакомо это чувство, когда вы открываете Pull Request коллеги, и вместо того, чтобы проверять логику, пишете:
🔵 «Тут лишний пробел»
🔵 «Название функции с большой буквы?»
🔵 «Удали неиспользуемый импорт»
Это трата дорогого времени разработчика. Эти споры (Tab vs Space, где ставить фигурную скобку) должны решать роботы, а не люди.
В 2026 году стыдно не иметь настроенный Linter (Линтер) в проекте.
🛠 Что подключить прямо сейчас:
🤖 Android (Kotlin):
1. Ktlint: Следит за стилем кода (официальный Kotlin Style Guide). Умеет сам форматировать файл по команде (
2. Detekt: Это уже тяжелая артиллерия. Он ищет не просто кривые отступы, а потенциальные баги: слишком сложные функции, магические числа, пустые блоки
🍏 iOS (Swift):
1. SwiftLint: Стандарт индустрии. Настраивается через
🔵 Пример правила:
🚀 Уровень Pro (Git Hooks):
Настройте Pre-commit hook.
Это скрипт, который запускает линтер до того, как коммит вообще создастся.
Если линтер найдет ошибку - Git просто не даст сделать коммит.
Итог: В репозиторий физически невозможно запушить «грязный» код.
💡 Договоритесь с командой о правилах один раз, запишите их в конфиг линтера и забудьте. Code Review должен быть про архитектуру и надежность, а не про красоту текста.
У вас в проекте стоит жесткий запрет на варнинги (Treat warnings as errors) или «пусть висят»? 👇
#ci #quality #detekt #swiftlint #ktlint #automation #middle
👉 @developer_mobila
Вам знакомо это чувство, когда вы открываете Pull Request коллеги, и вместо того, чтобы проверять логику, пишете:
Это трата дорогого времени разработчика. Эти споры (Tab vs Space, где ставить фигурную скобку) должны решать роботы, а не люди.
В 2026 году стыдно не иметь настроенный Linter (Линтер) в проекте.
🛠 Что подключить прямо сейчас:
🤖 Android (Kotlin):
1. Ktlint: Следит за стилем кода (официальный Kotlin Style Guide). Умеет сам форматировать файл по команде (
./gradlew ktlintFormat). Больше никаких споров о пробелах.2. Detekt: Это уже тяжелая артиллерия. Он ищет не просто кривые отступы, а потенциальные баги: слишком сложные функции, магические числа, пустые блоки
catch.🍏 iOS (Swift):
1. SwiftLint: Стандарт индустрии. Настраивается через
.swiftlint.yml. Может кидать Warning (желтое) или Error (красное), если код не соответствует правилам команды.force_cast (запрет на использование as!), line_length (длина строки).🚀 Уровень Pro (Git Hooks):
Настройте Pre-commit hook.
Это скрипт, который запускает линтер до того, как коммит вообще создастся.
Если линтер найдет ошибку - Git просто не даст сделать коммит.
Итог: В репозиторий физически невозможно запушить «грязный» код.
У вас в проекте стоит жесткий запрет на варнинги (Treat warnings as errors) или «пусть висят»? 👇
#ci #quality #detekt #swiftlint #ktlint #automation #middle
👉 @developer_mobila
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1
🎨 Почему простой список лагает: Скрытый враг FPS (Overdraw)
Бывало такое? Вы сверстали красивый экран, но при скролле он идет рывками, а телефон в руках начинает нагреваться. Вы смотрите в код адаптера, там всё чисто.
Проблема не в коде. Проблема в Overdraw (Перерисовке).
Это когда система вынуждена закрашивать один и тот же пиксель на экране 3-4 раза за один кадр.
Пример: У вас есть белый фон у
GPU делает 4 лишних действия, хотя пользователь видит только картинку.
🛠 Как увидеть это своими глазами:
🤖 Android:
Это встроенная суперсила, о которой забывают.
1. Идем в Настройки разработчика (Developer Options).
2. Ищем пункт «Отладка наложения GPU» (Debug GPU overdraw).
3. Выбираем «Показывать зоны наложения».
Ваш экран станет психоделически цветным:
• 💙 Синий: 1 слой (Идеал).
• 💚 Зеленый: 2 слоя (Норма).
• 🩷 Розовый: 3 слоя (Стоит обратить внимание).
• ❤️ Красный: 4+ слоя (Плохо! Тут тормозит).
🍏 iOS: В Xcode:
1. Запустите приложение на устройстве.
2. В меню Xcode: Debug -> View Debugging -> Rendering -> Color Blended Layers.
3. Красные зоны покажут места, где смешиваются прозрачные слои (это самое дорогое для GPU).
🚀 Как лечить:
1. Удаляйте лишние фоны (
2. Избегайте прозрачности (alpha). Для GPU просчитать полупрозрачность сложнее, чем просто сплошной цвет.
3. В списках (RecyclerView/LazyColumn) следите, чтобы элементы не рисовали фон там, где его перекрывает картинка.
💡 Задание: Включите этот режим на телефоне и зайдите в популярные приложения (Telegram, YouTube). Посмотрите, как качественно (или нет) они оптимизированы. А потом зайдите в своё. 😉
Знали про эту настройку или всё это время гадали, почему падает FPS? 👇
#performance #ui #fps #android #ios #optimization #middle
👉 @developer_mobila
Бывало такое? Вы сверстали красивый экран, но при скролле он идет рывками, а телефон в руках начинает нагреваться. Вы смотрите в код адаптера, там всё чисто.
Проблема не в коде. Проблема в Overdraw (Перерисовке).
Это когда система вынуждена закрашивать один и тот же пиксель на экране 3-4 раза за один кадр.
Пример: У вас есть белый фон у
Activity -> сверху белый фон у Fragment -> сверху белый фон у карточки товара -> сверху картинка.GPU делает 4 лишних действия, хотя пользователь видит только картинку.
🛠 Как увидеть это своими глазами:
🤖 Android:
Это встроенная суперсила, о которой забывают.
1. Идем в Настройки разработчика (Developer Options).
2. Ищем пункт «Отладка наложения GPU» (Debug GPU overdraw).
3. Выбираем «Показывать зоны наложения».
Ваш экран станет психоделически цветным:
• 💙 Синий: 1 слой (Идеал).
• 💚 Зеленый: 2 слоя (Норма).
• 🩷 Розовый: 3 слоя (Стоит обратить внимание).
• ❤️ Красный: 4+ слоя (Плохо! Тут тормозит).
🍏 iOS: В Xcode:
1. Запустите приложение на устройстве.
2. В меню Xcode: Debug -> View Debugging -> Rendering -> Color Blended Layers.
3. Красные зоны покажут места, где смешиваются прозрачные слои (это самое дорогое для GPU).
🚀 Как лечить:
1. Удаляйте лишние фоны (
background). Если у контейнера уже есть белый фон, не нужно ставить такой же белый фон вложенному TextView2. Избегайте прозрачности (alpha). Для GPU просчитать полупрозрачность сложнее, чем просто сплошной цвет.
3. В списках (RecyclerView/LazyColumn) следите, чтобы элементы не рисовали фон там, где его перекрывает картинка.
💡 Задание: Включите этот режим на телефоне и зайдите в популярные приложения (Telegram, YouTube). Посмотрите, как качественно (или нет) они оптимизированы. А потом зайдите в своё. 😉
Знали про эту настройку или всё это время гадали, почему падает FPS? 👇
#performance #ui #fps #android #ios #optimization #middle
👉 @developer_mobila
👍3👏1
🗣 «У меня не работает»: Почему сеньоры игнорируют ваши сообщения
Классическая ситуация:
Джун пишет в командный чат: «Парни, тут 500-я ошибка при логине, что делать?» и прикладывает скриншот логов.
В ответ - тишина. Или сухое: «Смотри бэкенд».
Почему так? Потому что вопрос сформулирован как «Решите проблему за меня». Это раздражает.
Опытного разработчика отличает умение ценить чужое время. Если вы хотите быстрый и качественный ответ, используйте алгоритм идеального вопроса:
1. Контекст: Что именно ты пытался сделать?
2. Ожидание vs Реальность: Что должно было произойти и что произошло на самом деле?
3. Самое важное - что ты уже попробовал
❌ Плохо: «Я ничего не трогал, оно само».
✅ Хорошо: «Я погуглил ошибку, проверил токен в хедере (он есть) и перезагрузил сервер. Не помогло».
⏳ Правило 15 минут:
Прежде чем дергать коллегу, потратьте ровно 15 минут на самостоятельный поиск решения.
🔵 Если спросили раньше - вы ленивый и не хотите думать.
🔵 Если залипли на 3 часа и молчите - вы тратите деньги компании впустую. Найдите баланс.
🦆 Метод Утенка (Rubber Duck Debugging):
Перед тем как написать вопрос, проговорите его вслух (или напишите в «Избранное» самому себе).
Магия в том, что пока вы структурируете проблему словами, вы в 90% случаев сами находите решение, даже не отправив сообщение.
💡 Совет: Никогда не присылайте код скриншотами! Скриншот нельзя скопировать, чтобы запустить или погуглить. Используйте сниппеты или Gist.
А у вас в команде есть человек, который задает вопросы лучше всех? 👇
#softskills #career #communication #teamwork #middle #tips
👉 @developer_mobila
Классическая ситуация:
Джун пишет в командный чат: «Парни, тут 500-я ошибка при логине, что делать?» и прикладывает скриншот логов.
В ответ - тишина. Или сухое: «Смотри бэкенд».
Почему так? Потому что вопрос сформулирован как «Решите проблему за меня». Это раздражает.
Опытного разработчика отличает умение ценить чужое время. Если вы хотите быстрый и качественный ответ, используйте алгоритм идеального вопроса:
1. Контекст: Что именно ты пытался сделать?
2. Ожидание vs Реальность: Что должно было произойти и что произошло на самом деле?
3. Самое важное - что ты уже попробовал
❌ Плохо: «Я ничего не трогал, оно само».
✅ Хорошо: «Я погуглил ошибку, проверил токен в хедере (он есть) и перезагрузил сервер. Не помогло».
⏳ Правило 15 минут:
Прежде чем дергать коллегу, потратьте ровно 15 минут на самостоятельный поиск решения.
🦆 Метод Утенка (Rubber Duck Debugging):
Перед тем как написать вопрос, проговорите его вслух (или напишите в «Избранное» самому себе).
Магия в том, что пока вы структурируете проблему словами, вы в 90% случаев сами находите решение, даже не отправив сообщение.
💡 Совет: Никогда не присылайте код скриншотами! Скриншот нельзя скопировать, чтобы запустить или погуглить. Используйте сниппеты или Gist.
А у вас в команде есть человек, который задает вопросы лучше всех? 👇
#softskills #career #communication #teamwork #middle #tips
👉 @developer_mobila
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🧟♂️ Зомби в вашем коде: Почему приложение «пухнет» со временем
Бывало такое? Вы открыли экран, закрыли его, а память не освободилась. Сделали так 10 раз и приложение упало.
Поздравляю, у вас Memory Leak (Утечка памяти).
Это происходит, когда объект (например, тяжелая
Главные причины утечек (Checklist):
🛑 Android:
1. Static Context: Никогда не сохраняйте
• Плохо:
2. Забытые слушатели: Если вы подписались на синглтон (
3. Внутренние классы: Анонимные классы (например,
🛑 iOS:
1. Retain Cycles (Циклы сильных ссылок):
Объект А держит Б, а Б держит А. Они никогда не удалятся.
• Классика: Вы передали
• Лечение: Всегда используйте
🛠 Инструменты для поиска (Без них вы слепы):
🐤 Android - LeakCanary:
Библиотека от Square. Must-have в любом debug-билде.
Она автоматически следит за Activity/Fragment. Если происходит утечка, она присылает уведомление (буквально кричит), дампит память и показывает красивое дерево ссылок: кто именно держит ваш объект.
📊 iOS - Memory Graph Debugger:
В Xcode есть встроенная кнопка (три шарика, соединенных линиями) в нижней панели дебага.
Нажимаете её во время работы приложения - и Xcode показывает граф всех объектов в памяти. Ищите фиолетовые восклицательные знаки (⚠️) - это утечки.
💡 Совет: Утечки памяти коварны тем, что на мощном телефоне разработчика они незаметны. А у пользователя на старом Android с 3 ГБ RAM приложение вылетит через 5 минут. Проверяйте память хотя бы раз в спринт.
А вы используете
#memory #performance #leaks #leakcanary #ios #android #middle #optimization
👉 @developer_mobila
Бывало такое? Вы открыли экран, закрыли его, а память не освободилась. Сделали так 10 раз и приложение упало.
Поздравляю, у вас Memory Leak (Утечка памяти).
Это происходит, когда объект (например, тяжелая
Activity или ViewController) уже не нужен пользователю, но сборщик мусора (GC) не может его удалить, потому что кто-то другой всё еще держит на него ссылку.Главные причины утечек (Checklist):
🛑 Android:
1. Static Context: Никогда не сохраняйте
Context или View в статические переменные!• Плохо:
companion object { var myView: TextView? = null } - это удержит всю Activity в памяти навсегда.2. Забытые слушатели: Если вы подписались на синглтон (
LocationManager.addListener(this)), но забыли отписаться в onDestroy - Activity останется жить вечно.3. Внутренние классы: Анонимные классы (например,
Handler или AsyncTask) неявно хранят ссылку на внешний класс.🛑 iOS:
1. Retain Cycles (Циклы сильных ссылок):
Объект А держит Б, а Б держит А. Они никогда не удалятся.
• Классика: Вы передали
self внутрь замыкания (closure), которое сохранено в свойстве этого же класса.• Лечение: Всегда используйте
[weak self] внутри клоужеров, если есть риск цикла.🛠 Инструменты для поиска (Без них вы слепы):
🐤 Android - LeakCanary:
Библиотека от Square. Must-have в любом debug-билде.
Она автоматически следит за Activity/Fragment. Если происходит утечка, она присылает уведомление (буквально кричит), дампит память и показывает красивое дерево ссылок: кто именно держит ваш объект.
📊 iOS - Memory Graph Debugger:
В Xcode есть встроенная кнопка (три шарика, соединенных линиями) в нижней панели дебага.
Нажимаете её во время работы приложения - и Xcode показывает граф всех объектов в памяти. Ищите фиолетовые восклицательные знаки (⚠️) - это утечки.
💡 Совет: Утечки памяти коварны тем, что на мощном телефоне разработчика они незаметны. А у пользователя на старом Android с 3 ГБ RAM приложение вылетит через 5 минут. Проверяйте память хотя бы раз в спринт.
А вы используете
[weak self] везде «на всякий случай» или только там, где нужно? 👇#memory #performance #leaks #leakcanary #ios #android #middle #optimization
👉 @developer_mobila
👍4❤1
🎭 Искусство обмана: Зачем нужны Mock-объекты (и почему без них тесты - мусор)
Представьте: вы пишете тест для экрана Логина.
Вы нажимаете «Войти» в коде теста -> идет запрос на реальный сервер -> сервер отвечает 200 OK -> тест проходит.
На следующий день у вас пропал интернет. Или бэкенд упал. Или Вася с бэкенда поменял JSON.
Ваш тест упал 🔴.
Но ваш код Логина не менялся и работает правильно!
Это Flaky Test (Хрупкий тест). Он проверяет не вашу логику, а погоду на Марсе (доступность сервера).
🛡 Решение: Mocking (Мокирование)
В Unit-тестах мы должны тестировать классы в изоляции.
Ваш
Как это работает (на пальцах):
1. У вас есть интерфейс
2. В реальном приложении вы используете
3. В тесте вы создаете Mock этого репозитория.
Что умеет Mock:
Вы говорите ему: "Слушай, когда у тебя вызовут метод
🛠 Инструменты Мидла:
🤖 Android (Kotlin):
Забудьте про Mockito (он из мира Java). Используйте MockK.
🍏 iOS (Swift):
В Swift часто пишут моки вручную (создают класс
Либо используют генераторы: Sourcery или Cuckoo.
Суть та же:
💡 Главная мысль:
Unit-тесты должны работать без интернета, без эмулятора и выполняться за миллисекунды. Если ваш тест идет 5 секунд - это не Unit-тест.
А какой процент покрытия кода тестами (Code Coverage) в вашем проекте? (Если 0% - не стесняйтесь, ставьте 🌚) 👇
#testing #unit #mockk #android #ios #quality #middle
👉 @developer_mobila
Представьте: вы пишете тест для экрана Логина.
Вы нажимаете «Войти» в коде теста -> идет запрос на реальный сервер -> сервер отвечает 200 OK -> тест проходит.
На следующий день у вас пропал интернет. Или бэкенд упал. Или Вася с бэкенда поменял JSON.
Ваш тест упал 🔴.
Но ваш код Логина не менялся и работает правильно!
Это Flaky Test (Хрупкий тест). Он проверяет не вашу логику, а погоду на Марсе (доступность сервера).
🛡 Решение: Mocking (Мокирование)
В Unit-тестах мы должны тестировать классы в изоляции.
Ваш
ViewModel / Presenter не должен знать, что существует настоящий сервер или база данных. Ему нужно подсунуть «куклу» (Mock).Как это работает (на пальцах):
1. У вас есть интерфейс
AuthRepository.2. В реальном приложении вы используете
NetworkAuthRepository (который ходит в сеть).3. В тесте вы создаете Mock этого репозитория.
Что умеет Mock:
Вы говорите ему: "Слушай, когда у тебя вызовут метод
login("admin", "123"), не ходи ни в какую сеть. Просто верни мне Success мгновенно" (или Error, если хотите проверить обработку ошибок).🛠 Инструменты Мидла:
🤖 Android (Kotlin):
Забудьте про Mockito (он из мира Java). Используйте MockK.
// Создаем мок
val repository = mockk<AuthRepository>()
// Обучаем его (Stubbing)
coEvery { repository.login(any(), any()) } returns Result.Success(User("Max"))
// Тестируем ViewModel
viewModel.onLoginClicked()
// Проверяем, что метод был вызван (Verification)
coVerify { repository.login("admin", "pass") }
🍏 iOS (Swift):
В Swift часто пишут моки вручную (создают класс
MockAuthRepo, реализующий протокол), так как рефлексия ограничена.Либо используют генераторы: Sourcery или Cuckoo.
Суть та же:
class MockAuthRepo: AuthRepository {
var loginResult: Result<User, Error>?
func login(...) {
return loginResult! // Возвращаем то, что настроили заранее
}
}
💡 Главная мысль:
Unit-тесты должны работать без интернета, без эмулятора и выполняться за миллисекунды. Если ваш тест идет 5 секунд - это не Unit-тест.
А какой процент покрытия кода тестами (Code Coverage) в вашем проекте? (Если 0% - не стесняйтесь, ставьте 🌚) 👇
#testing #unit #mockk #android #ios #quality #middle
👉 @developer_mobila
👍1
⚡️ Kotlin — современный мощный инструмент с простым синтаксисом. Он подходит как для бэкенд, так и фронтенд-разработки, к тому же на нем разрабатывают приложения под Android. Присматриваетесь к Kotlin, но еще нет навыков программирования? В OTUS стартовал набор на онлайн-курс «Kotlin Developer. Basic».
Всего через 4 месяца вы:
✔Освоите принципы программирования и алгоритмов
✔Узнаете о возможностях языка Kotlin на практике
✔Научитесь использовать популярные структуры данных
✔Опробуете Kotlin в качестве языка бэкенд- и фронтенд-разработки
И все это на живых вебинарах с ведущими разработчиками и на практике, где вы разработаете собственный проект для портфолио. Пройдите вступительный тест и успейте занять место со скидкой:
https://vk.cc/cUxQm5
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Всего через 4 месяца вы:
✔Освоите принципы программирования и алгоритмов
✔Узнаете о возможностях языка Kotlin на практике
✔Научитесь использовать популярные структуры данных
✔Опробуете Kotlin в качестве языка бэкенд- и фронтенд-разработки
И все это на живых вебинарах с ведущими разработчиками и на практике, где вы разработаете собственный проект для портфолио. Пройдите вступительный тест и успейте занять место со скидкой:
https://vk.cc/cUxQm5
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Подводные камни миграции на Swift 6, о которых стоит знать
Swift 6 вводит более строгие проверки изоляции конкурентности и поддерживает поэтапную миграцию, модуль за модулем. Хотя рекомендуемая Apple стратегия выглядит мягкой, на практике вы можете столкнуться со скрытыми сбоями во время выполнения, особенно когда в проекте одновременно сосуществуют модули на Swift 5 и Swift 6.
В этой статье разберем два реальных кейса, на которых команды регулярно спотыкаются при поэтапной миграции на Swift 6. Мы свяжем их с исходниками Swift Runtime, объясним задумку и триггеры падений, и завершим практическими мерами по снижению рисков и рекомендациями по обновлению.
https://www.hughlee.page/en/posts/swift-6-migration-pitfalls/
#ios
👉 @developer_mobila
Swift 6 вводит более строгие проверки изоляции конкурентности и поддерживает поэтапную миграцию, модуль за модулем. Хотя рекомендуемая Apple стратегия выглядит мягкой, на практике вы можете столкнуться со скрытыми сбоями во время выполнения, особенно когда в проекте одновременно сосуществуют модули на Swift 5 и Swift 6.
В этой статье разберем два реальных кейса, на которых команды регулярно спотыкаются при поэтапной миграции на Swift 6. Мы свяжем их с исходниками Swift Runtime, объясним задумку и триггеры падений, и завершим практическими мерами по снижению рисков и рекомендациями по обновлению.
https://www.hughlee.page/en/posts/swift-6-migration-pitfalls/
#ios
👉 @developer_mobila
👍1
🚀 Хватит собирать билды руками: Введение в CI/CD
Знакомая боль: вы закончили крутую фичу, и QA просит тестовую сборку. Вы переключаете ветку, жмете "Build APK" (или "Archive" в Xcode) и... идете гулять на 20 минут. Ноутбук гудит как турбина самолета, интерфейс тормозит, работать невозможно.
А потом тестировщик пишет: "Слушай, а ты версию (versionCode) забыл поднять, оно не ставится поверх старого". 🤦♂️
Сборка релизов руками со своего компьютера - это огромная трата времени и источник человеческих ошибок (забыли сменить конфиг с Debug на Release, выбрали не тот сертификат).
Взрослые команды используют CI/CD (Continuous Integration / Continuous Deployment).
⚙️ Как это выглядит у Мидлов:
Вы просто делаете
Дальше начинается магия:
1. В облаке просыпается виртуальный сервер.
2. Он скачивает свежий код.
3. Запускает линтеры и Unit-тесты (о которых мы говорили раньше). Если они упали - сборка отменяется, а вам в Slack/Telegram прилетает по шапке.
4. Если всё зелено — сервер сам увеличивает номер версии, собирает приложение и подписывает его нужным ключом.
5. Готовый файл (APK/IPA) автоматически улетает в Firebase App Distribution, TestFlight или прямо в чатик QA.
🛠 Что нужно знать мобильному разработчику (Инструменты):
• Fastlane: Это абсолютный мастхэв индустрии (работает и для iOS, и для Android). Это инструмент, который превращает клики мышкой по настройкам в простой код. Он умеет всё: от сборки до автоматического создания скриншотов для App Store / Google Play.
• GitHub Actions / GitLab CI / Bitrise: Это те самые «облачные серверы» (Runner'ы), которые будут выполнять ваши команды из Fastlane каждый раз, когда вы пушите код.
💡 Правило чистой среды:
Главный плюс CI/CD - код собирается на «чистой» машине. Это навсегда убивает отмазку -А у меня локально всё собирается и работает!". Если код не собрался на CI - значит, он сломан.
#cicd #automation #fastlane #android #ios #middle #githubactions
👉 @developer_mobila
Знакомая боль: вы закончили крутую фичу, и QA просит тестовую сборку. Вы переключаете ветку, жмете "Build APK" (или "Archive" в Xcode) и... идете гулять на 20 минут. Ноутбук гудит как турбина самолета, интерфейс тормозит, работать невозможно.
А потом тестировщик пишет: "Слушай, а ты версию (versionCode) забыл поднять, оно не ставится поверх старого". 🤦♂️
Сборка релизов руками со своего компьютера - это огромная трата времени и источник человеческих ошибок (забыли сменить конфиг с Debug на Release, выбрали не тот сертификат).
Взрослые команды используют CI/CD (Continuous Integration / Continuous Deployment).
⚙️ Как это выглядит у Мидлов:
Вы просто делаете
git push или сливаете Pull Request в ветку develop. ВСЁ. Ваша работа закончена.Дальше начинается магия:
1. В облаке просыпается виртуальный сервер.
2. Он скачивает свежий код.
3. Запускает линтеры и Unit-тесты (о которых мы говорили раньше). Если они упали - сборка отменяется, а вам в Slack/Telegram прилетает по шапке.
4. Если всё зелено — сервер сам увеличивает номер версии, собирает приложение и подписывает его нужным ключом.
5. Готовый файл (APK/IPA) автоматически улетает в Firebase App Distribution, TestFlight или прямо в чатик QA.
🛠 Что нужно знать мобильному разработчику (Инструменты):
• Fastlane: Это абсолютный мастхэв индустрии (работает и для iOS, и для Android). Это инструмент, который превращает клики мышкой по настройкам в простой код. Он умеет всё: от сборки до автоматического создания скриншотов для App Store / Google Play.
• GitHub Actions / GitLab CI / Bitrise: Это те самые «облачные серверы» (Runner'ы), которые будут выполнять ваши команды из Fastlane каждый раз, когда вы пушите код.
💡 Правило чистой среды:
Главный плюс CI/CD - код собирается на «чистой» машине. Это навсегда убивает отмазку -А у меня локально всё собирается и работает!". Если код не собрался на CI - значит, он сломан.
#cicd #automation #fastlane #android #ios #middle #githubactions
👉 @developer_mobila
👍1
🚀 Подборка полезных IT каналов в Max
Системное администрирование, DevOps 📌
https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.
1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика
Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика
GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://max.ru/database_info Все про базы данных
Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков
Библиотеки 📌
https://max.ru/programmist_of Книги по программированию
https://max.ru/proglb Библиотека программиста
https://max.ru/bfbook Книги для программистов
Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼💻👩💻
Шутки программистов 📌
https://max.ru/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://max.ru/thehaking Канал о кибербезопасности
https://max.ru/xakkep_1 Хакер Free
Книги, статьи для дизайнеров 📌
https://max.ru/odesigners Статьи, книги для дизайнеров
Математика 📌
https://max.ru/Pomatematike Канал по математике
https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике
Вакансии 📌
https://max.ru/progjob Вакансии в IT
Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных
Бонус 📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
Системное администрирование, DevOps 📌
https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.
1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика
Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика
GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://max.ru/database_info Все про базы данных
Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков
Библиотеки 📌
https://max.ru/programmist_of Книги по программированию
https://max.ru/proglb Библиотека программиста
https://max.ru/bfbook Книги для программистов
Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼💻👩💻
Шутки программистов 📌
https://max.ru/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://max.ru/thehaking Канал о кибербезопасности
https://max.ru/xakkep_1 Хакер Free
Книги, статьи для дизайнеров 📌
https://max.ru/odesigners Статьи, книги для дизайнеров
Математика 📌
https://max.ru/Pomatematike Канал по математике
https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике
Вакансии 📌
https://max.ru/progjob Вакансии в IT
Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных
Бонус 📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
MAX
Системный Администратор | Sysadmin Windows & Linux Server. Настройка Сети, ПК и Железа. IT Уроки для Сисадмина: Безопасность, Софт…
Блог практикующего админа. Настройка Windows Server, Active Directory (AD), GPO и терминальных серверов (RDP). Работа с Linux: Ubuntu, CentOS, Debian. Сетевое оборудование: Cisco, MikroTik, VPN, DNS, DHCP. Виртуализация (Hyper-V, VMware, Proxmox) и резервное…
👎4💩1
👩💻 Открытый урок «Знакомство с Kotlin: пишем первый код»
🗓 5 марта в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Kotlin Developer. Basic» от Otus.
Программа вебинара:
✔Разберем три ключевых преимущества Kotlin: безопасность null, лаконичность и совместимость.
✔Напишем небольшой, но полезный фрагмент, который решает понятную задачу.
✔Ответим на главный вопрос: почему Kotlin — это не просто «улучшенная Java», а другой подход к разработке.
Вебинар будет полезен:
Начинающим разработчикам, разработчикам на Java, которые хотят писать современный, более безопасный и лаконичный код.
🔗 Ссылка на регистрацию: https://vk.cc/cUZHBX
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🗓 5 марта в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Kotlin Developer. Basic» от Otus.
Программа вебинара:
✔Разберем три ключевых преимущества Kotlin: безопасность null, лаконичность и совместимость.
✔Напишем небольшой, но полезный фрагмент, который решает понятную задачу.
✔Ответим на главный вопрос: почему Kotlin — это не просто «улучшенная Java», а другой подход к разработке.
Вебинар будет полезен:
Начинающим разработчикам, разработчикам на Java, которые хотят писать современный, более безопасный и лаконичный код.
🔗 Ссылка на регистрацию: https://vk.cc/cUZHBX
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
📶 Что видит пользователь, когда заходит в лифт? (Или почему ваш лоадер всех бесит)
Представьте: пользователь едет в метро. Интернет то появляется, то пропадает. Он открывает ваше приложение, чтобы почитать ленту.
❌ Подход Джуна (Прямая труба):
Запрос в сеть
А если пользователь случайно повернет телефон (сменит ориентацию) - лоадер появится снова, потому что Activity пересоздалась и запрос полетел заново. Это боль.
✅ Подход Мидла (Single Source of Truth - SSOT):
Открыл приложение
Как это работает (Паттерн SSOT):
Запомните золотое правило: UI никогда не должен получать данные напрямую из сети!
Единственным источником «правды» для экрана должна быть ваша локальная База Данных (БД).
1. Ваш
2. Когда нужно обновить данные,
3. Скачанные из сети данные сохраняются в Базу Данных.
4. База данных отправляет сигнал в UI: "Эй, у меня новые данные, перерисуйся!".
🛠 Чем пользуются профи:
🤖 Android:
Связка Room + Flow (или LiveData).
Вы пишете в DAO:
🍏 iOS:
Современный SwiftData (или старая добрая CoreData) + макрос
Принцип тот же: UI биндится к хранилищу. Вы просто обновляете контекст базы, а списки на экране разъезжаются и анимируются сами.
💡 Совет:
Такой подход не только спасает от отсутствия интернета, но и решает проблему пагинации, поиска и шаринга данных между разными экранами (ведь все они смотрят в одну базу).
#architecture #offlinefirst #ssot #android #ios #middle #caching
👉 @developer_mobila
Представьте: пользователь едет в метро. Интернет то появляется, то пропадает. Он открывает ваше приложение, чтобы почитать ленту.
❌ Подход Джуна (Прямая труба):
Запрос в сеть
-> Показ лоадера на весь экран -> Ошибка тайм-аута -> Пустой белый экран.А если пользователь случайно повернет телефон (сменит ориентацию) - лоадер появится снова, потому что Activity пересоздалась и запрос полетел заново. Это боль.
✅ Подход Мидла (Single Source of Truth - SSOT):
Открыл приложение
-> Мгновенно увидел вчерашние данные из кэша -> В фоне пошел незаметный запрос в сеть -> Лента плавно обновилась свежими данными.Как это работает (Паттерн SSOT):
Запомните золотое правило: UI никогда не должен получать данные напрямую из сети!
Единственным источником «правды» для экрана должна быть ваша локальная База Данных (БД).
1. Ваш
ViewModel / Presenter просто подписывается на изменения в БД.2. Когда нужно обновить данные,
Repository идет в сеть.3. Скачанные из сети данные сохраняются в Базу Данных.
4. База данных отправляет сигнал в UI: "Эй, у меня новые данные, перерисуйся!".
🛠 Чем пользуются профи:
🤖 Android:
Связка Room + Flow (или LiveData).
Вы пишете в DAO:
fun getNews(): Flow<List<News>>. UI начинает слушать этот Flow. Как только метод из сети сделает insert(newItems) в базу, Room сам протолкнет новые данные в Flow, и UI обновится. Магия!🍏 iOS:
Современный SwiftData (или старая добрая CoreData) + макрос
@Query (в SwiftUI) или Combine.Принцип тот же: UI биндится к хранилищу. Вы просто обновляете контекст базы, а списки на экране разъезжаются и анимируются сами.
💡 Совет:
Такой подход не только спасает от отсутствия интернета, но и решает проблему пагинации, поиска и шаринга данных между разными экранами (ведь все они смотрят в одну базу).
#architecture #offlinefirst #ssot #android #ios #middle #caching
👉 @developer_mobila
⚡2👍1