Привет! Меня зовут Сергей Арсёнов, я руковожу мобильной разработкой в компании r_keeper. Хочу рассказать, как мы обновляли мобильное b2b-приложение для официантов и почему выбрали для него не совсем классический стек — Kotlin Multiplatform Mobile + UI на Flutter. 

На чем писать?

Наше мобильное приложение используют официанты в ресторанах, где установлена система автоматизации r_keeper: оформляют через него заказы, добавляют и удаляют блюда, принимают оплату и т. д. Когда-то давно оно было написано на Java + Objective-C + WebView и заметно устарело: функциональность для iOS и Android полностью дублировалась, обе версии выглядели абсолютно одинаково, нативной верстки не было. Приложение с трудом поддавалось улучшениям, и в конце концов мы решили переписать его с нуля. Вопрос — на чем?

Мы точно понимали, что хотим, как минимум, уйти от WebView и неактуального стека. Плюс выбрать такой набор технологий, который позволит максимально быстро повторить текущий функционал приложения и существенно сократить Time2Market. Рассуждали так.

  1. Нужна технология, которая позволит не писать одну и ту же логику несколько раз под разные платформы (тем более для b2b-приложения, где UI и функционал для всех ОС идентичен). Получается, чистый натив не оптимален — нужна кроссплатформа.

  2. Это должна быть кроссплатформа, которая позволит сделать приложение для iOS, Android, а в перспективе и под web / desktop. К тому же нужно уметь поддерживать работу с платформой и железом, поскольку такие задачи могут возникнуть — PWA по этой причине выбыл. Выбыл и Xamarin — он не поддерживает web и вообще не очень быстр. Список сузился до нескольких вариантов: Flutter, React Native, KMM + UI на чем-нибудь (например, NativeUI) и Cordova.

  3. У кроссплатформы должен быть низкий порог входа для Android-разработчиков — это тот ресурс, которым мы располагали. Javascript они не знают — из-за этого выбыли React Native и Cordova. 

Какие плюсы и минусы?

В результате до финиша дошли варианты Flutter и KMM + NativeUI с какими-то комбинациями. Все — со своими достоинствами и недостатками.

  1. Во Flutter используется незнакомый язык Dart (правда, сильно похожий по синтаксису на известный каждому Android-разработчику Java) и декларативная верстка. Для Android-платформы декларативный Jetpack Compose еще не стал нормой, так что был риск, что этот вариант построения интерфейса снизит темпы разработки (как минимум на первоначальном этапе). Не было уверенности, что неопытный в этой технологии разработчик сможет качественно выстроить архитектуру и написать бизнес-логику. Мы также опасались, что кроссплатформа не позволит полностью реализовать все специфические особенности каждой платформы, вроде работы с push-уведомлениями или железом. Были сомнения и в достаточной производительности Flutter на слабых устройствах (такие нередко встречаются у корпоративных клиентов). Притом мы понимали, что у технологии есть свои преимущества: относительная зрелость Flutter SDK, единый язык и код для всех платформ и вариантов. К тому же поддерживал энтузиазм разработчиков, которым хотелось «пощупать» новую технологию.

  2. У варианта KMM + Native UI — много достоинств: это знакомый всем Kotlin, знакомый всем Android UI, плюс возможность вынести любой специфичный функционал в нативную часть. Минусом мы посчитали то, что UI пришлось бы писать на Swift и делать двойную работу по слою представления (а работать с Xcode не хотелось никому) — это грозило увеличением сроков разработки. Кроме того, технология KMM еще недостаточно зрелая — могли возникнуть проблемы.

  3. Можно было попробовать гибрид Flutter + KMM, но тут тоже были потенциальные «грабли». Мы не знали, как смогут общаться KMM и Flutter и насколько сложно будет собрать проект из таких непохожих частей. Правда, такая связка позволила бы не писать сложную логику на Dart и вообще делать UI только один раз, а все сложные вещи привычно написать на Kotlin.

Три версии на тест

