Создание нового проекта на Flutter - это благословение - свежая кодовая база, никакого легаси кода (пока что), null safety, самые последние версии ваших любимых библиотек и так далее. Однако, в то же время, необходимо принять критические решения в самом начале, которые будут лежать в основании для будущего, такие как инструменты, пакеты, файловая структура, решение для менеджмента состояния, тестирование и планирование. В противном случае, в итоге, проект превратится в еще одну чашу спагетти с фрикадельками. Чтобы избежать этого, я подготовил список наиболее важных, по моему мнению, частей проекта, которые должны быть решены как можно раньше. Я надеюсь, что это поможет вам. Приятного чтения!

Данная статья является переводом с небольшой адаптацией. Приятного чтения!

Статические анализ кода

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

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

Локализация

Что такое локализация (localization, l10n)?

Localization is the adaptation of a product or service to meet the needs of a particular language, culture or desired population’s “look-and-feel.” — TechTarget

Очень важно делать приложение, которое будет чувствоваться естественным и простым для пользователя. Например, использование правильных переводов, дат, отображения валюты, а также направления текста. Локализация является неотъемлемым и фундаментальным инструментом для использования. Даже, не смотря на то, что вы делаете приложение для определенного региона или языка, я все равно рекомендую реализовать локализацию как можно раньше и отделить тексты от кода интерфейса. Таким образом, они могут быть переиспользованы и исправлены позже без влияния на код. 

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

Окружения (Environments) с различными особенностями

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

Окружение разработчика (development) - служит для экспериментов в коде, прямого изменения данных, позволяет использовать пути быстрого доступа, а также захардкодить токен авторизации или отдать предопределенные данные. Веселитесь и поставляйте новый функционал!

Промежуточная среда (testing, staging) - помогает подтвердить правильность изменений в коде, опробовать новый функционал на реальных данных. Обычно, копия реальных данных используется в этом окружении. Так же именно здесь есть возможность удостовериться в том, что приложение работает правильно, прежде чем отдавать его конечному потребителю. Если у вас есть QA инженеры, это место именно для них.

Производственная среда (production) - используется реальными пользователями, повреждение данных здесь критично. Всегда используйте резервное копирование, пожалуйста.

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

Непрерывная интеграция и непрерывная доставка (CI/CD)

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

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

  • Appcircle;

  • Codemagic;

  • Bitrise;

  • VS App Center (еще не имеет интеграции с Flutter, но имеет большое количество ресурсов, которые могут помочь настроить все правильно).

Подойдет любое из этих решений - просто выберите то, которое соответствует вашим потребностям и бюджету.

Сервера и API

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

В упрощенной версии есть два варианта серверной части вашего приложения:

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

  • Использование любого облачного решения для ускорения процесса разработки и предоставление большей части DevOps работы поставщику облачных услуг.

Если второй вариант кажется вам привлекательным, есть несколько отличных облачных платформ, поддерживающих Flutter:

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

Логирование, данные о сбоях и аналитика

Логирование - недооценено. Я сказал это! Все круто, пока что-то не пойдет не так, и вам понадобится информация об этом. Когда мы обсуждаем, что нужно регистрировать, а что нет, всегда есть серая зона. Но всегда ясно одно - вы должны знать, когда ваше приложение вылетает и что вызывает проблему. Чем больше данных об инциденте вы соберете, тем легче будет найти и устранить проблему.

Такие службы, как Sentry, Firebase Crashlytics, Datadog, могут помочь вам регистрировать наиболее важные данные, отчеты о сбоях или даже настраивать уведомления, когда ваше приложение или связанные службы не работают.

Другой тип логирования - это сбор пользовательских данных в целях анализа. Когда вы создаете новый, возможно, единственный в своем роде продукт, очень важно понимать потребности ваших пользователей, их поведение и то, как они используют приложение. Для этого в ваше приложение Flutter можно интегрировать различные инструменты анализа, такие как Firebase Analytics, App Center Analytics и многие другие.

Брендирование приложения

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

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

Структура проекта и менеджмент состояния

Да, спорно. Для ясности, не существует таких понятий, как «лучшее решение для управления состоянием» или «лучшая архитектура приложения» - если кто-то говорит обратное, помните, что они, вероятно, тоже наливают молоко в миску перед хлопьями. И что хуже всего - я не могу научить вас лучшему способу. Я могу предложить только несколько вариантов или поделиться своими предпочтениями.

Несколько вариантов структуры файлов для следующего проекта Flutter:

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

  • Многоуровневая архитектура - основана на идее разделения данных, бизнес-логики и логики представления на отдельные уровни. Такая файловая структура отлично работает для малых и средних проектов, но я чувствую, что эти слои становятся все более и более подавляющими по мере роста проекта;

  • Модульная архитектура (я описал эту концепцию здесь) - разделение кода на модули для каждой функции, в которой взаимодействуют разные модули. Это мой любимый вариант - он отлично работает с решением для управления состоянием BLoC (TEAM BLOC, ДА!), Хорошо масштабируется для больших проектов. Однако это создает некоторые проблемы, например, где разместить общую логику, как разные модули должны взаимодействовать и так далее.

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

Генерация кода

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

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

Для быстрого старта проекта Flutter я бы порекомендовал проверить Very Good CLI. Это сэкономит вам несколько часов настройки (к сожалению, я выучил это на собственном горьком опыте).

Кроме того, в прошлом месяце я говорил о генерации кода - это может стать отправной точкой для вашего пути генерации кода Flutter, так что проверьте это!

Стратегия тестирования

