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

Почему рецензирование кода имеет значение

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

Мы выясним, какие изменения стоит вносить в код Flutter/Dart, а какие не имеют смысла. Мои идеи основаны на реальных рецензиях кода, практическом опыте и коллективной мудрости моей команды. Независимо от того, являетесь ли вы новичком во Flutter или опытным разработчиком, эти практические советы помогут писать более чистый и эффективный код.


Соглашения об именовании: множественное и единственное число имен переменных

В приведенном ниже фрагменте кода имя переменной values используется для хранения экземпляра EdgeInsets. Это вводит в заблуждение, поскольку переменная хранит один объект EdgeInsets, а не несколько. Более подходящим именем было бы value.

class AppPaddingField extends StatefulWidget {
final Function(EdgeInsets) onChanged;
final EdgeInsets values;
// код...
}

Если бы переменная содержала список объектов EdgeInsets, например List<EdgeInsets> values;, то имя values было бы уместным.


Функции и виджеты

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

Вот пример:

class PaddingField extends StatelessWidget {
const PaddingField({super.key});

@override
Widget build(BuildContext context) {
return customRadioButton();
}

Widget customRadioButton() {
return // здесь - UI-код;
}
}

Рефакторинг функций в виджеты:

class PaddingField extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const CustomRadioButton();
}
}

class CustomRadioButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return // здесь - UI-код;
}
}

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


Стремление к содержательности: избегание “Custom” в названиях виджетов

Избегайте использования общих префиксов типа “Custom” в названиях виджетов. Например, вместо CustomRadioButton лучше использовать такое название, как BorderedTextRadioButton.

Вот как можно рефакторизовать код.

До рефакторинга:

class PaddingField extends StatelessWidget {
Widget build(BuildContext context) {
return const CustomRadioButton();
}
}

class CustomRadioButton extends StatelessWidget {
Widget build(BuildContext context) {
return // здесь - UI-код;
}
}

После рефакторинга:

class PaddingField extends StatelessWidget {
Widget build(BuildContext context) {
return const BorderedTextRadioButton();
}
}

class BorderedTextRadioButton extends StatelessWidget {
Widget build(BuildContext context) {
return // здесь - UI-код;
}
}

Обертывание виджетов: когда это имеет смысл

Во Flutter паттерн декоратора часто используется для расширения функциональности существующих виджетов. Обертывание виджета позволяет настроить его под конкретные нужды. Например, можно создать виджет NoBorderTextField, который обертывает встроенный TextField и устанавливает его без границ. Таким образом, можно использовать NoBorderTextField, когда требуется текстовое поле без границ, а не задавать каждый раз свойства без границ. Однако обертывание виджетов без добавления какой-либо новой функциональности не имеет смысла. Например, если PaddingField обертывает AppPaddingField без внесения каких-либо изменений, то это не добавляет ценности и должно быть устранено.

class PaddingField extends StatelessWidget {
final void Function(EdgeInsets) onChanged;
final EdgeInsets value;
// Конструктор
@override
Widget build(BuildContext context) {
return AppPaddingField(onChanged: onChanged, values: value);
}
}

Напутственные замечания

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

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Asfar Ali: Flutter Code Review: Do’s, Don’ts and Best Practices #1

Предыдущая статьяBun или Node: бенчмаркинг бессерверных сред выполнения на AWS Lambda
Следующая статьяJava 21: новый подход к созданию строк