СТРУКТУРА ПАПКИ

Структура папок для Flutter с чистой архитектурой. Как я сделал.

Как это может быть сложно?

Организация ваших папок и файлов болезненна, особенно в больших проектах, которые могут легко подавить 1000 файлов для управления.

Файлы не должны содержать сотни строк. Ради нашего психического здоровья мы не можем иметь высокую связь и стремиться реализовать принцип единой ответственности.

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

Работа с чистой архитектурой

Понятие Чистая архитектура широкое и непонятное, но когда я говорю: Я использую Чистую Архив на проекте. Я имею в виду Архитектурное предложение Флаттерандо!

Коротко о предложении

Вы разделите код на 4 уровня: Presenter, Domain, Infra и External.

  • Presenter — компоненты нашего пользовательского интерфейса, в основном все, что связано с виджетом или контроллером виджета.
  • Домен — ядро ​​приложения. Здесь будут храниться все сущности и бизнес-логика.
  • Инфраструктура. Поддержите уровень предметной области, адаптировав данные, поступающие с внешнего уровня, с помощью моделей, репозиториев и служб.
  • Внешние — классы для переноса функций из сторонних библиотек, датчиков, SO, хранилища и любых других внешних зависимостей нашего приложения.

Надежного решения нет, но чистая арка отлично работает для меня в большинстве ситуаций, особенно после добавления некоторых практик, которые я описываю в статье Улучшите свою чистую архитектуру в приложениях Flutter.

Примечание.

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

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

Чистая арка + Модульная арка = Счастливый разработчик 😀

Модульная архитектура направлена ​​на сбор связанного контента в одном месте, называемом «модулем».

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

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

Для создания модульной архитектуры на Flutter у нас есть пакет flutter_modular, основанный на модульной системе фреймворка Angular.

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

Этот пакет также поставляется с инструментами для внедрения зависимостей и навигации по системе.

Корневая структура

Вместе с файлом pubspec.yaml вам придется работать с тремя каталогами: lib, assets и test.

Ничего нового! Возможно, вы уже используете их, так как lib и test — это автоматически созданные папки при создании проекта флаттера и использовании актива рекомендуется командой flutter.

Тем не менее, я должен определить их использование для новичков. После этого мы сосредоточим наше внимание только на папке lib.

Папка активов

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

Ресурс — это файл, который связан и развернут вместе с вашим приложением и доступен во время выполнения. Общие типы ресурсов включают статические данные (например, файлы JSON), файлы конфигурации, значки и изображения (JPEG, WebP, GIF, анимированные WebP/GIF, PNG, BMP и WBMP). — docs.flutter.dev

Папка с библиотекой

Где будут ваши файлы дартс! Поместите код здесь, просто так. "="

Тестовая папка

Все ваши тестовые файлы будут здесь. Его структура повторяет структуру папки lib.

Например, тест для виджета user_register_form.dart, расположенного в

lib/modules/register/presenters/widgets

Должен быть создан как

test/modules/register/presenters/widgets/user_register_form_test.dart.

Структура библиотеки

Основная папка

В эту папку входят файлы, выполняющие функцию main для каждого вкуса.

Также файл common_main.dart, который выполняет общие команды всех ароматов.

В случаях, когда Flavors не используются, мы можем переключить эту папку и ее содержимое только на main.dart файл.

папка i18n

Подождите! JSON-файлы? Разве они не должны быть в папке с ресурсами? Ну...Да! Это мой грех. Правильное место для размещения файлов JSON — папка ресурсов. Но пакет локализации требует хранить его в файле lib.

Конечно, я делаю это только потому, что пакет вынуждает меня. Но если вы измените эту зависимость и будете использовать, например, пакет easy_localization, вам следует удалить папку i18n из lib.

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

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

Основная папка

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

  • Конфигурации — любая начальная конфигурация, необходимая для системы. Например, начальная конфигурация firebase.
  • Константы — строки контактов приложения, такие как имена маршрутов и регулярные выражения.
  • Расширения — Методы расширения Dart.
  • Миксины — Дарт Миксины.
  • Utils — служебные классы, такие как CurrencyFormatter или DateUtils.
  • Валидатор — классы, которые проверяют данные, такие как поля, номера телефонов, документы и т. д.

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

Папка модулей

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

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

Каждый слой хранит определенные типы классов. Они есть:

  • Presenter:
    Виджеты — классы визуальных компонентов.
    Контроллеры — классы управления состоянием виджета.
  • Домен:
    Сущности — классы для хранения данных.
    Случаи использования — классы бизнес-логики.
  • Infra:
    Модели — классы, которые расширяются от сущностей для преобразования данных.
    Источники данных — классы, которые подключаются к внешним API (используйте драйвер HTTP).
    Сервисы — классы, которые не подключаются к внешним API ( не используйте драйвер HTTP).
  • External:
    Драйверы — классы для изоляции внешних библиотек или системных функций.

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

Структура модуля

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

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

Мне нравится разделять модуль на страницы. В этом случае пользователю доступны 3 страницы: Login, Register и RecoverPassword.

Внутри нашей папки входа находятся чистые слои арки, необходимые для страницы входа.

Ведущий

Поскольку модуль разделен на страницы, мы можем встретить виджет страницы входа и его контроллер в корне папки докладчика.

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

Также есть папка «диалоги». Но может иметь папку «представления», если для создания страницы требуется виджет PageView.

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

Домен

Он имеет класс AuthEntity, в котором хранится имя пользователя и пароль для входа в систему.

Любая бизнес-логика выполняется Usecase. Но какова возможная бизнес-логика для функции входа в систему?

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

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

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

Инфра

Вы заметили файлы auth_datasource.dart и auth_datasource_impl.dart?

Интерфейсы создаются для источников данных, служб и драйверов. Код находится в файле ‹name›_‹layer›_impl.dart. Использование интерфейсов увеличивает развязку и помогает создавать тесты с фиктивными классами.

Если тип файла является источником данных, вы уже знаете, что он запрашивает API.

Домен предоставляет AuthEntity моему источнику данных, который использует AuthModel для преобразования своего значения в формат API.

Драйвер (внешний)

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

Общий модуль

Помимо наших модулей для хранения страниц, у нас есть общий модуль.

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

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

Доволен ли я своей структурой папок?

Черт возьми, нет! Почему я должен?

Эта грешная папка i18n, я надеюсь, что когда-нибудь пакет локализации это исправит!

Я никогда не знаю, находится ли драйвер, который я ищу, в текущем модуле, в котором я работаю, или в общем модуле.

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

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

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

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

Знаете ли вы какое-нибудь лучшее или негласное решение о файловых структурах для приложений Flutter?

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