Сегодня я буду вам рассказывать про DI
Поговорим о некоторых концепциях, которые нам нужны в работе:
Dependency inversion(SOLID): верхний уровень не должен зависеть от нижнего, оба от абстракций абстракции не зависят от деталей, а наоборот
По факту, мы хотим писать слабо зацепленный код, и для этого на каждой границе взаимодействия, мы конструируем абстракции: интерфейсы и контракты
На уровне кода это проявляется в следующей концепции
- не должно быть ручных конструирований конкретных имплементаций внутри других имплементаций
Дополнительно существует inversion of control -- инверсия управления, попытка возложить на фреймворк тяготы по управлению программой, давая программисту конкретное апи для внедрения своего кода
Код вызываем не мы, а фреймворк, потому и теряется управление
То есть мы не сможем ручками сконструировать имплементации внутри другой, за нас это сделает фреймворк исходя из наших настроек
Тут то на сцену и выходит Dependency injection
DI -- Dependency injection -- Внедрение зависимостей -- делегирование создания модульных зависимостей более релевантному механизму
То есть, объект не заботится о своих зависимостях, а работает так, будто ему их любезно предоставили.
В случае с ООП понятно, что происходит: существует некоторый контейнер, называемый di контейнер или ioc контейнер, который содержит интерфейсы и конкретные имплементации, выдающий инстансы имплементаций по требованию
Существует 3 варианта установки зависимостей:
- конструкторы -- является предпочтительным, поскольку явно определяет контракт на создание компонента
- сеттеры
- свойства
Но это ООП. А у нас JS с цирком
Пример с None Di отсутствует, мы жестко завязаны на реализацию Date.now, не выполняется D из Solid Да и тестировать это сложно: нам придется черной магией aka spyOn(dyn import) заставить Date.now возвращать то, что нам нужно И тут мы играем в русскую рулетку, потому что spyOn(dyn import) очень сильно полагается на то, что он может мутировать какую-то часть кода, заменяя её на что-то свое. Это требует __esModules, которые везде реализованы по разному spyOn(dyn import) может сломаться в любой момент, и с ним связано достаточно неочевидных вещей
Но мы же стараемся в ФП, а в ФП есть понятие чистой функции, функции зависящей только от аргументов Давайте вынесем эту зависимость в аргумент-пропс Вариант хороший, даже тестируемый, но очень громоздкий Нам приходится везде явно прописывать аргументы, где-то их можно забыть или прокинуть не то Это не очень приятно
И тут на помощь к нам приходит контекст! React контекст имитирует {} в js (то есть область видимости) Он позволяет сделать зависимость общей, явной и заменяемой, что в свою очередь положительно сказывается как на опыте разработчика, так и на тестировании И поскольку в тестировании мы не полагаемся на динамичные штучки, тесты становятся более стабильными А заменять правила и имплементации становится проще некуда
А еще:
- площадь удара бага