Идеального варианта не было, поэтому мы решили пойти методом проб и ошибок. Сделали три версии тестового приложения с идентичным функционалом, чтобы оценить производительность каждого решения, сложность и время разработки, незамеченные пока ограничения технологий. Само приложение было несложным — оно грузило из небыстрой REST API список рецептов с описаниями и картинками и отображало его с разбивкой по категориям. Подборки были длинными (по несколько тысяч рецептов), а картинки — тяжелыми. 

Версию № 1 написали на чистом нативном Android (Clean Architecture, Android Jetpack, MVVM, Coroutines, Koin), № 2 — на KMM + Native UI, № 3 — на KMM + Flutter. Делать отдельное приложение на чистом Flutter не стали, потому что версия № 3 позволяла оценить и этот вариант.

Время и сложность создания нативного приложения (версия № 1) мы взяли за эталон для сравнения. Трудностей с его разработкой не возникло, создание с нуля заняло примерно одну неделю. Приложение, в соответствии с концепцией чистой архитектуры, было разбито на три слоя: представления, бизнес-логики и слоя данных. 

Для переписывания приложения на KMM (версия № 2) было необходимо следующее.

  1. Перенести слои Data и Domain в кроссплатформенную часть
    Для слоя Data пришлось переписать базу данных со стандартного Jetpack’овского Room на кроссплатформенный SQLDelight. Последний требует, чтобы таблицы и методы для общения с ними были описаны на варианте чистого SQL, путем создания .sq-файлов — при сборке именно по ним генерируются методы для обращения с базой данных. Готовых инструментов для миграции из Room в SQLDelight мы не нашли, так что пришлось вручную переносить сгенеренные таблицы из Room и писать SQL-запросы для методов — это заняло пару дней.

    Еще мы переписали сетевую часть с Retrofit на Ktor (сериализацию делали через kotlinx.serialization). Тут особых сложностей не возникло: для логики интерфейс общения с бэкендом остался прежним, была изменена лишь имплементация. Вообще для большей гибкости на Ktor можно использовать не только кроссплатформенные, но и нативные движки, например, OkHttp, но для наших целей хватило дефолтного.

    Слой Domain, естественно, перенесся в KMM без каких-либо изменений.

  2. Поменять способ общения между логикой и представлением на подходящий для кроссплатформы
    Для общения с логикой KMM-части был описан публичный интерфейс с методами, которые будут видны в слое представления, а сама KMM-часть реализована в виде некой библиотеки, которая имплементирует этот интерфейс. 

  3. Изменить слой представления для Android-версии, поменяв способ общения с логикой
    Потребовалось лишь переделать ViewModels для общения с логикой через изменившиеся интерфейсы

  4. Написать UI-часть под iOS
    KMM собирается как обычный Framework-пакет для iOS. Особых сложностей с этим не возникло — надо было лишь подключить эту библиотеку и написать стандартный UI на Swift, который вызывает из нее методы. 

В целом переделка проекта заняла около двух недель (не считая написания iOS UI), в основном оно ушло на знакомство с новыми библиотеками. Подводных камней на этом этапе мы не увидели.

Третьей и самой интересной стала версия № 3 на Flutter + KMM. Часть KMM с логикой бизнес-и дата-слоев без каких-либо изменений была перенесена из версии № 2 — нам потребовалось лишь написать UI на Flutter. 

Серьезные опасения насчет падения производительности при передаче больших массивов объектов между UI и KMM не оправдались — версия № 3 показала вполне приличную производительность и плавность даже на слабых устройствах с ARMv7 и старых iPhone. Никаких особых сложностей в освоении языка Dart у Android-разработчиков не возникло, а создать работоспособный UI для тестового приложения удалось за считанные дни. 

С другой стороны, стало понятно, что создание грамотной архитектуры для приложения на чистом Flutter может стать проблемой и затормозить разработку. 

Что мы поняли?

В итоге тестирования, освоения новых библиотек и работы с плагином KMM мы сделали вывод, что сложность версии № 2 примерно соответствует обычной классической платформенной (если не учитывать время, потраченное на освоение новых библиотек и написание UI-части для iOS). КММ помог четче разделить приложение по слоям и избежать их смешения. 

