Что такое цикличные зависимости
Что проверяют
Здесь вопрос не про память, а про архитектуру: видите ли вы во взаимной зависимости модулей проблему сборки и сопровождения. За ответом смотрят, разделяете ли вы уровни, на которых цикл ведёт себя по-разному: классы, граф внедрения зависимостей и модули Gradle.
Как отвечать
Цикличная зависимость это когда A использует B, а B прямо или по цепочке использует A. Последствия зависят от уровня.
Между модулями Gradle цикл запрещён жёстко, сборка падает с сообщением о круговой зависимости. Это и есть главный аргумент за многомодульность: она превращает нарушение слоёв в ошибку сборки, а не в вопрос дисциплины.
В графе внедрения зависимостей цикл ловит генератор кода при компиляции. Обход существует, зависимость запрашивается отложенно через провайдер, но это отсрочка создания, а не устранение цикла.
Внутри одного модуля компилятор взаимные ссылки классов пропускает, поэтому там цикл живёт годами и проявляется иначе: класс невозможно протестировать отдельно, а мелкая правка тянет за собой половину проекта.
Устраняется инверсией зависимости. Интерфейс объявляется на стороне потребителя или в общем модуле контрактов, реализация лежит ниже и подставляется при сборке графа. Для оповещения в обратную сторону хорошо работает поток событий: вместо прямого вызова назад публикуется событие. Иногда верный ответ проще: две сущности, которые не живут друг без друга, часто должны быть одной.
Где спотыкаются
Считают, что внедрение зависимостей само по себе убирает циклы. Оно меняет способ доставки, граф остаётся прежним, и генератор упадёт ровно на том же месте.
Разрывают цикл первым попавшимся приёмом, лишь бы собралось: отложенный провайдер, сервис-локатор, поле, заполняемое после конструктора. Связность остаётся, только теперь она обнаруживается в рантайме.
Выносят общий код в модуль-свалку с именем вроде common и считают задачу закрытой. Через полгода от него зависит всё, и слои снова не читаются.