Hola, Amigos! На связи Саша Чаплыгин, Flutter-dev. Нашел интересную статью от автора Deep Bhavsar, которая помогла мне детальнее разобраться с Flutter 3, а еще я сам теперь применяю советы из нее в разработке. Будет полезно почитать разработчикам всех мастей, эта информация окажется весьма полезной для решения ваших повседневных рабочих задач. Я и мои коллеги пишем о том, что такое быть Flutter-разработчиками и рассказываем о внутренней кухне проектов в телеграм-канале Flutter.Много. Заходите, будем вас ждать :)   В этой публикации вы познакомитесь с передовыми методиками, предназначенными для разработчиков Flutter, которые помогут вам улучшить качество программного кода, его читаемость, простоту сопровождения и продуктивность. Для эффективной работы функции build необходимо обеспечить ее максимальную «чистоту», т.е. отсутствие ненужных элементов программного кода. Это связано с тем, что существуют определенные внешние факторы, которые могут спровоцировать создание нового виджета (Widget build), ниже приведены некоторые примеры: навигация в приложении; изменение размера экрана, обычно из-за показа/скрытия клавиатуры или изменения ориентации экрана;  родительский виджет воссоздал свой дочерний виджет; виджет Inherited Widget зависит от изменения значений (Class. of(context) pattern). Пример неправильного программного кода выглядит так: Пример правильного программного кода должен выглядеть так: Существует одно широко распространенное практическое правило в отношении макетов Flutter, которое должен соблюдать каждый разработчик приложений Flutter: ограничения уменьшаются, размеры увеличиваются, а родительский элемент определяет положение. Давайте разберемся в этом вопросе подробнее. Виджет имеет свои собственные ограничения, которые определяются его родительским виджетом. Ограничение – это набор из четырех парных значений: минимальной и максимальной ширины, а также минимальной и максимальной высоты. Далее виджет просматривает свой собственный список дочерних элементов. Виджет по очереди задает своим дочерним элементам ограничения (которые могут быть разными для каждого элемента), а затем запрашивает у каждого такого элемента информацию о желаемом размере. Далее виджет размещает один за другим свои дочерние элементы (горизонтально по оси x и вертикально по оси y). Затем виджет передает своему родительскому элементу информацию о своем собственном размере (в рамках исходных ограничений). Во Flutter все виджеты определяют себя на основе ограничений своего родительского элемента или ограничений своего бокса. Однако здесь имеется ряд ограничений. Например, если у вас есть дочерний виджет внутри родительского виджета, и вы хотите задать его размер. Виджет не может иметь какой-либо размер сам по себе. Размер виджета должен находиться в пределах ограничений, установленных его родительским элементом. Используйте оператор Cascades Если необходимо выполнить последовательность операций для одного и того же объекта, то следует выбрать оператор Cascades(...). Используйте коллекции spread Вы можете использовать коллекции spread, когда существующие элементы уже хранятся в другой коллекции. Синтаксис коллекций spread обеспечивает более простой программный код. Используйте операторы Null safe (??) и Null aware (?.) В условных выражениях всегда используйте операторы ?? (if null) и ?. (null aware) вместо проверки на неопределенное значение (null). Избегайте использования оператора as, вместо него необходимо использовать оператор is. Как правило, оператор приведения as создает исключение, если приведение невозможно. В таких случаях можно использовать оператор is. Хотя функция Streams представляет собой достаточно мощный и эффективный инструмент, она создает большую нагрузку на аппаратные ресурсы. Неправильная реализация может привести к увеличению потребления ресурсов памяти и процессора. Но дело не только в этом. Если вы забудете остановить выполнение функции Streams, это приведет к утечке памяти. Поэтому в таких случаях для реактивного пользовательского интерфейса можно использовать другой инструмент, который потребляет меньше ресурсов памяти, например, ChangeNotifier. Для более продвинутых функций мы можем выбрать библиотеку Bloc, которая обеспечивает эффективное использование аппаратных ресурсов и предлагает набор простых инструментов для создания реактивного пользовательского интерфейса. Если функция Streams не используется, ее данные будут эффективно удаляться. Дело в том, что если вы просто удалите переменную, этого будет недостаточно, чтобы убедиться, что она не используется. Она может продолжать работать в фоновом режиме. Вам нужно вызвать Sink.close(), чтобы остановить соответствующий StreamController, чтобы убедиться, что ресурсы памяти могут быть позже освобождены с помощью функции очистки GC. Для этого необходимо использовать метод StatefulWidget.dispose: Вы не сможете застраховать себя от ошибок, связанных с тестированием, выполняемом в ручном режиме, однако наличие автоматизированного набора тестов поможет вам сэкономить значительное количество времени и усилий. Поскольку комплект средств разработки Flutter предназначен для большого количества платформ, проверка каждой функции после внесения каждого изменения будет отнимать много времени и потребует большого объема постоянно повторяющейся работы. Проверка всего программного кода целиком гарантирует наилучшие результаты, однако ее выполнение не всегда возможно в силу ограниченного времени и средств. Тем не менее, необходимо иметь тесты хотя бы для проверки основных критически важных функций приложения. Тесты для проверки отдельных юнитов и виджетов будут оптимальными решениями, которые следует использовать с самого начала, и их выполнение не будет настолько сложной задачей по сравнению с тестами проверки интеграции. Необработанные строки можно использовать не только для того, чтобы изолировать символы «\»и «$». В обычной строке «$» предшествует идентификатору, который подставит значение. А «\» позволит вставить символ (\\ = \ в консоле). В случае var s = r'$ \'; все ок, оно так же отобразится в консоле. Антон Мартышков, Flutter-dev Amiga. При одновременном использовании функции относительного и абсолютного импорта может возникнуть путаница, когда один и тот же класс импортируется двумя разными способами. Чтобы избежать этого, необходимо использовать относительный путь в папке lib/. Существует множество случаев, когда необходимо использовать заполнитель. Ниже приведен наглядный пример: Container – это отличный виджет, который вы будете активно использовать во Flutter. Container() адаптируется, чтобы соответствовать ограничениям, заданным родительским элементом, и не является const-конструктором. В то время как виджет SizedBox является const-конструктором и создает бокс фиксированного размера. Значения ширины и высоты могут быть равны нулю, чтобы указать, что размер бокса не должен быть ограничен в соответствующем измерении. Таким образом, когда нам нужно использовать заполнитель, нужно сделать выбор в пользу виджета SizedBox, а не Container. Функции print() и debugPrint() всегда применяются для входа в консоль. Если вы используете функцию print() и получаете слишком большой объем выводимых данных, то Android иногда отбрасывает некоторые строки функции log. Чтобы избежать возникновения подобного рода ситуаций используйте функцию debugPrint(). Если данных функции log более чем достаточно, используйте функцию dart: developer log(). Это позволяет вам получить более детальную информацию. Для вариантов с одной строкой используйте условный оператор. Для вариантов, как те, что показаны ниже, используйте условие if вместо условного оператора. Всегда старайтесь использовать виджеты Const. Виджет не будет меняться при вызове setState, мы должны определить его как константу. Таким образом виджет не будет перестраиваться и сохранит высокую скорость работы. В Dart переменная интуитивно инициализируется в null, если ее значение не указано, поэтому добавление null является избыточным и необязательным. Всегда выделяйте тип члена, если тип его значения известен. Не используйте var, когда это не требуется. Поскольку var является динамическим типом, для его выполнения требуется больше места и времени. Использование const-конструктора для виджетов позволяет уменьшить объем мусора и упростить работу функции очистки GC. Возможно, вначале скорость работы покажется вам не слишком высокой, но на самом деле она увеличивается и играет важную роль, когда приложение становится достаточно большим, или существует представление, которое часто перестраивается. Декларации const также лучше подходят для горячей перезагрузки. Более того, мы не должны использовать ненужное ключевое слово const. Посмотрите на следующий код: Нам не нужно использовать const для виджета Text, поскольку const уже применяется к родительскому виджету. Dart поддерживает следующие правила Linter для const: Не забывайте убирать корневые виджеты в безопасное место. Вы можете объявить несколько переменных с помощью сокращения- (int mark =10, total = 20, amount = 30;) Убедитесь, что используете переменные класса final/const, когда есть такая возможность. Старайтесь не использовать необязательный закомментированный код. Создавайте частные переменные и методы, когда это возможно. Создавайте различные классы для цветов, стилей текста, размеров, постоянных строк, продолжительности и так далее. Разработайте константы API для ключей API. Старайтесь не использовать ключевые слова await внутри блока Старайтесь не использовать глобальные переменные и функции. Они должны быть связаны со своим классом. Следуйте рекомендациям Dart Analysis Проверьте строки с подчеркиванием, которое указывает на опечатку или дает советы по оптимизации Используйте _ (нижнее подчеркивание), если значение не используется внутри блока кода. Магические числа всегда имеют правильные названия для удобочитаемости.  Flutter-dev