На очередном митапе ОЭЗ "Иннополис" Flutter-разработчики поделились опытом эффективного использования возможностей фреймворка в больших проектах. В ходе митапа они раскрыли основные преимущества своих подходов, поделятся полезными инструментами в работе с web-приложениями.
Как показывает практика, в приложения, которые переходят на определенный новый уровень, редко добавляются новые экраны или модули. Однако в то же время, постоянно появляются специфические бизнес требования, которые должны быть соблюдены. И в этот момент у абсолютного каждого разработчика возникает вопрос: “Как добавить новые требования в приложение, чтобы оно не сломалось?”
Именно поэтому наша разработка приложений осуществляется на основе определенного подхода.
Ниже вы можете увидеть фрагмент дерева и маленький разобранный кусочек логики. Был использован WM подход, поэтому можно считать, что это элемент интерфейса.
Для добавления новых требований нам нужен StatementService - сервис, в котором находятся методы для работы с выписками и состоянием счета пользователя. Также нужен StatementRepository, чтобы подключиться к бэкграунду. Клиент и провайдер нам тоже нужен для реализации нашей затеи. В нашем случае это Dio и Interceptor соответственно.
В этой статье мы рассмотрим Dependency Injection для Dart и Flutter проектов. Мы расскажем о том, как сделать Dependency Injection декларативным (самогенерируемым) и при этом сохранить человеко-читабельность, как подменить компоненты при тестировании и как изолируются моки от production-кода.
![](https://habrastorage.org/getpro/habr/upload_files/420/068/1ea/4200681ea52c9d993c7abf1a4e7d5ec8.png)
Реализация
Для реализации dependency injection by codegen необходимо 4 разных пакета - get_it, injectable, injectable_generator и build_runner (два последних - это dev зависимости).
![](https://habrastorage.org/getpro/habr/upload_files/115/13a/fe7/11513afe7f9f6610de1b2719a0d4afe1.png)
![](https://habrastorage.org/getpro/habr/upload_files/729/611/3cf/7296113cf972eac9d531c444d617555a.png)
Если использовать метод main для разработки флаттера приложения, то стоит помнить, что используется метод графических зависимостей. Это означает, что график зависимостей будет готов еще до готового флаттера приложения. И в нем уже будет находиться бизнес логика с ее компонентами.
Следующим этапом реализации dependency injection by codegen является выполнение команды:
![](https://habrastorage.org/getpro/habr/upload_files/083/932/46f/08393246f8152674491f036ed156d4f2.png)
Чтобы выполнить эту команду, нужно запустить build_runner с условием watch - эта команда просмотрит все файлы и составит график зависимостей. Прелестью этой команды является то, что она будет работать постоянно и будет следить за всеми файлами. Если произойдут какие- либо изменения среди файлов, эта команда составит новый график зависимостей.
![](https://habrastorage.org/getpro/habr/upload_files/597/60a/294/59760a29483b8853e949d92d25c77cec.png)
Однако на этом этапе возникает уже первая сложность.
Поскольку мы взаимодействуем с конструкторами, то и компоненты создаются с их помощью. И используя Dio как клиент невозможно создать новый конструктор - отсутствует возможность аннотировать класс Dio как injectable. Именно поэтому используется модуль, который состоит из абстрактного класса, и чьи публичные методы воспринимаются как фабрики для создания компонентов.
![](https://habrastorage.org/getpro/habr/upload_files/a6f/ead/856/a6fead85675b86942dbb727b72465a9b.png)
Например, место, куда обращается репозиторий, может быть занято с помощью класса SettingsInterceptor. Поскольку он получает сеттингсервис, он вызывается заблаговременно.
Осуществляя запуск, в MoneyScreenModel инициализированы StatementService, в нем инициализирован statementRepository. Стоит понимать, что в statementRepository инициализирован клиент, в котором находятся два интерцептора. А в нем лежат SettingService и settingRepository.
Вот так выглядит созданный график:
![](https://habrastorage.org/getpro/habr/upload_files/b43/ea8/81d/b43ea881db895c050ab4d852b0aed628.png)
Также рекомендуем присмотреться к процессу регистрации компонентов по названию. В нашем случае, мы обладаем двумя клиентами - settings и winter. Всего получилось 3 фабрики HTP клиента.
![](https://habrastorage.org/getpro/habr/upload_files/f1e/03a/b43/f1e03ab437ae3943d4475c384f26ec80.png)
Тут вы можете видеть элементарный пример циклической зависимости. В этом случае ее невозможно решить ни одним простым способом. Однако, если поэкспериментировать и сделать циклическую зависимость длиннее, результат будет следующим:
![](https://habrastorage.org/getpro/habr/upload_files/129/184/de5/129184de54916de360b25fb057c3280c.png)
Очень частая проблема каждого разработчика, который работает над клиентским приложением - это готовность сервера как минимум через несколько месяцев. В этом случае очень сильно помогает di контейнер.
Репозиторий должен быть заменен заглушками и mock в этом случае не поможет, поскольку он доходит аж до карточки лояльности.
![](https://habrastorage.org/getpro/habr/upload_files/4de/c0c/f20/4dec0cf20589a29c01f52b815ffd14a8.png)
Именно поэтому возникает необходимость в создании нового контейнера. В аннотации необходимо указать, что он должен создаваться для двух папок: lib и test. В нашем случае контейнер будет разрабатываться для обеих папок одновременно.
Очень важно добавлять фильтр при инициализации getit, чьим функционалом будет добавление компонентов без какой-либо аннотации или с аннотацией dev.
![](https://habrastorage.org/getpro/habr/upload_files/5aa/35b/c98/5aa35bc987b4df59fce019ff71c3871e.png)
![](https://habrastorage.org/getpro/habr/upload_files/c79/e68/90a/c79e6890a574275a6262d3380e70666c.png)
Важный нюанс - появились константы prod и dev, а также две новые фабрики - StatementRepository и StatementRepositoryMock.
Ниже представлены интеграционные тесты:
![](https://habrastorage.org/getpro/habr/upload_files/181/a34/9df/181a349df72124205ee5453b2d692afd.png)
![](https://habrastorage.org/getpro/habr/upload_files/41a/bee/ad9/41abeead9e42b7bb761ced37510f71b8.png)
![](https://habrastorage.org/getpro/habr/upload_files/615/95e/bb5/61595ebb564a13a57926e5245394a61c.png)
Заключение
Вышеописанный метод реализации dependency injection by codegen рабочий. Однако у него есть некоторый недостаток - это отсутствие модульности при регистрации и снятия с регистрации в скоупах. Однако эту проблему можно частично решить с помощью именованных фабрик и Environment.
Источник: innevia.tech