--- marp: true --- # CherryPick 3.x ### Быстро. Безопасно. Просто. Современный DI-framework для Dart и Flutter Автор: Сергей Пеньковский --- ## Что такое CherryPick? - Лёгкий и модульный framework для внедрения зависимостей (DI) - Фокус: производительность, безопасность и лаконичный код - Применяется во frontend, backend, CLI --- ## Эволюция: что нового в 3.x? - Оптимизация скорости разрешения зависимостей - Интеграция с Talker для наглядного логирования DI-событий - Защита от циклических зависимостей на уровне ядра - Полностью декларативное описание DI через аннотации и генерацию кода - Автоматическая очистка ресурсов --- ## Быстро * Мгновенное разрешение зависимостей --- ### Мгновенное разрешение зависимостей - Операция resolve теперь выполняется за O(1) - Используется Map-индексация всех биндингов в каждом скоупе (в среднем ускорение в 10x+ на крупных графах) - Производительность не зависит от размера приложения --- ## Безопасно * Циклические зависимости больше не страшны * Интеграция с Talker и расширенное логирование --- ### Циклические зависимости больше не страшны - CherryPick 3.x автоматически выявляет циклы при разрешении зависимостей. - Возможна проверка как внутри отдельного scope, так и во всём DI-графе (глобально). --- #### Как включить проверку циклов - Для защиты только внутри одного scope: ```dart // 1. Для текущего scope (локальная проверка) final scope = CherryPick.openRootScope(); scope.enableCycleDetection(); ``` - Для защиты всей иерархии скоупов: ```dart // 2. Для всей иерархии скоупов (глобальная проверка) CherryPick.enableGlobalCycleDetection(); CherryPick.enableGlobalCrossScopeCycleDetection(); final rootScope = CherryPick.openRootScope(); ``` --- #### Пример обработки ошибки При обнаружении цикла будет выброшено исключение с подробной трассировкой: ```dart try { scope.resolve(); } on CircularDependencyException catch(e) { print(e.dependencyChain); } ``` ```bash === Circular Dependency Detection Example === 1. Attempt to create a scope with circular dependencies: ❌ Circular dependency detected: CircularDependencyException: Circular dependency detected for UserService Dependency chain: UserService -> OrderService -> UserService ``` --- ### Интеграция с Talker и расширенное логирование - Всё, что происходит в DI: регистрация, создание, удаление, ошибки ― теперь логируется! - Достаточно подключить observer: ```dart final talker = Talker(); final talkerLogger = TalkerCherryPickObserver(talker); CherryPick.setGlobalObserver(talkerLogger); ``` - Логи сразу видны в консоли, UI ```bash ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────── │ [info] | 9:41:33 89ms | [scope opened][CherryPick] scope_1757054493089_7072 └────────────────────────────────────────────────────────────────────────────────────────────────────────────── ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────── │ [verbose] | 9:41:33 90ms | [diagnostic][CherryPick] Scope created: scope_1757054493089_7072 {type: Scope, name: scope_1757054493089_7072, description: scope created} └────────────────────────────────────────────────────────────────────────────────────────────────────────────── ``` --- ## Просто * Декларативный DI * Автоматическая очистка ресурсов --- ### Декларативный DI: аннотации и генерация кода - Описывайте зависимости с помощью аннотаций - Автоматически генерируется модуль DI и mixin для автоподстановки зависимостей ```dart @module() abstract class AppModule extends Module { @provide() @singleton() Api api() => Api(); @provide() Repo repo(Api api) => Repo(api); } ``` Регистрация модуля ```dart final scope = openRootScope() ..installModules([$AppModule()]); ``` --- ### Field injection: минимум кода — максимум удобства ```dart @injectable() class MyScreen extends StatelessWidget with _$MyScreen { @inject() late final Repo repo; MyScreen() { _inject(this); } } ``` - После генерации mixin и вызова `screen._inject()` — зависимости готовы - Сильная типизация, никаких ручных вызовов resolve --- ## Автоматическая очистка ресурсов Автоматическая очистка ресурсов (контроллеры, потоки, сокеты, файлы и др.). Если вы регистрируете объект, реализующий Disposable, через DI-контейнер, CherryPick вызовет его метод dispose() при закрытии скоупа. ```dart class MyServiceWithSocket implements Disposable { @override Future dispose() async { await socket.close(); print('Socket закрыт!'); } } scope.installModules([ Module((bind) => bind().toProvide(() => MyServiceWithSocket()).singleton()), ]); await CherryPick.closeRootScope(); // дождётся завершения async очистки ``` --- ## Почему это удобно? ### Сравнение с ручным DI || Аннотации | Ручной DI | |:---|:-----------|:------------| |Гибко|✅|✅| |Кратко|✅|❌| |Безопасно|✅|❌ (легко ошибиться)| --- ## CherryPick 3.x: ваш DI-фреймворк - Быстрое разрешение зависимостей - Гарантия безопасности и тестируемости - Интеграция с логированием - Максимально простой и декларативный код --- ## Спасибо за внимание --- ## Вопросы? - Try CherryPick - [https://pub.dev/packages/cherrypick](https://pub.dev/packages/cherrypick) - Contributing — [https://github.com/pese-git/cherrypick](https://github.com/pese-git/cherrypick) - Документация и примеры — [https://cherrypick-di.netlify.app](https://cherrypick-di.netlify.app/) - Готов помочь — пишите, пробуйте, внедряйте!