Мы пришли к интересной мысли, что можно даже сразу делать нативные Android-приложения на КММ, если планируется версия под iOS. Это практически не удлиняет разработку под Android, но зато экономит немало усилий при создании и тестировании iOS-версии — достаточно лишь написать UI-часть.

В целом тестирование убедило, что самым эффективным и быстрым в реализации решением для нас станет разработка приложения на связке KMM + Flutter. А если что-то пойдет не так, мы всегда сможем вернуться к резервному варианту Native UI + KMM — переделка из схемы Flutter + KMM затронет лишь слой представления. 

Пара слов о выбранных технологиях

Для тех, кто не знаком с выбранными нами технологиями, сделаю небольшое пояснение:

  • В качестве основы для слоя представления используется Flutter — SDK для создания приложений под iOS, Android и web (плюс desktop в планах). Это уже достаточно зрелая технология (релиз первой версии состоялся в 2015 году), с накопленной базой готовых решений и вопросами / ответами по ней. Впрочем, родная документация на сайте тоже очень подробная.

  • В качестве языка программирования для Flutter используется Dart. Он компилируется в бинарный код, что позволяет добиться высокой скорости выполнения операций, сравнимой с результатами Objective-C, Swift, Java или Kotlin. Dart не использует нативные компоненты платформ ни в каком виде: подобно игровым движкам он отрисовывает все графические элементы самостоятельно — с помощью собственного движка Google Skia. Все элементы этого интерфейса описываются декларативно, подобно новомодным Swift UI и Jetpack Compose. 

  • В качестве основы для бизнес-логики и, что немаловажно, дата-слоя используется Kotlin Muliplatform Mobile (KMM). Это SDK, созданный для упрощенной разработки кроссплатформенных приложений. Он построен на Kotlin Multiplatform (KM) — технологии, которая позволяет запускать на множестве платформ (Android, iOS, Linux, Windows, MacOS, web и т. д.) один и тот же код, написанный на Kotlin. При добавлении к KM интеграции с мобильными платформами получается KMM. Есть удобный репозиторий, где собраны основные библиотеки для KMM. Большинство компонентов KMM (за исключением интеграции с IDE и плагина под Android Studio) находятся в статусе stable или beta, так что риск использования данной технологии минимален, а ее API уже не будет меняться с новыми релизами. 

Если есть вопросы, буду рад ответить. А о реальном внедрении расскажу в следующей статье.

