My Authors
Read all threads
Сегодня вторник, по плану - разработка Android и iOS приложений в аутсорсе. Расскажу свою точку зрения о том какие приложения заказывают, как мы их делали когда-то и как сейчас, интересные случаи с разработки разных проектов
Чаще всего (80% от всех заказов) нам приходят за разработкой с нуля. Поддержка существующих приложений тоже бывает, но редко. Обычно получается что мы с нуля разрабатываем приложение, потом оно нам же на поддержку и остается.
Из-за того что разработка с нуля мы получаем возможность не копить легаси, проверять разные подходы на разных проектах, учиться новому очень быстро. Но в то же время на каждом проекте мы часто делаем схожие фичи. Авторизация, работа со списками и ряд других фичей есть почти везде
Технарей не радует перспектива постоянно делать похожие вещи. Поэтому всегда есть стремление переиспользовать то, что уже сделали. И мы не исключение - сначала на Android мы выделили набор библиотек, в которых были наши базовые классы, утилиты, вьюхи и прочие полезные штуки
Это был отдельный репозиторий с библиотеками, все библиотеки публиковались на приватный maven, разработка и публикация релизов велась техлидом. И в итоге техлид стал бутылочным горлышком для процесса - хотелки нового функционала прилетали к нему, но он не успевал это обрабатывать
Тем временем на iOS задумали аналогичный набор библиотек, но подключать решили в виде git submodule. Это позволяло всей команде одновременно развивать общие библиотеки, не требовалось ждать релизов - просто подтяни новые коммиты. Этот подход перетянули и на Android.
Такая конфигурация у нас продержалась пару лет. В начале все шло хорошо, но со временем в репозиториях общих библиотек становилось все больше хаоса - каждый проект запускался со своей веткой, мержи изменений в мастер происходили все реже, изменения становились более несовместимы
Начав работу с Kotlin Multiplatform мы сделали такой репозиторий и для mpp. Отказались от android репозитория общих библиотек - mpp версия полностью включала android либы. А ios репозиторий заметно похудел, часть ушла в mpp. Проблема хаоса стала наиболее заметна именно на mpp
В итоге мы решили опубликовать свои наработки в OpenSource (moko.icerock.dev), а вместе с этим и решить проблемы прошлых подходов. Мы вернулись к централизованным релизам каждой либы - больше нет разных веток под разные проекты...
Так же был налажен процесс внесения изменений каждым участником команды (нет завязки на техлида) - все обучились работе через mavenLocal, для чего мы даже codelabs сделали codelabs.kmp.icerock.dev/codelabs/moko-…. Теперь только на этапе публикации релиза в паблик нужен лид, и для ревью мержей.
В результате скорость внесения изменений в общие библиотеки снизилась (все же git submodule сильно проще менять), но не так критично, как было в самом начале. И централизованное версионирование дало прозрачность и улучшило обмен фиксами между проектами.
Отдельный плюс - само участие в OpenSource. Ребята имеют публичную активность, что хорошо и им и компании (любой клиент может помимо собеседования посмотреть и код). Желающие с нами работать могут сами потрогать заранее проект шаблон, на основе которого мы работаем
С темой переиспользования кода между проектами думаю хватит, дальше расскажу о подходах в разработке. Начну с Android. Начинали мы с подхода "в лоб" - без разбиения бизнеслогики и отображения, был набор классов типа NetworkHelper, DataBaseHelper, в которых была сервисная логика
Это продолжалось не долго, дальше мы увлеклись MVP подходом, начали задумываться где у нас бизнес-логика, где отображение, где сервисные вещи...Тогда же появились опасения как бы не уйти в overengineering. Регулярно возникали вопросы стоит ли добавлять Interactor'ы или нет
Всем известная статья о Clean Architecture в android только подлила масла в огонь, но в итоге обязательного наличия Interactor'а у нас так и не появилось. Если видно что в каком-то случае стоит это применить - применяем, а в остальных случаях (которых большинство) делаем попроще
Основная причина почему Interactor'ы у нас не прижились - чаще всего они выходили просто проксями между Presenter и Repository, ведь мобилки часто это просто тонкие клиенты, выводящие данные с сервера/бд. Тратить время на лишние прокси не хотелось
Дальше когда появились рекомендации гугла и AAC мы попробовали подход с ViewModel, при чем на тот момент не было нормальной связи LiveData с DataBinding (мы его активно использовали для биндинга данных) и первый проект с ViewModel у нас был с Rx и ObservableField.
Позже зарелизили поддержку LiveData в DataBinding и мы переехали на них, попутно улучшая их разными операторами по типу Rx. В тот момент уже мы начали работать на Kotlin, поэтому такие операторы выглядели очень схожи (extension методы)
Кстати про DataBinding - в половине собеседований сталкиваюсь с негативным фидбеком о DataBinding. с одной стороны из-за некорректного использования, из-за которого в xml оказывается куча кода и условий (у самих был такой кейс и это действительно ужасно)
С другой стороны DataBinding отталкивает своей неинформативностью в ошибках и отсутствием прямой интеграции с кодом (поиск, рефакторинг, подсветка кода). Все эти проблемы мы знаем, но для нас пользы было больше чем вреда, связь с view практически не требовала кода, что радовало
Но забегу вперед - сейчас у нас становится меньше databinding'а в пользу декларативного описания UI в коде...со временем придет и jetpack compose, тогда совсем про databinding можно будет не вспоминать
Так вот типовое Android приложение на момент перехода к работе на Kotlin Multiplatform у нас было такое - AAC ViewModel, LiveData, DataBinding, Dagger 2, RxJava 2, Retrofit, Room/Realm, Timber. В целом список совпадает с опытом почти каждого Android разработчика на собесе :)
Остановились на подходе MVVM мы потому что связь с View основана на реактивном подходе, при пересоздании вью не надо повторно выставлять ей нужное состояние, клея для связи vm и v требовалось мало, а ViewModel от гугла решал проблему смены конфигурации
Для одноразовых событий типа routeToMain, showToast мы сделали специальный класс EventsDispatcher, который внутри так же как LiveData учитывает изменения жизненного цикла, но позволяет работать с View по протоколу (напоминает MVP кстати). Подход SingleLiveData нам не зашел
В SingleLiveData надо плодить новые классы-события, хотя по сути нам нужны методы которые хочется вызвать в какой-то момент. И EventsDispatcher это и позволяет, пример можно посмотреть тут - github.com/icerockdev/mok…. Эта идея перешла с андроида и в mpp, работает и на iOS
Теперь все же про iOS - там подходов к разработке пробовали поменьше - изначально было MVC, с вытягиванием логики из ViewController чтоб не становился слишком жирным, примерно так и осталось. Но были пробы VIPER, MVVM
VIPER для нас оказался слишком массивным, приседаний для реализации фичи надо было сделать слишком много. MVVM в отдельных проектах прижился и живет. Реактивщина строится там на RxSwift. При чем интересно что Rx в iOS используется заметно слабее чем в Android (у нас в компании)
Желания сильно экспериментировать с архитектурой у iOS и не возникает, по моим наблюдениям это связано с тем что в Android мире на разрабов скинуто много особенностей системы, которые надо учитывать, а для iOS все попроще.
Типовое iOS приложение у нас до mpp было: swift, mvc, alamofire, rxswift, realm, storyboard + xib. Раньше часто замечал на собеседованиях что auto layout и Interface Builder не нравился кандидатам, но сейчас вроде такого уже нет. Наша команда активно использует это
Только в Storyboard не делаем верстку, оставляем там навигацию без вьюх, чтобы вьюхи загрузились из xib контроллера (на больших проектах лаги бесят). В последних проектах применяем Coordinator для навигации, от чего storyboard становится совсем ненужным.
Еще из интересного - на одном из iOS проектов реализовали разделение на модули в виде отдельных фреймворков - один фреймворк содержал весь objc код, другой бизнеслогику на swift, а приложение на swift цепляло оба фреймворка и работало с ними. Сделали так из-за времени компиляции
На тот момент был swift 3, время компиляции данного проекта на наших рабочих mac доходило до 10 минут clean, а инкрементальные 2-7 минут. Разбиение позволило нам снизить затраты на инкрементальные компиляции до 1-3 минут, на какое то время.
Вернусь ненадолго к android - в нем мы активно используем многомодульность, это позволяет упростить понимание границ фичей и позволяет юзать параллельные сборки, кеши модулей. В KMP это тоже используется, некоторые модули функционала переиспользуем и между проектами
И снова iOS - на проектах используем разделение конфигураций на dev/prod (выходит dev-debug, dev-release и т.д.). При чем сами конфиги держим в xcconfig файлах, что минимизирует дубликаты. Разные схемы запуска позволяют один и тот же проект собрать с разным окружением.
Сначала для этих целей пробовали отдельные таргеты - но там появляется необходимость проверять что исходники и ресурсы подключены к нужным таргетам. И общие для таргетов настройки дублировались. С конфигурациями вышло сильно удобнее
Пора уже про интересные кейсы накидать. Первое что вспоминается - на проекте с фото-фильтрами использовали GPUImage, сделали приложение-конструктор для клиента, чтобы настраивал свои версии фильтров комбинацией стандартных. И позже сделали чтобы Android и iOS читали json конфиг
То есть на сервере у нас лежал json c конфигурацией всех фильтров, которые можно использовать на мобилках, он различался для разных пользователей, качался в рантайме и обе платформы умели правильно его преобразовать в работу с GPUImage
На андроиде пришлось сделать fork GPUImage, так как были отличия от iOS версии в работе части фильтров. Ну а приложение-конструктор вообще сделали опенсорсно - github.com/icerockdev/gpu….
Другой интересный кейс - необходимость выполнять цифровую подпись запросов в iOS приложении. Сделали как надстройку для Alamofire. Такая задачка довольно редкая для нас. Схожее было SSL pining на обе платформы, тоже только раз столкнулись (при чем даже не банковское приложение)
Еще была интеграция с BT девайсом для цифровых подписей. С BT вообще любят интегрироваться - умный горшок для цветов, специальный пульт управления дейвайсом, устройство для считывания мозговых волн. Такими устройствами хотят управлять с мобилки, а мы реализуем это :)
Самая веселая BT интеграция была с тонометром. Было предоставлено устройство и огромная pdf спецификация с чистыми BT командами. Наш android разработчик копался в этой большой доке и успешно реализовал работу с тонометром. В остальных случаях присутствовал какой-либо готовый SDK
Накидаю еще несколько кейсов и хватит на сегодня...есть у нас приложение андроид-клавиатура. Реализация хитрого способа набора китайскими иероглифами (клиент разработал специальный алгоритм, согласно которому за 3-4 клика будет получен нужный иероглиф).
Был проект для android, где нужно было реализовать набор приложений, связанных между собой единым сервисом (тут была межпроцессная коммуникация с aidl интерфейсами), а сами приложения запускались на специальной tv-приставке. Архитектурно проект был интересен
Как-то помогали одному hr приложению, с функционалом определения номера телефона на android, вернуться в play market - когда google решил ограничить доступ к READ_CALL_LOG приложение было удалено из стора. Мы побадались с гуглом в разных форматах, но в итоге так и не прошли :(
При чем ответ гугла был в формате "функционал определения номера телефона не является необходимым для вашего приложения", хотя все приложение это реально только определение номера. Ну и фоновая синхронизация базы данных с номерами кандидатов. В чем логика такого ревью - непонятно
Missing some Tweet in this thread? You can try to force a refresh.

Enjoying this thread?

Keep Current with Мобильный разработчик

Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Follow Us on Twitter!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just three indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3.00/month or $30.00/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!