Circuit을 사용하면서, Circuit Navigation 사용 시 feature 모듈간의 참조 문제가 있었는데, 팀원인 지훈님이 해결한 코드를 보고 어떻게 해결했는지 분석해보고자 한다!
Circuit에 대한 분석, 지훈님 블로그 참고
https://velog.io/@mraz3068/Circuit-Try-Out 
자세한 내용 및 코드는 아래 PR 참고
https://github.com/YAPP-Github/Reed-Android/pull/39
Circuit에서 Screen은 해당 화면을 식별하는 key 역할을 하며, 다음과 같은 역할을 한다
Compose Navigation과는 달리, Circuit에서는 Screen 객체가 하나의 진입점이며 이에 맞춰 Presenter, UI, 상태(State), 이벤트(Event)가 연결된다
📦 feature
 ├── 📂 home
 │    ├── HomePresenter.kt
 │    └── HomeScreen.kt  // 내부에 UiState + Event 중첩 정의됨
feature:home 모듈의 HomeScreen.kt파일 내 HomeScreen 정의는 다음과 같이 구현되어 있었다
// 식별자 역할을 하는 Screen
@Parcelize
data object HomeScreen : Screen {
	// Screen 내부에 State와 Event가 중첩
    data class State(
        val eventSink: (Event) -> Unit,
    ) : CircuitUiState
    sealed interface Event : CircuitUiEvent
}
// Composable UI
@CircuitInject(HomeScreen::class, ActivityRetainedComponent::class)
@Composable
internal fun Home(
    state: HomeScreen.State,
    modifier: Modifier = Modifier,
) {
    Column(
        modifier = modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center,
    ) {
        HomeContent(
            state = state,
            modifier = modifier,
        )
    }
}
navigator.goTo(HomeScreen)과 같은 코드를 호출할 경우 직접적인 참조를 갖게 된다📦 feature
 ├── 📂 home
 │    ├── HomePresenter.kt
 │    ├── HomeUiState.kt
 │    └── HomeScreen.kt 
 └── 📂 screens
     └── ReedScreen.kt
1. feature:screens 모듈에 추상화된 ReedScreen 정의
abstract class ReedScreen(val name: String) : Screen {
    override fun toString(): String = name
}
@Parcelize
data object HomeScreen : ReedScreen(name = "Home()") // HomeScreen이 ReedScreen을 상속
2. feature:home의 HomeUiState.kt에서 UiState/UiEvent 정의 
data class HomeUiState(
    val eventSink: (HomeUiEvent) -> Unit,
) : CircuitUiState
sealed interface HomeUiEvent : CircuitUiEvent {
    data object OnOcrButtonClicked : HomeUiEvent
}
3.HomePresenter.kt에서는 screens 모듈만 참조한다
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import com.ninecraft.booket.screens.HomeScreen
import com.ninecraft.booket.screens.OcrScreen // screens 모듈 참조
import com.slack.circuit.codegen.annotations.CircuitInject
import com.slack.circuit.runtime.Navigator
import com.slack.circuit.runtime.presenter.Presenter
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.components.ActivityRetainedComponent
@Suppress("unused")
class HomePresenter @AssistedInject constructor(
    @Assisted private val navigator: Navigator,
) : Presenter<HomeUiState> {
    @Composable
    override fun present(): HomeUiState {
        fun handleEvent(event: HomeUiEvent) {
            when (event) {
                is HomeUiEvent.OnOcrButtonClicked -> {
                    navigator.goTo(OcrScreen)
                }
            }
        }
        return HomeUiState(
            eventSink = ::handleEvent,
        )
    }
    @CircuitInject(HomeScreen::class, ActivityRetainedComponent::class)
    @AssistedFactory
    fun interface Factory {
        fun create(navigator: Navigator): HomePresenter
    }
}