Комментарии (36)


  1. dimsog
    16.09.2021 21:41

    rkeeper просто тихий ужас для разработчика. Извините ребят, просто наболело. Делал интеграцию сайта ресторана с Rkeeper (+ ваша же CRM для бонусов) Не знаю как сейчас, но полгода назад не было метода, с помощью которого можно было получить количество бонусов у клиента из CRM, список пользователей, проверить, есть ли такой пользователь и так далее.

    Мне кажется там просто огромное легаси. У меня была задача сделать личный кабинет, я не придумал ничего лучше, чем просто выдернуть из базы данных данные и по крону эти данные в специальном файле обновлять.

    Худшее API. Поддержки 0, им задаешь вопрос, в ответ - обратитесь к вашему дилеру. Да дилер сам не знает. Он не является разработчиком...

    Еще раз, не принимайте близко к сердцу, реально накипело.

    Если не верите, смотрите:

    1) https://docs.rkeeper.ru/delivery/arhiv/api-webdelivery/opisanie-api/crm-api#CRMAPI-%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D0%B8%D0%BE%D0%BA%D0%BB%D0%B8%D0%B5%D0%BD%D1%82%D0%B5(GET)

    Метод получения информации о клиенте, окей, а как мне получить сам ID клиента из существующей базы? А никак.

    2) Как узнать бонусы? Никак.

    Может быть я не там смотрю, у вас как раз был переезд документации. Может быть интеграторы не знают, все может быть. Я не нашел. Но не сдался.


    1. Mox
      16.09.2021 22:47
      -2

      Это все относится к самому r_keeper, тут речь про приложение для официантов.


  1. alphamikle
    16.09.2021 22:24
    +1

    Можете ли поделиться тестовыми проектами (1. 2. 3)? Особенно интересен 3.


    1. SergeiArsyonov Автор
      22.09.2021 15:06

      С удовольствием бы, но в проектах используется проприетарный backend-API, руководство, к сожалению, не разрешило выкладывать код в открытый доступ
      Извините за поздний ответ, надеялся договориться


  1. Mox
    17.09.2021 01:51

    А почему не рассматривали React Native?


    1. ApeCoder
      17.09.2021 09:03

      . Javascript они не знают — из-за этого выбыли React Native и Cordova. 


      1. SergeiArsyonov Автор
        17.09.2021 11:15

        Да, порог освоения был выше. Плюс, менеджмент хотел, в перспективе, поддержку Linux


  1. dellby
    17.09.2021 12:04

    Когда вы решите сделать web версию приложения, по какому пути вы пойдёте?


    1. SergeiArsyonov Автор
      17.09.2021 14:52

      А, собственно, в чем разница? KMM работает под WEB, даже недавно вышел драйвер под JS для БД SQLDelight. Flutter также в этом году в марте дошел до стадии релиза для Web. Схема та же, аналогична приведенной в статье.

      Сложности могут быть, разве что, в том, что не все плагины под флаттер поддерживают веб. Но, конечно, надо пробовать этот вариант и тестить, там могут оказаться невидимые пока грабли


  1. sshustoff
    19.09.2021 22:40

    А как данные передаются между flutter и kotlin кодом? Имхо самый интересный аспект, как получить данные в UI с этим подходом и как вызвать методы kotlin слоя.


    1. SergeiArsyonov Автор
      20.09.2021 11:54

      Вообще, во флаттере существует вполне удобный механизм для работы с платформой https://flutter.dev/docs/development/platform-integration/platform-channels.
      Можно и вызывать методы другого слоя напрямую, и подписываться на потоки, слушая изменения. Сущности через этот механизм platform-channels передаются через сериализацию\десериализацию в json.

      во второй части статьи про это будет подробнее рассказано


      1. sshustoff
        20.09.2021 13:15

        Если оно идёт через сериализацию, то не приходится ли писать один и тот же класс 2 раза в котлине и дарте? И не будет потом проблем с поддержкой 2х вариантов класса? Есть какая-то валидация консистентности этих дубликатов во время компиляции?


        1. SergeiArsyonov Автор
          20.09.2021 13:59

          Именно писать 2 раза не приходится, есть же готовые конвертеры из JSON вроде https://javiercbk.github.io/json_to_dart/. То есть мы писали в kotlin-части сущности в виде data-классов, конвертили в JSON и потом его же в Dart.

          Ну проблемы при общении между слоями всегда могут быть, разве общение с бэкендом через API и передача сущностей в обе стороны чем-то принципиально отличаются от общения flutter с kotlin? Там тоже могут быть проблемы с разными вариантами одного класса. На практике, в реальном проекте в этой части мы серьезных проблем не ловили
          Валидации на этапе компиляции нет, как прикрутить тут тесты не придумали


          1. sshustoff
            20.09.2021 14:12

            Бэк обычно покрыт тестами и задокументирован, плюс любые изменения в апи делаются максимально осторожно без отламывания старой версии эндпоинта или с обратной совместимостью, а тут все это внутри клиента.

            Кажется что в большом проекте такой подход очень даже может выстрелить ногу


            1. SergeiArsyonov Автор
              20.09.2021 14:21
              +1

              ну никто не мешает покрывать тестами обе части и делать изменения в контракте между флаттером и котлином максимально осторожно. Собственно, так у нас и происходит на практике

              Но хотелось бы в идеале как-то автоматизировать проверку консистентности на этапе компиляции, тут целиком согласен


  1. avdosev
    20.09.2021 16:00
    +1

    Можно поподробнее, чем плох вариант Flutter и только Dart? использование Котлин мультиплатформ, на мой взгляд, это излишнее усложнение, которое имеет смысл только при наличии кодовой базы на котлин


    1. SergeiArsyonov Автор
      20.09.2021 16:15

      Извините, что повторяюсь, но еще раз приведу консёрны из статьи:

      "Не было уверенности, что неопытный в этой технологии разработчик сможет качественно выстроить архитектуру и написать бизнес-логику. Мы также опасались, что кроссплатформа не позволит полностью реализовать все специфические особенности каждой платформы, вроде работы с push-уведомлениями или железом. Были сомнения и в достаточной производительности Flutter на слабых устройствах (такие нередко встречаются у корпоративных клиентов). "

      Если резюмировать - то разработчики отлично знали котлин и не знали дарт. Плюс хотели иметь резервный вариант по-быстрому написать UI на нативке, если вдруг flutter-UI будет медленным или неудобным.

      Сейчас, по прошествии полугода, выбор пал бы на чистый флаттер, полагаю


      1. avdosev
        20.09.2021 16:27

        Спасибо за ответ. В целом тогда - да, выбор Котлин мультиплатформ кажется логичным и оправданным


  1. dagot32167
    21.09.2021 17:35

    На мой взгляд, тут больше вопрос не "на чем", а "зачем":
    - зачем с нуля что то переписывать?
    - зачем был выбран flatter (на Dart) вместо React Native (на javascript) если команда не знала ни тот ни другой язык?
    - зачем вам вообще было нужно нативное приложение (какие преимущества вы ожидали в отличии от веб версии)?
    - если разработка хотела на kotlin и знала его, то почему не был выбран https://github.com/JetBrains/kotlin-wrappers/tree/master/kotlin-react?
    - зачем вам в вашем приложении в котором выводится картинка и информация, нужно быстродействие нативного приложения?
    - я верно понимаю, что вы в приложении объединили все три слоя на которые разделили свое приложение?
    - не понятен результат выбора технологии: вы окончательно перешли на выбранный технологический стек и если да то сколько времени вам на это потребовалось и сколько разработчиков в этом участвовали?
    - ну и самый важный вопрос, вы указывали что есть желание сократить ttm, какой он был средний и какой он стал после перехода на новый стек?


    1. Bringoff
      22.09.2021 14:16
      +2

      Мне кажется, вы невнимательно читали статью.

      зачем с нуля что то переписывать?

      Если код в старом приложении дурно пахнущий, то его отрефакторить и переписать заново — задачи одного уровня времязатрат. Тут же их 2 нативных, так что рефакторить можно и дольше. Плюс в кроссплатформенное приложение потом быстрее изменения вносить, потому что это надо делать один раз.

      зачем был выбран flatter (на Dart) вместо React Native (на javascript) если команда не знала ни тот ни другой язык?

      Dart максимально похож на Java, который Android-разработчики точно знали. Можно буквально сказать: "private/public/protected теперь нет, используйте _ для обозначения приватности. Все, можете приступать к работе". У меня с Dart так и было. JS же — это целый свой мир.

      зачем вам вообще было нужно нативное приложение (какие преимущества вы ожидали в отличии от веб версии)?

      Нормальный доступ к нативным функциям устройства? Не знаю, допустим, считывать NFC-чипы официантам надо будет.

      kotlin-react

      Штука намного менее мейнстримная, чем даже Flutter.

      зачем вам в вашем приложении в котором выводится картинка и информация, нужно быстродействие нативного приложения?

      Кажется, вы путаете тестовое приложение для сравнения трех подходов с реальным приложением, которое потом делалось на выбранной технологии.


      1. SergeiArsyonov Автор
        22.09.2021 14:50

        Спасибо, все верно, сам бы не ответил лучше


      1. dagot32167
        22.09.2021 16:11

        сорь, но достаточно внимательно.
        мой опыт показывает, что зачастую переписать и отрефакторить - это разные уровни задачи по времезатратам и бюджету. Если у вас иной опыт, то я завидую вашему опыту.
        я веб разраб и для меня не очевидно какие именно нативные функции необходимы для официанта в приложении, быстродействие ему не нужно т.к. бизнес логики кроме отправить запрос в rest api ему тоже не нужно, на мой взгляд. Даже nfc функционал зачем ему? (@SergeiArsyonov тут наверное к тебе вопрос)
        по поводу того что js (ts) это другой мир - соглашусь. но с вашего позволения обновлю ваши знания о js и теперь там есть приватные методы и свойства (https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Classes/Private_class_fields)


        1. SergeiArsyonov Автор
          22.09.2021 16:48

          • какие именно нативные функции необходимы для официанта в приложении, быстродействие ему не нужно т.к. бизнес логики кроме отправить запрос в rest api ему тоже не нужно, на мой взгляд. Даже nfc функционал зачем ему?

          Ну оплата заказа карточками (в виде взаимодействия с драйверами терминалов), сканирование QR-кодов камерами, понимать состояние коннекта с интернетом и т.д.


          1. dagot32167
            22.09.2021 17:10

            хм. я думал, что мобильное приложение для официанта не имеет прямой доступ к кассе, а касса - это отдельное приложение и/или устройство которое получает данные с сервера транзакций


            1. SergeiArsyonov Автор
              22.09.2021 17:19

              Ну формально да, оплата это мобильная касса, не совсем приложение официанта. Но у r_keeper эти два приложения объединены в одно: официант набивает заказы в приложение, оно передает все на сервер\стационарную кассу (на которой тоже можно сделать оплату), и это же приложение офицанта может принять оплату


              1. dagot32167
                22.09.2021 17:28

                и оплату мобильный официант принимает qr кодом?
                я верно понимаю, что ради сканирования qr были объединены 2 функционально разных приложения?
                сорь, реально интересно т.к. я всегда думал, что касса как отдельный терминал который выполняет узкоспециализированную задачу и более никто ее не выполняет в целях безопасности


                1. SergeiArsyonov Автор
                  22.09.2021 17:43

                  Ну почему обязательно QR-кодом? И обычной банковской картой тоже через выносной терминал. А код может использоваться для скидок, програм лояльности и т.д.
                  Само приложение синхронизируется с кассовым сервером, поэтому проблем с платежами нет. В любом случае, безопасность при использовании традиционного бумажного блокнотика и оплате наличными или карточкой ничуть не выше.

                  В случае использования приложения официанта ресторатор имеет гораздо больший централизованный контроль за происходящим, в этом, собственно, основной смысл


                  1. dagot32167
                    22.09.2021 17:46

                    оке. пасиб


    1. SergeiArsyonov Автор
      22.09.2021 15:04

      Уважаемый Bringoff уже абсолютно верно ответил за меня на основные вопросы. Немного дополню его ответ:

      • зачем с нуля что то переписывать?

      Если вы не сталкивались в своей жизни со старым дурнопахнущим кодом, который гораздо дешевле переписать с нуля, чем поддерживать, то я вам сильно завидую.

      В целом, по грубой оценке, переписывание с нуля сэкономило 50% усилий (человеко-часов) и сильно повысило удовлетворенность разработчиков от работы, что тоже важно

      • я верно понимаю, что вы в приложении объединили все три слоя на которые разделили свое приложение?

      Не очень понял вопрос. В приложении 3 классических слоя чистой архитектуры. Слой представления сделан на флаттер, остальные два - на КММ, все слои объединены в одном приложении

      • не понятен результат выбора технологии: вы окончательно перешли на выбранный технологический стек и если да то сколько времени вам на это потребовалось и сколько разработчиков в этом участвовали?

      Да, в рамках этой части статьи описывался процесс выбора. В результате этого процесса мы перешли на выбранный стек и сделали рабочее приложение, о чем скоро будет рассказано во второй части

      • ну и самый важный вопрос, вы указывали что есть желание сократить ttm, какой он был средний и какой он стал после перехода на новый стек?

      Не замеряли. Но за полгода был почти полностью повторен функционал старого приложения + внедрены фичи, которые висели в бэклоге пару лет. ttm совершенно явно значительно сократился


      1. dagot32167
        22.09.2021 16:00

        Признаюсь честно, последние 3 года, где я работал - начинал именно с разгребания легаси и дурно пахнущий кода, внедрение линтеров, код ревью, тестирования, типизации, ci/cd и отсутствия документации.
        В связи с этим, всегда интересен опыт компании, которая перешла с одного стека на другой.
        Потому и спрашиваю, ведь переход на новый стек - это всегда вопрос компромиссов и дополнительных ресурсов. Когда говорят что "мы хотим улучшить ttm" то всегда встает вопрос "улучшили?" и метрика в виде "явно значительно сократился" немного расплывчата и не говорит вообще ни о чем, ведь мы должны продать бизнесу идею перехода на новый стек, а не "просто потому что". Из этого и спрашиваю, что переход на другой стек (который в себя вбирает обучение своих сотрудников языку и фреймворку, построению верного релизного цикла и разработки, переделка с нуля всех компонентов вью, переделка с нуля всей бизнес логики, обмазывание всего тестами, возможно описание новых интеграционных и e2e тестов, а самое главное, что стек в среднесрочной перспективе может вообще не подойти) действительно ли дороже трансформации текущего кода в котором уже есть тесты и который разрабы знают как свои 5 пальцев (рефакторинг и разделение вью и бизнес логики, что бы подготовить базу к возможной смене одного из слоев архитектуры на любую другую технологию)?
        Особенно интересено, для меня, в связи с частичным уходом компании Wrike от Dart и перехода на Typescript их вью части. И да, я понимаю, что у них веб приложение, а у вас нативка. От того более интересно, с какими проблемами вы встретились как со стороны языка, так и со стороны фреймворка


        1. Bringoff
          22.09.2021 16:09

          Особенно интересено, для меня, в связи с частичным уходом компании Wrike от Dart и перехода на Typescript их вью части

          Позволю себе продолжить вмешиваться в диалог ???? Wrike ушли в основном потому, что AngularDart не развивался, а Flutter for Web ещё не готов к боевому использованию, да и когда будет готов, это не совсем общего назначения фреймворк. Flutter же для мобильных устройств развивается довольно быстро.


          1. dagot32167
            22.09.2021 16:13

            ага, это больше со ссылкой на вот этот коммент https://habr.com/ru/company/r_k/blog/578386/#comment_23493888


        1. SergeiArsyonov Автор
          22.09.2021 17:05

          А кто сказал, что в старом коде это все было? )) Начиная от тестов и кончая разделением.
          К сожалению, зачастую тот код, в котором разработчики нарыли ходов и хорошо ориентируются, не очень-то подходит для рефакторинга.

          Продать идею было несложно. Был проведен аудит, менеджменту сказали - чтобы отрефакторить текущее приложение до состояния вменяемости нужен год, чтобы написать то же самое с нуля нужно полгода. Но отрефакторенное все равно будет хуже, ибо стек совсем уже плохо пахнет. Плюс разработчиков новых будет сложно найти, никому не хочется ковыряться в древнем стеке с задепрекейченным кодом. Плюс кроссплатформа даст большую выгоду в плане минимизации усилий.
          Менеджмент все равно боялся и говорил что-то похожее "стек в среднесрочной перспективе может вообще не подойти" . Для этого и сделали тестовые приложения на всех исследуемых технологиях и проверили, как оно.

          А вот как оно оказалось в реальности, когда с нуля написали на выбранном стеке уже рабочее приложение и какие выводы сделали - про это во второй части статьи. Планируем выложить ее в течении пары недель


  1. Gargoni
    10.10.2021 13:02

    Привет конкурентам))).

    Вариант нативный UI и БЛ на плюсах не рассматривали?


    1. SergeiArsyonov Автор
      11.10.2021 07:55

      Приветствую )
      Не рассматривали, в нашем случае у этого варианта множество минусов и ни одного явного плюса:

      • Нужно кормить 3х условных программистов (android, ios и ++) вместо одного универсального андроид-флаттериста

      • нужно 2 раза писать UI на нативке для каждой платформы (а то и 3, для десктопа)

      • имхо, kotlin как язык, все-таки, гораздо современнее плюсов


      1. Gargoni
        11.10.2021 14:43

        Но вы тогда жертвуете нативными контролами и немного производительностью.