Этот сайт использует файлы cookies. Оставаясь на сайте, Вы соглашаетесь с использованием файлов cookies и принимаете Соглашение об использовании сайта.

flutter2

Flutter. Пробуем Dart на зуб и наводим порядок в коде

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


Оглавление

Знакомство с Dart

Dart сравнительно молод (впервые заявил о себе в 2011 году), разрабатывался компанией Google как замена языку JavaScript. И, откровенно говоря, рука автора в творении ощущается довольно явно. Многие вещи, которые смутят или заставят задуматься iOS-разработчиков, нисколько не удивят их Android-коллег. Речь идет, в частности, о Future с реактивностью, которые стали доступны только в Swift 5, но давно используются в Java и Kotlin.

В объектно-ориентированном Dart абсолютно всё, включая даже числа и логические значения, является экземпляром классов, корнем генеалогического древа, которым стал Object. Статическая типизация языка избавляет программистов от неуверенности, знакомой разработчикам на Objective-C. Вместе с тем компилятор Dart не хуже Swift’ового аналога умеет выводить тип переменных по косвенным признакам и не требует прописывать названия классов явно.

Любопытно решение, принятое относительно области видимости переменных. Public, private… забудьте эти ненужные слова! Изначально все переменные и методы публичны. Но стоит начать имя переменной со знака подчеркивания, как она автоматически станет private для нашего класса. Аналогичный фокус можно провернуть и с названиями функций.

Dart старается не отставать от модных тенденций, поэтому «джентльменский» набор из лямбд, универсальных шаблонов, вложенных функций и объектов первого порядка на месте и радует глаз. В перспективе появятся и extension-методы (пока доступны только в dev-ветке). Имеется даже ряд излишеств вроде опциональных параметров функций, наличия позиционных и именованных параметров в одном методе или глобальных функций, существующих за пределами какого-либо класса. А вот полноценных опционалов, кортежей и мощных Swift’овых enum’ов пронзительно не хватает.

Зато создатели языка значительно упростили для программистов работу с асинхронными операциями. В рамках одного потока они реализуются при помощи явного вызова команд async/await, использования концепций Futures и Streams. Многопоточность в Dart тоже сильно упрощена. Потоки здесь называются «isolate», они используют изолированные ресурсы. По сути, два «isolate» способны обмениваться друг с другом только сообщениями. Что это значит для программиста? Прежде всего то, что потоки не смогут получить одновременный доступ к разделяемым ресурсам, организовать «гонку» и добавить седых волос разработчику. Среднестатистическое Flutter-приложение живет и работает в одном единственном потоке. Впрочем, никто не запретит создать свой собственный «isolate» и вынести «тяжелый» код туда.

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

 SomeClass someReference = SomeClass()


..firstMethod()

..aProperty = value

..secondMethod();

может вызвать у особенно чувствительных аллергическую реакцию.

А вот с визуальным разделением кода дела пока обстоят не очень. После ярких #pragma mark у Objective-C и MARK у Swift, которые в последнем Xcode сияют едва ли не неоновым огнем на миникарте класса, серенькие неприметные regions, используемые для выделения блоков кода в Android Studio, впечатления как-то не производят.

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

Code Style

После краткого знакомства и погружения в код возникает острое желание навести в нем порядок при помощи линтера. И здесь нас ждет приятный сюрприз: линтер добавляется автоматически при создании нового проекта! Больше не надо вручную подключать дополнительные библиотеки (да, я говорю о тебе, SwiftLint) для проверки «чистописания». Результаты анализа кода беспощадным потоком выливаются на нас во вкладке Dart Analysis (в Android Studio: View → Tool Windows → Dart Analysis), предварительно сгруппировавшись по степени суровости проступка.

Кроме того, имеется возможность дополнительно настроить список правил, которым будет руководствоваться линтер. Для этого добавляем в корень проекта analysis_options.yaml. Flutter-сообщество разработало эталонный набор правил и готово поделиться им с новообращенными, так что выдумывать ничего не придется. Но мы, конечно, решили настроить линтер под себя. И здесь пришлось набить несколько шишек…

Начнем с того, что некоторые правила из стандартного списка открыто противоречат друг другу (взять хотя бы prefer_double_quotes и prefer_single_quotes). Большинство из них не учитывают ситуативность использования той или иной строчки кода. Отсутствует возможность самостоятельно добавлять правила при помощи регулярных выражений (прости, SwiftLint, не стоило тебя ругать) или хотя бы минимально настраивать уже существующие. Предел наших возможностей — выключение правила для конкретных строк кода. И хотя все они снабжены документацией с примерами, некоторые из них так и остались загадкой. Например, код:

groups.add(newGroup);

groups.sort();

выдает ошибку по правилу cascade_invocations, а после замены на:

groups.add(newGroup)

..sort();

начинает ругаться на отсутствие у метода add возвращаемого значения и невозможность его использования в связи с этим.

По итогу в душе борются благодарность за само наличие линтера у Dart и ноющая боль от его несовершенства.

Что дальше?

Итак, Dart нам больше не страшен. Мы не только освоились в языке, но и подобрали удобный для команды code style. Выходит, можно переходить к активной разработке. А начиная писать новое приложение, нужно сразу озаботиться его локализацией. В следующей статье поговорим о поддержке мультиязычности во Flutter-проекте.