Все чаще и чаще замечаю, что у многих разработчиков нет навыка презентации своего кода, а между тем за этим навыком будущее. Даже идеально прописанный код теряет ценность, если заказчик не видит пользы для себя. Уже сейчас тебе недостаточно просто хорошо уметь писать код, чтобы отличаться на рынке труда. Поэтому один из главных навыков успешного разработчика - показать, как его работа, влияет на бизнес.
Свяжите код с конкретной бизнес-задачей:
Не углубляйтесь в архитектуру или алгоритмы. Объясните, как ваш код устраняет проблему клиента. Например:
«Раньше пользователи жаловались на долгую загрузку карточек товаров. Мы переработали обработку изображений - теперь страницы открываются моментально, а конверсия в покупки выросла на 20%».
Используйте визуализацию и аналогии:
Найдите способ показать результат: демонстрация работы, видеозаписи и скриншоты интерфейса, упрощенные схемы или сравнение до/после помогут сделать абстрактное понятным.
Замените технический термины на простые формулировки:
Слова вроде «деплоить», «фреймворк», «хард-код» или «дебажить» оставьте для коллег. Клиенту скажите: «Исправили ошибки предыдущей версии, и теперь при регистрации не выдает ошибку».
Акцентируйте выгоды, а не процесс:
Ваш заказчик хочет знать не КАК вы писали код, а ЗАЧЕМ. Для этого продемонстрируйте, как вы помогли добиться бизнес-целей. Начните с проблемы, которую устранили, коротко объясните, что вы сделали. Но главное - покажите результат: «Теперь приложение не зависает в при наплыве пользователей, а значит, клиенты не уйдут к конкурентам из-за провисаний».
Проверяйте понимание:
После объяснения спросите:
«Хотите уточнить, как это повлияет на ваши ежедневные задачи?»
Это покажет, что вы заботитесь о ясности, а не просто отчитались о работе.
Главное: ваш код - не цель, а инструмент. Заказчик должен ясно видеть, что ваш код - это не абстракция, а инструмент, который делает его продукт стабильнее, быстрее и прибыльнее.
Please open Telegram to view this post
VIEW IN TELEGRAM
Ошибки, которые совершают практически все опыте разработчики, и я не исключение:
Работа разработчиком заключается не только в написании кода. Вам платят далеко не только за это, вам платят для того, чтобы вы решали бизнес-проблемы. Соответственно вам нужно уметь говорить с заказчиком на языке бизнес-процессов, и уметь донести какую пользу вы приносите. Подробнее писал в этом посте.
Застревание в зоне комфорта мешает развитию. Пока ваши конкуренты растут и нарабатывают новые скиллы, вы отказываетесь назад только, потому что вы не изучаете ничего нового.
Если вы не обращаете внимание на физическое и ментальное состояние, то в скором времени начнутся проблемы со здоровьем, проблемы в семье, а по итогу круг замыкается, и это приводит к проблемам и на работе.
Разработка - это командная работа, и кто бы что не говорил, в команде важно уметь отстаивать свою позицию. Вы должны уметь доносить ценность ваших решений группе людей, чтобы вас слышали, а не отметали идеи.
Страх перемен держит в плохих условиях и снижает мотивацию. А еще интерес к работе, уважение к себе, веру в людей. Если вам не нравится коллектив - ищите другой, лучше не станет поверьте.
Please open Telegram to view this post
VIEW IN TELEGRAM
Когда мы говорим о безопасности мобильных приложений, первое, что приходит в голову - защита исходного кода, обфускация, шифрование API-ключей. Но есть менее очевидный вектор атаки, который многие упускают из виду: ресурсы приложения. Те самые изображения, JSON-файлы, HTML-шаблоны и конфигурации, которые лежат в папке assets и кажутся безобидными. На самом деле они могут стать троянским конем, превращающим ваше приложение в инструмент мошенников без единого изменения в коде на Dart.
Как работает атака: проще, чем кажется:
Представьте стандартный процесс публикации Flutter-приложения. Вы собираете APK или AAB, подписываете его и отправляете в магазин. Но что происходит с этим APK после сборки?
Любой человек может скачать ваше приложение, выполнить несколько команд:
# Извлекаем ресурсы
apktool d yourapp.apk
# Редактируем файлы в папке assets/
# ...
# Перепаковываем
apktool b yourapp -o modified.apk
# Подписываем (да, даже без вашего ключа!)
zipalign -v 4 modified.apk aligned.apk
apksigner sign --ks fake.keystore aligned.apk
И вот уже существует модифицированная версия вашего приложения, которая выглядит и работает так же, но содержит измененные ресурсы. Этот APK может распространяться через сторонние магазины, мессенджеры или фишинговые сайты.
Сценарии, которые уже происходят:
WebView становится оружием:
Вы используете локальный HTML-файл для отображения справки или условий использования. Кажется безопасным? Хакер заменяет ваш help.html на страницу с фишинговой формой входа, которая крадет логины и пароли пользователей. При этом адресная строка показывает file:///android_asset/help.html - выглядит доверительно.
Конфигурация как бэкдор:
Приложение загружает настройки из config.json. В оригинале там безобидные цвета и тексты. После замены в конфиге появляются:
{
"api_endpoint": "https://malicious-server.com/collect",
"enable_debug": true,
"disable_ssl_checks": true
}
Теперь ваше приложение отправляет все данные на сервер злоумышленника и отключает проверки безопасности.
Кража ключей, которые «никто не найдет»:
Вы положили Firebase-ключ или токен Stripe в assets/secrets.json, решив, что «это же не в коде». Хакер извлекает APK, находит файл за 30 секунд и получает доступ к вашей инфраструктуре.
Защита - многослойный подход:
Минимизация ущерба:
Первый и главный принцип: не храните в ресурсах того, что можно не хранить. Конфигурации должны приходить с защищенного бэкенда. Ключи API - использовать через нативные хранилища или серверные прокси. Если ресурс не критичен для безопасности - проблема отпадает сама собой.
Верификация целостности:
Для ресурсов, которые действительно должны быть локальными, добавьте проверку контрольных сумм:
import 'package:crypto/crypto.dart';
import 'dart:convert';
Future<bool> verifyAsset(String assetPath, String expectedHash) async {
final data = await rootBundle.load(assetPath);
final bytes = data.buffer.asUint8List();
final hash = sha256.convert(bytes).toString();
return hash == expectedHash;
}
Храните хэши в нативной части приложения или получайте их с сервера при первом запуске.
Шифрование на лету:
Критичные данные в ресурсах можно хранить в зашифрованном виде. Например, конфигурационный JSON шифруется AES на этапе сборки и расшифровывается только в памяти при запуске. Ключ шифрования не должен лежать в том же APK.
Безопасность ресурсов - это не опциональная функция, а обязательная часть разработки, особенно для финансовых, медицинских и корпоративных приложений. Злоумышленники ищут самые простые пути взлома, и незащищенные assets - именно такой путь.
Главный вывод: относитесь к ресурсам приложения с тем же уровнем паранойи, что и к исходному коду. Каждый файл в assets должен проходить проверку «а что будет, если его заменить?». Если ответ пугает - значит, нужна защита.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Если в вашем проекте накопилось много ненужных локальных веток, их можно удалить одной командой, оставив только ключевые (например, main и dev).
cd /путь/к/проекту
git branch | grep -v "main" | grep -v "dev" | xargs git branch -D
Как это работает:
git branch - выводит список всех локальных веток.
grep -v "main" и grep -v "dev" - исключают из списка защищённые ветки.
xargs git branch -D — удаляет оставшиеся ветки.
Важно:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Forwarded from Мобильный трудоголик
👨💻 Честно о минусах работы в IT.
На всяких инфокурсах постоянно говорят о плюсах IT: высокие зарплаты, востребованность, удалёнка, крутые офисы с кофе. И это правда, но не целиком. Есть вещи, о которых говорят намного реже, но которые знает каждый, кто проработал в индустрии больше пары лет.
Скажу сразу, это не жалобы на мир IT, это предостережение для новичков от старичка.
1️⃣ Знания устаревают невероятно быстро – то, что работало 2 года назад, сегодня уже не катит. Постоянная учеба – это не развитие, а обязательное условие просто остаться на плаву. Выгорание от вечной "догонялки" – реальная угроза.
2️⃣ Код-костыль, написанный когда-то "на время" код, копится годами. Он замедляет разработку, делает каждое изменение рискованным и дорогим, и живет в проекте как постоянная угроза, которая вот-вот взорвется.
3️⃣ Современные инструменты скрывают сложность (абстракция). Когда что-то ломается глубоко внутри, найти причину – это детектив с расследованием "магии", которую ты не создавал и плохо понимаешь.
4️⃣ Тебе постоянно приходится объяснять сложные технические вещи (почему что-то сломалось, сколько времени займет) людям, которые в этом не разбираются. То, что им кажется простым (например, "сделай баннер"), на деле может требовать огромной работы с твоей стороны. "Просто баннер" для них может означать недели работы и переделку архитектуры для тебя.
5️⃣ Code Review. Процесс улучшения кода часто превращается в арену для демонстрации превосходства, придирок к мелочам и споров о вкусах , а не по существу проблемы.
6️⃣ Адские сроки, ночные марафоны перед релизом - классика жанра. Умение работать в стрессе важно, но цена – хроническая усталость и риск профессионального выгорания. Баланс work-life – постоянный челлендж.
7️⃣ Сидячий Образ Жизни: 8+ часов за монитором – убийственно для спины, шеи, глаз и общего здоровья. Если не заниматься спортом и эргономикой – последствия гарантированы. Как бонус, у вас чаще всего не бывает возможности заниматься спортом, потому что после работы идет еще работа.
8️⃣ Удалёнка. Удобно, но влечет за собой размытие границ между работой и личной жизнью, отсутствие живого общения, зависимость от качества интернета и самодисциплины. Иногда хочется просто "выйти с работы", а возможности нет.
➡️ Подписаться на канал
Мобильный трудоголик
На всяких инфокурсах постоянно говорят о плюсах IT: высокие зарплаты, востребованность, удалёнка, крутые офисы с кофе. И это правда, но не целиком. Есть вещи, о которых говорят намного реже, но которые знает каждый, кто проработал в индустрии больше пары лет.
Скажу сразу, это не жалобы на мир IT, это предостережение для новичков от старичка.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
Квартальные релизы Flutter постепенно становятся похожими на швейцарские часы: предсказуемые, точные и наполненные множеством мелких улучшений, которые в сумме меняют опыт разработки. Версия 3.38 не исключение. На первый взгляд кажется, что это просто еще одно обновление, но под поверхностью скрываются изменения, которые затрагивают самую суть разработки на Flutter: от синтаксиса языка до способа взаимодействия с нативными платформами.
Синтаксическая революция:
Самый обсуждаемый элемент релиза: dot shorthands - на самом деле не фича Flutter, а изменение Dart 3.10. Но именно во Flutter оно проявляется наиболее ярко. Возможность писать .start вместо MainAxisAlignment.start - это не просто сокращение символов. Это изменение философии.
Раньше Dart требовал явности, даже когда контекст был очевиден. Теперь язык доверяет разработчику и инструментам. Компилятор понимает, что в контексте Column параметр mainAxisAlignment может быть только типа MainAxisAlignment. Эта, казалось бы, мелочь меняет ощущение от языка - код становится более плотным, читаемым и менее зашумленным.
Но здесь же кроется и вызов: теперь начинающим разработчикам будет сложнее понять, откуда берется .all в EdgeInsets.all(8). Прозрачность уступает место эффективности - классический компромисс дизайна языков программирования.
Жизненный цикл по-новому - UIScene для iOS:
Поддержка UIScene lifecycle не просто очередная адаптация под требования Apple. Это фундаментальное изменение в том, как Flutter-приложения живут на iOS. Переход от AppDelegate-based к Scene-based архитектуре открывает возможности для более сложных сценариев: несколько окон, улучшенная работа с внешними дисплеями, лучшая интеграция с iPadOS и visionOS.
Но здесь есть и темная сторона: миграция обязательна. Apple уже объявила, что в релизе после iOS 26 приложения, не использующие UIScene, просто не запустятся. Flutter 3.38 дает инструменты для миграции, но сам процесс - еще один пример того, как мобильная разработка становится все сложнее.
Производительность - тихая работа над ошибками:
Никто не будет писать в релизных нотах «исправили 15 мелких утечек памяти и улучшили производительность на 3% в крайних случаях». Но именно такие изменения составляют суть версии 3.38:
Flutter 3.38 - это релиз про зрелость. Зрелость языка, который учится быть более выразительным с меньшим количеством символов. Зрелость инфраструктуры, которая переходит от «работает» к «работает предсказуемо и эффективно». Зрелость экосистемы, которая начинает разделять ответственности.
Главный тренд, который прослеживается во всех изменениях - это движение от монолита к модульности. Dot shorthands отделяют намерение от избыточной специфики. Web-конфигурация отделяет настройки среды от кода. Будущее разделение Material / Cupertino отделяет дизайн-системы от ядра фреймворка.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
Forwarded from Мобильный трудоголик
Главный навык разработчиков будущего - уметь писать не только код, чтобы добавить экран в приложение, но и понимать для чего добавляется та или иная кнопка. Т.е. быть ориентированным на продукт. О чем я кстати не раз уже упоминал в блоге. На таких разработчиков работодатели будут всегда охотнее смотреть, так как они мыслят намного шире своей первоначальной специализации, соответственно решение будет более выигрышно для бизнеса. Вот несколько советов, как развивать его разработчику:
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1🔥1
В русскоязычном ИТ-сообществе существует интересный феномен: некоторые технологии умудряются умирать годами, при этом демонстрируя стабильный рост и принятие в индустрии. Flutter - чемпион в этой категории. Пока в комментариях в интернете пишут очередные некрологи, статистика рассказывает другую историю: каждое третье, новое iOS-приложение в 2024 году создано на Flutter, а в Google Play таких приложений уже более полумиллиона.
Разрыв между нарративом и реальностью:
Есть два параллельных мира Flutter. В первом фреймворк постоянно умирает. Во втором живут реальные метрики - Flutter является самым популярным кроссплатформенным решением уже четвертый год подряд.
Интересно, что этот разрыв не уникален для Flutter. Подобное происходило с Kotlin («зачем нужен, когда есть Java»), TypeScript («сложно, просто пишите на JavaScript»), и многими другими технологиями, которые в итоге стали стандартом индустрии.
Что говорят цифры:
Если отключить эмоции и включить аналитику, картина выглядит иначе:
pub.dev насчитывает 55 тысяч пакетов - рост на 10 тысяч за год.Эти цифры не из пресс-релизов Google. Это данные из отчетов Apptopia, Stack Overflow Developer Survey и публичной статистики магазинов приложений.
Почему нарратив «Flutter мертв» так живуч:
Есть несколько психологических и социальных причин:
Интересно, что аналогичная ситуация была с Docker в начале 2010-х («виртуалки надежнее») и с Kubernetes в середине 2010-х («сложно, зачем»).
Реальные проблемы Flutter в 2025:
Технологические дискуссии часто напоминают спор болельщиков разных футбольных клубов: эмоции преобладают над фактами, а лояльность к своей технологии важнее объективной оценки.
Flutter в 2025 году - это зрелая, стабильно развивающаяся технология с четкой нишей: создание кроссплатформенных приложений с контролируемым, одинаковым UI на всех платформах. Она не подходит для всего (как и любая другая технология), но для своей ниши предлагает отличное решение.
Цифры говорят сами за себя: рост доли рынка, расширяющаяся экосистема, использование крупными компаниями. Эти метрики важнее, чем мнения в комментариях, особенно когда эти мнения повторяют тезисы трехлетней давности, уже не соответствующие реальности.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍1
Обе команды объединяют изменения из одной ветки в другую, но делают это по-разному.
Git Merge:
Создает новый коммит слияния, сохраняя историю всех веток.
# Переключись на ветку, куда нужно влить изменения (например main).
git checkout main
# Влить изменения из ветки feature.
git merge feature
Плюсы:
Минусы:
Git Rebase:
Перемещает ваши коммиты в другую ветку, перезаписывая историю другой ветки таким образом, будто вы только что ответвились от этой ветки и добавили новые коммиты. Все прошлые коммиты в истории данной ветки будут до ваших коммитов.
# Переключись на feature ветку.
git checkout feature
# Перебазировать ее на main.
git rebase main
Плюсы:
Минусы:
Когда вы делаете rebase, Git фактически переписывает историю коммитов - создает новые коммиты с тем же содержимым, но другим хешем.
Если вы уже запушили ветку в удаленный репозиторий, обычный git push без --force не сработает, потому что локальная история и на сервере расходится.
git push --force
Когда что использовать:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1
В арсенале Flutter-разработчика есть десятки виджетов для построения визуала, но ключевое качество современного интерфейса - не только красота, но и его предсказуемое поведение. Как элегантно запретить двойное нажатие на кнопку, сделать слайдер только для чтения или временно приостановить все жесты в сложной форме? Для этих задач существуют специальные виджеты-контроллеры, которые оставаясь невидимыми, кардинально меняют логику взаимодействия. Сегодня разберем двух таких стражей порядка: AbsorbPointer и IgnorePointer.
Суть проблемы - управление потоком событий:
Каждое нажатие, свайп или скролл в приложении - это событие (event), которое проходит определенный путь (hit test) по дереву виджетов, чтобы найти целевой элемент. Иногда необходимо этот поток прервать или перенаправить. Именно здесь на сцену выходят невидимые виджеты-обертки. Их главная задача - влиять на процесс обработки жестов, не изменяя при этом внешний вид дочерних виджетов.
AbsorbPointer - полная блокировка:
Это стена. Когда absorbing: true, все касания останавливаются на этом виджете. События не проходят к дочерним виджетам и не ищут другие цели.
Пример: кнопка отправки формы. Нужно заблокировать ее во время загрузки, но оставить видимой с анимацией:
AbsorbPointer(
absorbing: isLoading,
child: ElevatedButton(...),
)
IgnorePointer - сквозное игнорирование:
Это невидимка. При ignoring: true виджет пропускает события сквозь себя. Hit-тестирование продолжается, события могут попасть в виджеты ниже.
Пример: полупрозрачный баннер поверх карты. Баннер виден, но карта остается интерактивной:
Stack(
children: [
InteractiveMap(),
IgnorePointer(
child: PromoBanner(),
),
],
)
Главное отличие:
Критические сценарии:
Выбор между AbsorbPointer и IgnorePointer - это не вопрос вкуса, а вопрос архитектуры взаимодействия. Он сводится к простому решению: нужно ли изолировать проблемную зону от всей системы событий (AbsorbPointer), или же требуется точечно выключить один виджет, не трогая общий поток (IgnorePointer).
Понимание этой разницы - признак зрелости разработчика. Оно позволяет не костылять отключение через onPressed: null (что портит UX, меняя визуальную обратную связь) или сложные флаги в состояниях, а использовать декларативный и точный инструмент. Эти невидимые виджеты - фундамент для создания проработанного, устойчивого к нежелательным действиям пользовательского интерфейса, где каждое взаимодействие находится под вашим полным контролем.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Привет! Во Flutter, где каждое изменение состояния может запускать перестроение дерева виджетов, управление производительностью часто сводится к искусству скрытия. Не буквального, а архитектурного. Когда перед нами встает задача заранее подготовить сложный фрагмент интерфейса, но не показывать его немедленно, на помощь приходит неочевидный, но мощный виджет Offstage. В отличие от простого условного рендеринга, его работа гораздо тоньше и направлена на решение конкретных проблем с производительностью и состоянием.
Принцип работы:
Ключевое отличие Offstage от Visibility с флагом visible: false или условного оператора (if (condition) Widget()) - в его отношении к дереву. Когда вы оборачиваете виджет в Offstage(offstage: true), происходит следующее:
Этот принцип «жить, но не мешать» создает уникальные возможности.
Ключевые сценарии применения:
🔹 Пребилдинг ресурсоемких экранов и вкладок. Представьте навигацию с табами, где каждый таб - это сложный экран с сетями, графиками или списками. Используя Offstage для неактивных вкладок, вы избегаете:
🔹 Сложные, готовые к показу модальные окна или меню. Если диалог или боковое меню должно появляться мгновенно по жесту или кнопке, его можно заранее построить и спрятать в Offstage. В момент показа (offstage: false) произойдет только включение в лейаут и отрисовка - без инициализации контроллеров, загрузки ассетов или вычисления сложной логики. Это критично для создания ощущения отзывчивости интерфейса.
🔹 Управление жизненным циклом для оптимизации. Иногда виджет должен продолжать выполнять фоновую работу (например слушать поток данных или считать таймер), но не должен быть виден. Offstage позволяет сохранить эту логику, не отвлекая ресурсы на ненужный лейаут и отрисовку. Альтернатива - вынос логики в родительский виджет или сервис, что часто нарушает инкапсуляцию.
Технические нюансы и ограничения:
Пример - быстрое переключение вкладок:
Сохраняем состояние обеих вкладок, а не пересоздаем их.
Stack(
children: [
Offstage(
offstage: _currentTab != 0,
child: SettingsScreen(), // Живое состояние
),
Offstage(
offstage: _currentTab != 1,
child: ProfileScreen(), // Контроллеры активны
),
],
)
Offstage - это не просто скрытие виджета. Он сохраняет его состояние и ресурсы, предотвращая пересоздание. Используйте его для пребилдинга вкладок, сохранения анимаций и быстрых переходов. Так вы сделаете приложение отзывчивее без лишней нагрузки на процессор и память.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Создание адаптивного интерфейса во Flutter часто сводится к использованию MediaQuery и расчетам на основе размеров экрана. Но есть два менее известных, но исключительно мощных виджета, которые решают специфичные задачи адаптивности на уровне композиции, без сложной математики. FractionallySizedBox и FittedBox - это не просто обертки, а точные инструменты контроля пропорций и масштабирования.
FractionallySizedBox - размер в процентах:
Этот виджет задает размер дочернего элемента как долю от родителя. Например, кнопка на 80% ширины контейнера:
FractionallySizedBox(
widthFactor: 0.8,
child: ElevatedButton(...),
)
Главное условие: родитель должен иметь конкретный размер. Не будет работать в Column без Expanded, где ширина не ограничена.
FittedBox - умное масштабирование:
Когда контент не помещается, FittedBox масштабирует его, сохраняя пропорции. Типичный случай - крупный заголовок в маленькой карточке:
FittedBox(
child: Text('Заголовок', style: TextStyle(fontSize: 40)),
)
Это предотвращает OverflowError и автоматически подбирает размер.
В чем разница между FractionallySizedBox и FittedBox:
Когда что использовать:
Изучение адаптивности во Flutter не должно начинаться и заканчиваться на MediaQuery.of(context).size.width. Такие виджеты, как FractionallySizedBox и FittedBox, предлагают декларативный и композиционный подход к решению распространенных проблем верстки. Они смещают фокус с реактивного программирования («посчитай размер экрана и обнови») на декларативное описание отношений между элементами интерфейса («этот элемент занимает половину родителя, а его содержимое подстраивается под доступное пространство»).
Внедрение этих виджетов в повседневную практику сокращает количество кастомных расчетов, делает код чище и предсказуемее, а главное - создает по-настоящему гибкий интерфейс, который корректно ведет себя не только на разных размерах экрана, но и в сложных, вложенных layout-структурах. Это следующий уровень мастерства после освоения Row, Column и Flex.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1🔥1
При возникновении необходимости в установке нескольких, разных версий среды разработки Xcode на одной машине можно воспользоваться удобным приложением Xcodes, которое является удобным менеджером версий Xcode.
Зачем нужно:
Особенности данной утилиты:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1