Какое нарушение принципов SOLID встречается в Android и где?
Что проверяют
Умеете ли вы видеть принципы SOLID не в учебных примерах, а в реальном Android: в самом SDK и в типичном коде приложения. Следом обычно просят показать, как вы бы исправили одно из нарушений.
Как отвечать
Сильнее всего звучат примеры из самой платформы:
- SRP,
ActivityиFragment: исторически в них жили разметка, сеть, работа с базой, жизненный цикл и навигация. Отсюда классы на тысячи строк. Лечится выносом логики воViewModel, репозитории и use case; - SRP и ISP,
Context: один объект даёт доступ к ресурсам, файлам, базам, системным сервисам, запуску экранов и темам. Классу, которому нужна строка из ресурсов, приходится получать весьContext, и заодно появляется риск утечкиActivity; - ISP,
TextWatcher: три обязательных метода, хотя почти всегда нужен толькоafterTextChanged. Та же история сAnimator.AnimatorListener, для которого SDK добавилAnimatorListenerAdapter, а в Kotlin есть расширения вродеdoAfterTextChanged; - DIP, создание компонентов системой:
Activityсоздаёт фреймворк, в конструктор ничего не передать, поэтому класс сам тянет конкретные зависимости. Решение: DI через Hilt или Koin, для фрагментовFragmentFactory; - OCP, адаптер с
when (viewType): каждый новый тип ячейки меняет один и тот же адаптер. Лечится делегатами или отдельным классом на тип ячейки.
LSP в SDK встречается реже. В прикладном коде это наследник базового экрана или View, который молча игнорирует часть контракта родителя.
Jetpack во многом появился как ответ на эти проблемы: ViewModel, Lifecycle, Hilt, Navigation.
Где спотыкаются
Перечисляют пять принципов с определениями и без единого Android-примера. На этом вопросе интервьюер ждёт именно «где».
Считают, что ViewModel решает SRP сама по себе. На практике вся логика переезжает из Activity во ViewModel на две тысячи строк, и нарушение просто сменило адрес.
Путают DIP и DI. Инверсия зависимостей означает, что модуль верхнего уровня зависит от абстракции, а Hilt лишь инструмент, который подставляет реализацию. Можно пользоваться Hilt и при этом внедрять конкретный RetrofitUserApi вместо интерфейса.