На очередном митапе ОЭЗ "Иннополис" Flutter-разработчики поделились опытом эффективного использования возможностей фреймворка в больших проектах. В ходе митапа они раскрыли основные преимущества своих подходов, поделятся полезными инструментами в работе с web-приложениями.
Как показывает практика, в приложения, которые переходят на определенный новый уровень, редко добавляются новые экраны или модули. Однако в то же время, постоянно появляются специфические бизнес требования, которые должны быть соблюдены. И в этот момент у абсолютного каждого разработчика возникает вопрос: “Как добавить новые требования в приложение, чтобы оно не сломалось?”
Именно поэтому наша разработка приложений осуществляется на основе определенного подхода.
Ниже вы можете увидеть фрагмент дерева и маленький разобранный кусочек логики. Был использован WM подход, поэтому можно считать, что это элемент интерфейса.
Для добавления новых требований нам нужен StatementService - сервис, в котором находятся методы для работы с выписками и состоянием счета пользователя. Также нужен StatementRepository, чтобы подключиться к бэкграунду. Клиент и провайдер нам тоже нужен для реализации нашей затеи. В нашем случае это Dio и Interceptor соответственно.
В этой статье мы рассмотрим Dependency Injection для Dart и Flutter проектов. Мы расскажем о том, как сделать Dependency Injection декларативным (самогенерируемым) и при этом сохранить человеко-читабельность, как подменить компоненты при тестировании и как изолируются моки от production-кода.
Реализация
Для реализации dependency injection by codegen необходимо 4 разных пакета - get_it, injectable, injectable_generator и build_runner (два последних - это dev зависимости).
Если использовать метод main для разработки флаттера приложения, то стоит помнить, что используется метод графических зависимостей. Это означает, что график зависимостей будет готов еще до готового флаттера приложения. И в нем уже будет находиться бизнес логика с ее компонентами.
Следующим этапом реализации dependency injection by codegen является выполнение команды:
Чтобы выполнить эту команду, нужно запустить build_runner с условием watch - эта команда просмотрит все файлы и составит график зависимостей. Прелестью этой команды является то, что она будет работать постоянно и будет следить за всеми файлами. Если произойдут какие- либо изменения среди файлов, эта команда составит новый график зависимостей.
Однако на этом этапе возникает уже первая сложность.
Поскольку мы взаимодействуем с конструкторами, то и компоненты создаются с их помощью. И используя Dio как клиент невозможно создать новый конструктор - отсутствует возможность аннотировать класс Dio как injectable. Именно поэтому используется модуль, который состоит из абстрактного класса, и чьи публичные методы воспринимаются как фабрики для создания компонентов.
Например, место, куда обращается репозиторий, может быть занято с помощью класса SettingsInterceptor. Поскольку он получает сеттингсервис, он вызывается заблаговременно.
Осуществляя запуск, в MoneyScreenModel инициализированы StatementService, в нем инициализирован statementRepository. Стоит понимать, что в statementRepository инициализирован клиент, в котором находятся два интерцептора. А в нем лежат SettingService и settingRepository.
Вот так выглядит созданный график:
Также рекомендуем присмотреться к процессу регистрации компонентов по названию. В нашем случае, мы обладаем двумя клиентами - settings и winter. Всего получилось 3 фабрики HTP клиента.
Тут вы можете видеть элементарный пример циклической зависимости. В этом случае ее невозможно решить ни одним простым способом. Однако, если поэкспериментировать и сделать циклическую зависимость длиннее, результат будет следующим:
Очень частая проблема каждого разработчика, который работает над клиентским приложением - это готовность сервера как минимум через несколько месяцев. В этом случае очень сильно помогает di контейнер.
Репозиторий должен быть заменен заглушками и mock в этом случае не поможет, поскольку он доходит аж до карточки лояльности.
Именно поэтому возникает необходимость в создании нового контейнера. В аннотации необходимо указать, что он должен создаваться для двух папок: lib и test. В нашем случае контейнер будет разрабатываться для обеих папок одновременно.
Очень важно добавлять фильтр при инициализации getit, чьим функционалом будет добавление компонентов без какой-либо аннотации или с аннотацией dev.
Важный нюанс - появились константы prod и dev, а также две новые фабрики - StatementRepository и StatementRepositoryMock.
Ниже представлены интеграционные тесты:
Заключение
Вышеописанный метод реализации dependency injection by codegen рабочий. Однако у него есть некоторый недостаток - это отсутствие модульности при регистрации и снятия с регистрации в скоупах. Однако эту проблему можно частично решить с помощью именованных фабрик и Environment.
Источник: innevia.tech