Files
friflex_flutter_starter/.github/copilot-instructions.md
Yuri Petrov 6500b917c5 refactor(app): обновить структуру приложения и удалить устаревшие провайдеры (#44)
* refactor(app): обновить структуру приложения и удалить устаревшие провайдеры
* refactor(runner): упростить обработку ошибок и улучшить логирование времени инициализации
* refactor(runner): улучшить порядок инициализации приложения и обработку ошибок
* refactor(app): исправить контекст MediaQuery для предотвращения перерисовки
* refactor(pp): удалить главный виджет приложения и заменить его на AppRoot
* docs(copilot-instructions): уточнить правила проведения Code Review на русском языке
* refactor(linter): добавить правило avoid_catches_without_on_clauses для улучшения обработки исключений

---------

Co-authored-by: petrovyuri <petrovyuri@example.com>
2025-12-11 21:18:24 +03:00

20 KiB
Raw Blame History

Правила разработки Flutter проекта

Этот файл содержит правила и стандарты разработки для проекта. Все правила обязательны к соблюдению при написании кода.

ВАЖНО: Перед каждым PR необходимо отформатировать код (dart format .) и проверить анализатор на отсутствие сообщений (dart analyze).


Правила проведения Code Review

Основные правила проведения Code Review

ВАЖНО: - Комментарии, обзоры и описание Pull Request при проведении code review должны быть на РУССКОМ языке.

Стиль кода

Именование

Интерфейсы

Все интерфейсы в приложении должны начинаться с заглавной буквы "I".

Примеры: IAuthRepository, IProfileRepository, IMainRunner и т.д.

Таким образом, сразу видно, что работаешь с интерфейсом.

Пример:

/// Интерфейс - **IUserRepository**
abstract interface class IUserRepository {}

/// Основная реализация (prod и stage окружения)
class UserRepository implements IUserRepository {}

/// Иная реализация (мок, локальное хранилище) должна содержать
/// постфикс функциональности: 
/// - Network - сетевое взаимодействие.
/// - Local - локальное хранилище.
/// - Mock - мок репозиторий.
class UserRepositoryLocal implements IUserRepository {}

Классы - Репозитории

Репозитории должны содержать в конце название источника данных (если используется мок или локальное хранилище). Основная реализация не должна содержать постфикса.

Примеры:

  • Интерфейс - IAuthRepository
  • Основная реализация (prod и stage окружения) - AuthRepository
  • Мок (мок данные) - AuthRepositoryMock
  • Локальное хранилище (например бд или просто имитация данных) - AuthRepositoryLocal

Файлы

Используется snake_case. Название файла должно иметь следующую структуру: [раздел]_[тип].dart

Примеры: user_details_screen.dart, shop_entity.dart

Классы

Название классов UpperCamelCase. Для создания приватных классов используем префикс _. Название класса в конце должно содержать в себе тип.

Примеры: UserEntity, AdultDialog

Методы

Название метода в начале должно содержать в себе действие (глагол):

  • fetch
  • put
  • update
  • delete
  • и так далее

Примеры:

int fetchFirstElement() {}
void updateFirstElement() {}

ВАЖНО: Название метода не должно содержать в себе And/Or, и метод соответственно не должен выполнять подобную логику.

Переменные и константы

Константы именуются также lowerCamelCase.

Примеры:

const String carItem = 'default';

или

final String userName = 'user';

Виджеты

Виджеты именуются UpperCamelCase. В названии виджетов не должно содержаться слово widget.

Экраны

Экраны, используемые в роутинге, именуются с постфиксом Screen.

Пример: ShopListScreen

Содержимое экрана

Виджеты, отображающие содержимое экрана, именуются с постфиксом View.

Пример: ShopListView

Глобальные виджеты

Глобальные виджеты именуются с приставкой App.

Пример: AppButton

Структура класса

Объявления элементов класса должны располагаться в следующем порядке:

  1. Constructors
    • constructors
    • named-constructors
    • factory-constructors
  2. Static
    • public-static-methods
    • private-static-methods
    • public-static-const-fields
    • private-static-const-fields
    • public-static-final-fields
    • private-static-final-fields
    • public-static-fields
    • private-static-fields
  3. Fields
    • public-final-fields
    • private-final-fields
    • public-fields
    • private-fields
  4. Getters/Setters
    • public-getters-setters
    • private-getters-setters
  5. Methods
    • overridden-methods
    • public-methods
    • protected-methods
    • private-methods

Ведение документации и комментариев

Документация

Основные правила ведения документации в проекте

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

Шаблоны и примеры документации объектов

Документация классов

/// {@template new_class}
/// Класс для {описание назначения и реализуемого функционала в классе}.
/// {@endtemplate}
class NewClass {}

Пример:

/// {@template app_button}
/// Класс для реализации кастомизированной кнопки.
/// {@endtemplate}
class AppButton {}

Документация конструкторов и фабрик

Если конструктор один, то достаточно указать {@macro new_class}. {@macro new_class} дублирует на конструктор указанную в рамках описания класса документацию, поэтому описание класса должно в таком случае включать все передаваемые в конструктор параметры.

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

/// {@macro new_class}
const NewClass();

/// Создает {описание создаваемого фабрикой объекта}.
/// Принимает:
/// - [json] - {описание параметра}
factory NewClass.fromJson(Map<String, dynamic> json) {}

Документация полей классов

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

/// Возраст пользователя.
final int age;

/// Индикатор совершеннолетия пользователя. Принимает значение true, когда [age] больше 18 лет.
final bool isAdult;

Документация геттеров/сеттеров

/// Получения доступа к {описание данных, которые получает геттер}
int get newGetter => ...

/// Установка значения для {описание работы сеттера}
set newSetter(int setterValue) => ...

Документация методов

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

/// Метод для {описание назначения метода}.
/// {описание особенностей работы метода}.
/// Принимает:
/// - [param] - {описание назначения параметра}.
void newMethod({required String param}) {
    ...
}

Пример:

/// Метод для расчета температуры.
/// Принимает:
/// - [grad] - параметр необходим для расчета температуры.
/// Возвращает:
/// - температуру в градусах.
/// При ошибке расчета возвращается null.
int? calcTemperature({required int grad}) {
    // Реализация
}

Комментарии

Основные правила комментирования кода в проекте

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

Примеры неправильного использования:

if (flag != true)  // не нужно описывать как "Если значение не равно true..."

Примеры правильного использования:

if (isAurora) {
    // Так как Аврора не может открывать WebView,
    // то заменяем на открытие внешнего браузера
}

TODO

Основные правила создания TODO в проекте

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

Пример:

// TODO(username): Оптимизировать алгоритм сортировки

Ведение проекта в git

Создание commits/pull-request

  • Язык описания PR - Русский
  • Описание должно отражать краткую суть изменений
  • Коммит/PR должен содержать:
    • исчерпывающую информацию об изменениях
    • ссылку на задачу в таск-трекер
    • Перечисление deprecated-кода (если есть)

Типы коммитов согласно convention

  • feat: — новая функция
  • fix: — исправление ошибок
  • refactor: — Изменение кода, которое не исправляет ошибку и не добавляет функции (рефакторинг кода)
  • build: — изменения, влияющие на систему сборки или внешние зависимости (примеры областей (scope): android, ios, linux и так далее)
  • docs: — изменения только в документации
  • chore: — добавление/обновление/настройка инструментов и библиотек (пример: pubspec.yaml)
  • test: — добавление недостающих тестов или исправление существующих тестов
  • ci: — изменения в файлах конфигурации и скриптах CI (примеры областей: папка CI)

Структура проекта

Рекомендуемая структура проекта (может отличаться в зависимости от проекта и согласований)

  • / - папка проекта
  • /assets - директория расположения графических ресурсов
  • /tools/ - все необходимые инструменты для проекта
    • /docs - документация проекта
  • /env - папка, с внешними переменными окружения
  • /lib - код на Dart, Flutter-приложение
    • /app - содержит основные настройки нашего приложения
      • /data - общие поставщики данных
      • /domain - общий слой
      • /presentation - общий слой
    • /di - файлы конфигурации зависимостей
    • /router - все, что касается роутинга
    • /features - фичи приложения, для каждой фичи создается отдельная папка
      • /feature_name - подробнее см в разделе Структура feature папок
        • /data
        • /domain
        • /presentation
    • /gen - для сгенерированных файлов
    • /targets - таргеты для сборок
      • /prod.dart - сборка для prod
      • /dev.dart - сборка разработки на моковых репозиториях
      • /stage.dart - сборка для stage окружения

Пример структуры feature папок

  • /data - слой данных
    • /dto - реализация DTO (data transfer object)
    • /repository - реализации репозиториев
  • /domain - слой бизнес логики
    • /entity - модели которые используются для работы в domain/presentation слоях
    • /repository - интерфейсы репозиториев, которые используются в domain слое
    • /state - state-management
    • /service - реализации сервисов
  • /presentation - слой представления
    • /screens - все экраны должны заканчиваться на Screen, например UserProfileScreen
    • /components - виджеты, которые необходимы для работы в presentation слое. Например: SuperButton, AppTextFields итд

Пояснение к структуре feature папок

Data (слой данных)

Этот слой является поставщиком данных.

  • Repository - сущность, которая реализует внутри себя предоставление данных. Должен реализовывать какой либо интерфейс репозитория из domain слоя
  • DTO - Dto(Data Transfer Object) модели, и модели с которыми происходит работа в data слое. Например: UserDto

Domain (слой бизнес логики)

  • Entity - должны быть в максимально удобном виде для работы внутри Domain и Presentation. Например: UserEntity, ShopEntity
  • State - управления состоянием - state manager
  • Service - различные сервисы, для выполнения различных задач
  • interfaces - интерфейсы репозиториев, которые используются в domain слое

Presentation (слой представления)

  • components - widget'ы которые реализуют работу какого либо визуального компонента (Buttons, TextFields, Lists, итд). Например: ShopList, RateButton. Модальные окна
  • screens - widget'ы которые представляют собой экран приложения. Например: UserInfoScreen

Основные правила общения объектов между папками

В рамках всего приложения

  • Объекты внутри фичи должны быть инкапсулированы и не могут использоваться в других feature
  • Если есть необходимость использовать объект в нескольких feature, его нужно вынести в папку app и использовать как глобальный для всего приложения
  • Сервис, который должен быть использован в нескольких feature, создается как отдельная feature
  • Если создаваемый сервис является платформно-зависимым, его необходимо выносить в app_services. В приложении должен быть только интерфейс

В рамках одной feature

  • Объекты data слоя не должны ничего знать про объекты слоя presentation. Имеют доступ к объектам entity из domain слоя для преобразования DTO в Entity
  • Объекты domain слоя не должны ничего знать про объекты слоя data, используемый экземпляр репозитория передается в объекты domain слоя через интерфейс репозитория, расположенного в этом же domain слое
  • Объекты domain слоя не должны ничего знать про слой presentation, не должны использовать компоненты библиотек ui, material, cupertino, widget и прочих, не должны использовать context
  • Объекты presentation слоя не должны ничего знать про объекты слоя data, все взаимодействия непосредственно через объекты слоя domain