• TAGES
  • Блог
  • Переходим на Flutter: за и против

Переходим на Flutter: за и против

Меня зовут Данил и уже более пяти лет я занимаюсь мобильной разработкой, три из которых — на Flutter. Последние несколько лет я разрабатываю продукты для энтерпрайза в TAGES, и за это время у меня успел накопиться определенный опыт, которым я бы хотел поделиться с вами в сегодняшней статье. Я расскажу, что нужно знать опытному мобильному разработчику для перехода на Flutter, с какими особенностями можно столкнуться и стоит ли вообще переходить на него.

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

Что такое Flutter?

Flutter — это открытый набор инструментов для разработки кроссплатформенного программного обеспечения, в котором используется язык Dart. Если вы знакомы с Kotlin, Swift или Java, то Dart вам может показаться до боли знакомым.

Отличительные особенности:

  • Проект с открытым исходным кодом и большим активным сообществом.
  • Собственный движок рендеринга, кроссплатформенность и единый язык разработки.
  • Безопасное взаимодействие с нативным кодом по каналу платформы.
  • Высокая производительность по отношению к другим кроссплатформенным инструментам.

Достоинства

1. Dart — главная причина, по которой разработчики любят Flutter

Язык Dart создавался командой Google в качестве альтернативы JavaScript. Начать писать на нем можно довольно быстро, даже если у вас нет особого опыта в программировании на одном из перечисленных ранее языков. Для наибольшего эффекта рекомендую приступать к изучению языка с небольшой экскурсии.

К слову, сам язык «из коробки» многопоточный (с некоторыми ограничениями), который предоставляет механизмы Event Loop, Isolates, помогающие работать с асинхронными и параллельными операциями. Внешне это может выглядеть почти так же, как корутины в Kotlin или Concurrency в Swift. Но только внешне. Ключевое отличие находится в технической составляющей. Dart выполняет одну операцию за раз, одну за другой, что означает, что пока выполняется одна операция, ее нельзя прервать никаким другим кодом Dart.

Для наглядности сравним синтаксис:

Dart

class Language {
  const Language(this.name);

  final String name;

  Future<void> learn(Duration duration) {
    return Future<void>.delayed(
      duration, () => print('Well done! $name is learned!'),
    );
  }
}

Future<void> main() async {
  final dart = Language('Dart');
  await dart.learn(Duration(seconds: 2));
}

Kotlin

import kotlinx.coroutines.delay

class Language(private val name: String) {
    suspend fun learn(duration: Long) {
        delay(duration)
        print("Well done! $name is learned!")
    }
}

suspend fun main() {
    val kotlin = Language("Kotlin")
    kotlin.learn(2000L)
}

Swift

import Foundation

class Language {
  let name: String

  init(name: String) {
    self.name = name
  }

  func learn(interval: TimeInterval) async throws -> Void {
    try await Task.sleep(nanoseconds: UInt64(interval * 1_000_000_000))
    print("Well done! \(name) is learned!")
  }
}

Task.init {
  let swift = Language(name: "Swift")
  try await swift.learn(interval: 2.0)
}

Как можно заметить, Dart имеет хорошую визуальную эстетичность кода, но, помимо этого, он еще и поддерживает:

2. Простая и гибкая верстка

Процесс построения пользовательского интерфейса декларативный и состоит из виджетов — в своем роде компонентов, которые могут располагаться на экране. Если сравнивать с привычными инструментами, то это как Jetpack Compose для Android или SwiftUI для iOS.

По умолчанию, для отрисовки виджетов используется Skia, но можно переключиться на Impeller (на данный момент он доступен для предварительного просмотра). Они не требовательны к версии и самой платформе, что позволяет воплощать многие задумки. Физика и сами виджеты стараются быть максимально приближенными к нативным компонентам, повторяя гайдлайны той или иной системы, что открывает дополнительную возможность максимально их кастомизировать под свои цели и задачи.

Ознакомиться с компоновкой пользовательского интерфейса можно в блоке «Введение в виджеты» из официальной документации.

3. Быстрая адаптация к изменениям ОС

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

Рассмотрим пример с поддержкой дисплеев ProMotion, обладающих динамической частотой кадров:

Для любого инструмента кроссплатформенной разработки сейчас эта тема является серьезной задачей, поскольку для внесения изменений в ядро движка необходимо:

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

С появлением iPhone 13 Pro и iPhone 13 Pro Max, оснащенных дисплеем ProMotion, разработчикам стало интересно, как поведут себя приложения написанные на Flutter. Чуда не произошло, и в первый же день продаж в репозитории была заведена проблема, а также появлялись первые наброски решения, которое бы позволило добавить такую поддержку.

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

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

4. Пакеты от сторонних разработчиков