Покрывать тестами 100% кода - это хорошо или плохо? Конечно, это круто, но какой ценой? Думая таким образом, вы можете попасть в обреченную яму, где вы тратите больше времени на написание тестов, чем на разработку функционала. Чтобы этого избежать, нужна стратегия тестирования.

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

  • Бизнес-логика (сервисы, репозитории, BLoC) должна быть охвачена на 85-100% в модульных / интеграционных тестах - это самая важная часть любого приложения, поэтому я вижу здесь большую ценность в тестах;

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

  • Сквозные тесты (end-to-end), охватывающие основные потоки приложений и взаимодействия с пользовательским интерфейсом. Никакой глубокой магии - просто прохождение некоторых важных рабочих процессов. Чем больше экранов они включают, тем лучше.

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

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

README файл

Вы меня правильно поняли - документация. Файл README - важнейший документ проекта, особенно при работе в команде.

Вы только что представили новое решение, требующее генерации кода? Вы только что добавили новый полезный сценарий bash для автоматизации процесса? Вы реализовали глобальный регистратор, который ДОЛЖЕН использоваться повсюду в проекте? Мы не можем читать ваши мысли - укажите это в файле README!

Не бывает слишком много документации (по крайней мере, я не был в такой ситуации), только отсутствие информации о проекте и коде. Все команды для генерации, тестирования и запуска кода, различные решения по структуре файлов, диаграммы, внешние инструменты и службы, информация о различных средах (БЕЗ СЕКРЕТНЫХ КЛЮЧЕЙ) должны быть помещены сюда и храниться в одном месте. Это скучная работа, но очень полезная!


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

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


  1. sargon5000
    31.08.2021 14:52
    +1

    Что ж, поскольку переводчик просит указать на его ошибки, я перечислю те, что бросаются в глаза.

    1. Если предложение начинается со слова "Однако", "Но", "Даже", "Обычно" и т.п. – запятая после него точно не нужна.

    2. Обстоятельства места и времени никогда не выделяются запятыми. В фразе "Однако, в то же время, необходимо..." сразу две ошибки. И такого много.

    3. "Вы точно слышали истории о том, из вашего окружения, повредил данные" – немного безумная фраза.

    4. Несогласованное слов. "Внедрение собственного серверного решения с использованием любого языка программирования и фреймворка, который вам нравится, но позже позаботится обо всех материалах.." – кто именно позаботится? Язык/фреймворк? Решение? Внедрение? Читатель? Склоняюсь к последнему, но тогда нужно было написать "позаботиться". И даже в таком виде эта фраза корявая, нужно было ее написать так: "Внедрить собственное серверное решение ... но позже позаботиться..."

    5. Вы упорно используете знак минус (дефис) там, где нужно тире. Напрасно. Ввести тире в виндосовском редакторе совсем несложно: Alt+0150 или Alt+0151.


    1. alyxe Автор
      31.08.2021 17:13

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


  1. Sergo_1969
    31.08.2021 15:57
    -1

    Главная проблема любого флаттер-проекта - как сделать так что-б не тормозило на ровном месте, а они линт-блок-глок-локализейшн...


    1. alyxe Автор
      31.08.2021 17:59

      Довольно часто мобильное приложение подтормаживает, если вы производите тяжелые задачи на основном потоке. Так же, естественно, что гибридное приложение будет работать медленнее и тяжелее, чем если бы делали нативную версию. В любом случае, думаю есть моменты, которые явно возможно поправить и приложение начнет работать стабильнее и быстрее.


      1. ookami_kb
        31.08.2021 18:48

        Так же, естественно, что гибридное приложение будет работать медленнее и тяжелее

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

        Есть (были?) проблемы с подлагиванием на iOS, но это баги, которые со временем фиксятся, а не архитектурные проблемы фреймворка.


        1. zim32
          31.08.2021 23:51
          -1

          И почему оно ожидаемо. Что там такого под капотом? Нативный код? Так jit джавы быстрее нативного дарта в тестах. Биндинги Ския? Почему они должны быть быстрее нативного рендеринга? Композабл виджеты? Почему бесконечное пересоздания и уборка легких объектов должно быть быстрее создания нативных уи объектов и последующим изменением лишь их свойств?


          1. ookami_kb
            01.09.2021 01:48
            +2

            Так jit джавы быстрее нативного дарта в тестах

            И что это за тесты?

            Биндинги Ския? Почему они должны быть быстрее нативного рендеринга?

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

            Почему бесконечное пересоздания и уборка легких объектов должно быть быстрее создания нативных уи объектов и последующим изменением лишь их свойств?

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

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


      1. Sergo_1969
        01.09.2021 01:38

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


        1. ookami_kb
          01.09.2021 02:48

          А в чем проблема? iPhone SE2, profile (даже не релиз) билд, бесконечный скролл картинок из сети: https://drive.google.com/file/d/1T40SkYbK5oA8o5tNW_r_hvXK0BA_zUev/view?usp=sharing


          1. Sergo_1969
            01.09.2021 08:00
            -1

            Но вот вживую, в наличии иных компонентов ю-ай, и при картинках в нормальном, а не мелком разрешении - все не так радостно: https://drive.google.com/file/d/14wkNBMUkFbqmuRCytBFcFyPH-fRhhiru/view?usp=sharing Это не фейсбук, код прописан мной вручную - следуя уроку тут: https://www.youtube.com/watch?v=HvLb5gdUfDE Версия флаттера - наипоследнейшая.


            1. ookami_kb
              01.09.2021 11:48
              +1

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


              1. Sergo_1969
                01.09.2021 14:58
                -1

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


                1. ookami_kb
                  01.09.2021 15:37

                  1. Sergo_1969
                    01.09.2021 15:54
                    +1

                    Вы возвращаете мне веру в данную технологию - спасибо.