tgoop.com/dev_easy_notes/282
Last Update:
⚖️ Когда нужно использовать статику
Недавно ко мне прилетел вопрос, касательно того как правильно делать логирование. Нужно ли делать логер статичным или же инжектить его везде через DI?
Вообще этот вопрос часто может возникнуть у начинающих разрабов, которые только изучили концепцию DI. Я по себе помню, что как только знакомишься с этим паттерном, в твоих руках он превращается в молоток, а ты везде начинаешь видеть гвозди. DI далеко не панацея и есть много мест в коде, где этот паттерн не приносит пользы, а наоборот делает код сложнее в поддержке.
И вот топ 3 вещей которые обязаны делаться через статику:
📜Логирование/Аналитика. Мне досталось одна либа, в которой логирование было сделано именно через DI. Каждый раз когда мне нужно было писать лог, приходись прикидывать логер через конструктор, это максимальное неудобное убожество.
Суть логера в том, что он должен быть доступен в любой части программы, независимо от слоя UI/Presenter/Domain. Может возникнуть вопрос, а как тогда быть, если логер нужно подменить, например заменить в релизной сборке. Идем и смотрим как это сделано в Timber. Либа предоставляет возможность подменить реализацию во время инициализации приложения через статические методы. Устанавливаете нужный логер вначале и потом не парите голову.
С аналитикой ровно тоже самое. Аналитика также должна быть доступна из любой части программы без возни с DI. Как быть если у нас несколько систем или нужно будет заменять их в будущем? Во-первых, мы фигово предсказываем будущее, а во-вторых делайте также как Timber.
🖼 Загрузка картинок. Вот это вообще такая вещь на грани, вот почему. Очевидно что смешивать View и DI затея не самая удачная. Потому как у вас View становятся зависимы от вашего DI, помимо этого важно с самим DI не закосячить в плане скоупов и ЖЦ View, так еще это и максимально неудобно в коде.
При этом с другой стороны тут у нас network слой, что означает что его по-хорошему контролировать. Подсовывать нужные там proxy, или отслеживать куда трафик идет, возможно как-то хитро подменять url или добавлять заголовки к запросам на картинки. Должна быть возможность это все конфигурировать и подменять это все для разных фичей.
Тут на самом деле, даже и думать не придется, потому как все либы для работы с картинками работают по одному и тому же принципу. Для примера можно взять coil. По умолчанию используется один и тот же экземпляр загрузчика, который можно сконфигурировать при старте приложения. Если же нужен другой загрузчик, можно прям на месте загрузки сконфигурировать свой и подсунуть в туже же самую функцию.
⛓Dispatchers/Schedulers. Раньше почти на каждом проекте был следующий подход. Мы не используем библиотечные шедулеры (вроде Schedulers.io()
, Schedulers.computation()
) а сделаем интерфейс:
interface Schedulers{
fun io():Schedulers
fun computation():Schedulers
}
Затем как вы уже поняли инжектим этот интерфейс везде где у нас есть асинхронные вызовы. Нужно это для тестирования, ведь теперь максимально удобно взять и подменить шедулеры на тестовые.
Идея дурацкая по двум причинам: первое как я уже писал в посте про тестирование, лучше ничего не подменять и тестировать в условиях реальной работы. Иначе в тестах на одном потоке все прекрасно, а в проде гонка и плавающие баги, второе это просто бесячее дублирование в каждом классе с асинхронщиной, что по сути везде кроме UI.
Ну а что делать если подменять все таки нужно? Если RX, то ничего делать не нужно, он из коробки позволяет подменять стандартные шедулеры. Корутины к сожалению такого не умеют, однако это можно сделать через статику. Делаем класс, который по умолчанию возвращает библиотечные реализации диспетчеров, а в тестах эту статику меняем. Единственный минус, что важно теперь следить чтобы все использовали этот самый класс для получения диспетчеров, который мы договорились использовать.
BY Dev Easy Notes
Share with your friend now:
tgoop.com/dev_easy_notes/282