Почему не стоит хранить все зависимости в одном компоненте Dagger

Ответ

Хранение всех зависимостей в одном компоненте Dagger приводит к нескольким проблемам:

  1. Производительность - при каждом изменении графа зависимостей пересобирается весь компонент, что замедляет сборку.

  2. Читаемость - большой монолитный компонент сложно поддерживать и понимать.

  3. Избыточность - зависимости могут создаваться даже когда они не нужны.

Лучше разбивать на логические подкомпоненты:

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
    fun sessionComponent(): SessionComponent.Factory
}

@SessionScope
@Subcomponent(modules = [SessionModule::class])
interface SessionComponent {
    @Subcomponent.Factory
    interface Factory {
        fun create(): SessionComponent
    }
}

Такой подход улучшает модульность, ускоряет инкрементальные сборки и делает код чище.

Ответ 18+ 🔞

А, ну это классика, блядь! Смотри, как обычно бывает: сидит чувак, пишет приложение, и ему в голову приходит гениальная идея — а давай-ка я все свои зависимости, все эти сервисы, репозитории и прочую хуету, засуну в один здоровенный компонент Dagger! Ёпта, удобно же — всё в одном месте, как в большой сумке!

И вроде бы работает, но потом начинается пиздец. Представь: ты меняешь одну маленькую зависимость в модуле авторизации, а компилятор начинает пересобирать весь этот монстр-компонент, от корки до корки. Это как если бы у тебя спустило колесо на машине, а ты разбираешь весь двигатель, чтобы его подкачать. Овердохуища времени уходит, терпения ноль ебать!

И читать этот код — это отдельный вид ебушки-воробушки. Открываешь файл на 500 строк, а там такая каша из @Provides и @Binds, что глаза разбегаются. Хуй поймёшь, где что лежит и зачем. Чистая манда с ушами, а не архитектура.

А самое смешное, что половина этих зависимостей может вообще не понадобиться в конкретном сценарии. Но они всё равно создаются, как будто на дворе 2002-й год и ресурсов дохуя. Зачем тебе в сплеш-скрине инжектить модуль работы с базой данных? Да похуй, создадим на всякий случай!

Так делать — это вы ходите по охуенно тонкому льду. Рано или поздно всё накроется медным тазом.

Вот смотри, как умные люди делают. Берут и разбивают этот монолит на логические куски — подкомпоненты.

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
    // Не создаём всё сразу, а даём фабрику для создания SessionComponent, когда он понадобится
    fun sessionComponent(): SessionComponent.Factory
}

// Отдельная область видимости для всего, что связано с сессией пользователя
@SessionScope
@Subcomponent(modules = [SessionModule::class])
interface SessionComponent {
    @Subcomponent.Factory
    interface Factory {
        fun create(): SessionComponent
    }
}

В чём прикол? Сам от себя охуел, когда понял.

  1. Скорость. Изменил что-то в сессионных модулях? Пересобирается только SessionComponent. Основной AppComponent остаётся нетронутым. Инкрементальные сборки летают.
  2. Порядок. Каждый компонент отвечает за свою зону. В AppModule — глобальные штуки вроде Retrofit или SharedPreferences. В SessionModule — всё, что нужно авторизованному пользователю. Никакой хитрой жопы, всё на своих местах.
  3. Эффективность. SessionComponent создаётся только когда пользователь залогинился. Пока он на экране логина — этих зависимостей просто не существует. Не тратятся память и процессорное время.

В общем, чувак, мораль проста: не лепи всё в одну кучу. Дели граф зависимостей на осмысленные части, и жить станет проще, а код перестанет быть пиздопроебибной кашей. Поверь, оно того стоит.