На сегодняшний день сообщество Flutter активно растет и развивается, что, к примеру, хорошо видно в исследовании Statista. Этому способствуют и разработчики, прилагающие усилия, чтобы оставить в нем свой вклад. Не меньше развитию сообщества способствует и программа Flutter Favorite, задающая планку качества, на которую стоит ориентироваться как начинающим, так и опытным разработчикам при выборе внешней зависимости в проект.

Недостатки

У любого инструмента рано или поздно появляются слабые места. Рассмотрим основные.

1. Кодогенерация

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

В Dart кодогенерация устроена таким образом, что ее приходится перезапускать каждый раз, чтобы увидеть новые изменения. В больших проектах это особенно неудобно, поскольку такая генерация кода (например, в CI/CD) отнимает у разработчиков немало времени. Да, можно задействовать слушателя. Но он подходит не для всех случаев, поскольку реагирует на любые изменения в коде, что приводит к частым обращениям к накопителю и, в свою очередь, подвисаниям.

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

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

Для сравнения, в Kotlin есть довольно быстрый фоновый kapt и его более современная замена KSP. В отличие от build_runner в Dart, с ними приятно работать.

2. Имитация пользовательского взаимодействия

Flutter можно отметить за отличную поддержку и оптимизацию только под одну платформу, под которую он затачивался в первую очередь – Android. Если нативному iOS-разработчику дать «пощупать» приложение, написанное на Flutter, то он не получит тот самый первоклассный пользовательский опыт от его использования, поскольку физика и анимации лишь симулируют то, к чему привык пользователь.

Разработчикам все же удалось бесшовно повторить компоненты и физику в стиле Material Design. Исключением можно назвать лишь Human Interface Guidelines, в котором физика и сами компоненты при взаимодействии порой ощущаются искусственными, словно между пальцем и кнопкой существует еще одна прослойка, портящая все ощущения от использования. Причем проблема даже не в самих компонентах, а в том, как Flutter в целом работает на этой платформе.

3. Уровень производительности, платформы и архитектуры

Если говорить о веб-приложениях, то разработка на Flutter Web будет требовать особый и настолько строгий подход к оптимизации, что заставит переосмыслить ее целесообразность. Хочется предостеречь от использования этой платформы для разработки прогрессивных веб-приложений (PWA) и одностраничных приложений (SPA), поскольку их производительность может значительно уступать приложениям, созданным при помощи других инструментов. В свою очередь это негативно сложится на общем впечатлении и пользователя, и разработчика.

Помимо этого, Flutter не поддерживает сборку проекта под архитектуру x86 для Android. Считается, что количество таких устройств на рынке не так велико, и с каждым днем их становится все меньше, а изменения, которые необходимо внести для реализации, потребуют значительного объема работ в компиляторе Dart.

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

Стоит отметить, что написать приложение под watchOS не получится, однако можно встроить собственное нативное расширение в текущее приложение, сделанное на Flutter.

4. Анализатор оставляет желать лучшего

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

«Из коробки» нам доступен analyzer, и его можно настраивать различными правилами, однако, они ограничены определенными типами предупреждений/ошибок, не позволяющими проводить дорогостоящие операции по нахождению неиспользуемых методов, классов и тому подобного.

В качестве частичного решения проблемы можно использовать Dart Code Metrics, но с ним в больших проектах будет ощущаться низкая скорость проведения статистического анализа, что неприятно.

Ни туда, ни сюда

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

1. Различие платформ

В кроссплатформенном подходе не каждый дизайнер готов воплощать привычный пользователям UX/UI для различных платформ. Нередко выбирается что-то среднее и, чаще всего, основой в дизайне выступает Human Interface Guidelines. Порой этим злоупотребляют столь часто, что это приводит к поистине галактическим проблемам.

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

2. Одна кодовая база

Поддерживать кроссплатформенное приложение на одной кодовой базе, конечно, интересное приключение — код с виду один, а условия для взаимодействия с каждой платформой могут значительно разниться. Например, неправильно заложенная архитектура может привести к увеличению сроков на тестирование и поддержку.

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

Выводы

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

Резюмируя:

  1. Виджеты Flutter позволяют быстро и гибко реализовывать сложные пользовательские представления, а сам Dart представляет собой простой язык, который легче освоить, чем Kotlin, Swift или Java.
  2. Flutter имеет активное сообщество разработчиков, различные пакеты, а также программы для повышения качества этих пакетов. Инструментарий старается идти в ногу со временем, адаптируясь к аппаратным и программным изменениям.
  3. Кодогенерация и статистический анализ кода требуют роста вовлеченности команды, развивающей Flutter, в улучшении этих инструментов.
  4. Реальная производительность может отличаться от платформы к платформе, поэтому необходимо определиться с целевым предназначением.
  5. Пользовательское взаимодействие на некоторых платформах может отличаться от взаимодействия нативного.

Автор: Данил Абдрафиков (разработчик мобильных приложений TAGES)

Источник: Хабр

Назад