1. FSD란 무엇인가?
Feature-Sliced Design(FSD)은 프로젝트를 기능 중심으로 구조화하여 유지보수성과 확장성을 높이는 방법론입니다. 기존 계층 기반 아키텍처(MVVM, 클린 아키텍처)와 달리 기능 단위로 모듈을 나누고, 관련된 코드(UI, 비즈니스 로직, 데이터 등)를 한 곳에 배치하는 방식을 따릅니다. 이를 통해 코드의 응집도를 높이고, 기능 단위의 독립성을 유지할 수 있습니다.
FSD는 여러 계층으로 구성되며, 각 계층이 서로 긴밀히 연결됩니다. 각 계층이 어떻게 상호작용하는지를 이해하는 것이 중요합니다. 이제 FSD의 핵심 계층을 살펴보고, 하나의 기능을 중심으로 이 계층들이 어떻게 유기적으로 연결되는지 예제를 통해 설명하겠습니다.
2. FSD의 핵심 계층
1) App Layer (앱 레이어)
앱 레이어는 애플리케이션의 진입점이며, 전체적인 설정과 글로벌 구성을 담당합니다. 앱이 시작될 때 필요한 초기 설정을 처리하며, Application 클래스, 네비게이션 설정, 의존성 주입(DI) 등의 요소가 이 레이어에 포함됩니다.
예를 들어, Koin을 사용하여 의존성을 주입하는 경우, 앱 레이어에서 이를 초기화할 수 있습니다.
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
modules(listOf(appModule, featureModule, networkModule))
}
}
}
이러한 초기화 과정이 있으면 애플리케이션이 실행될 때 필요한 의존성을 자동으로 주입받을 수 있습니다.
2) Pages Layer (페이지 레이어)
페이지 레이어는 사용자가 접근하는 주요 화면을 구성하는 역할을 합니다. 이 레이어는 여러 기능(Feature)과 위젯(Widget)을 조합하여 화면을 구성합니다. 페이지 레이어의 역할은 개별 기능을 조립하여 사용자가 상호작용할 수 있는 완전한 UI를 제공하는 것입니다.
예제에서는 로그인 페이지를 구성하는 코드를 보여줍니다.
@Composable
fun LoginPage(viewModel: LoginViewModel, navController: NavController) {
val state by viewModel.uiState.collectAsState()
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
Text(text = "Login", style = MaterialTheme.typography.h4)
Spacer(modifier = Modifier.height(16.dp))
CustomTextField(value = state.username, onValueChange = viewModel::onUsernameChange, label = "Username")
CustomTextField(value = state.password, onValueChange = viewModel::onPasswordChange, label = "Password", isPassword = true)
CustomButton(text = "Login", onClick = { viewModel.login(navController) })
if (state.isLoading) {
CircularProgressIndicator()
} else if (state.errorMessage != null) {
Text("Error: ${state.errorMessage}", color = Color.Red)
}
}
}
3) Features Layer (기능 레이어)
기능 레이어는 개별 기능을 독립적으로 관리하며, UI, 비즈니스 로직, 데이터 처리를 포함합니다. 예를 들어, 로그인 기능을 담당하는 LoginFeature는 ViewModel, UseCase, Repository 등을 포함할 수 있습니다.
class LoginViewModel(private val loginUseCase: LoginUseCase) : ViewModel() {
private val _uiState = MutableStateFlow(LoginUiState())
val uiState: StateFlow<LoginUiState> = _uiState
fun login(navController: NavController) {
viewModelScope.launch {
_uiState.value = _uiState.value.copy(isLoading = true)
val result = loginUseCase.execute(_uiState.value.username, _uiState.value.password)
if (result.isSuccess) {
navController.navigate("home")
} else {
_uiState.value = _uiState.value.copy(isLoading = false, errorMessage = result.exceptionOrNull()?.message)
}
}
}
}
4) Widgets Layer (위젯 레이어)
위젯 레이어는 여러 기능에서 재사용할 수 있는 공통 UI 컴포넌트를 포함하는 레이어입니다. 예를 들어, 로그인 페이지에서 사용된 CustomButton과 CustomTextField는 위젯 레이어에서 관리됩니다.
@Composable
fun CustomButton(text: String, onClick: () -> Unit) {
Button(
onClick = onClick,
modifier = Modifier.fillMaxWidth().padding(8.dp)
) {
Text(text, fontSize = 16.sp, fontWeight = FontWeight.Bold)
}
}
@Composable
fun CustomTextField(value: String, onValueChange: (String) -> Unit, label: String, isPassword: Boolean = false) {
TextField(
value = value,
onValueChange = onValueChange,
label = { Text(label) },
visualTransformation = if (isPassword) PasswordVisualTransformation() else VisualTransformation.None,
modifier = Modifier.fillMaxWidth().padding(8.dp)
)
}
5) Shared Layer (공유 레이어)
공유 레이어는 여러 기능에서 공통으로 사용되는 유틸리티, API 클라이언트, 데이터 모델 등을 포함하는 레이어입니다. 예를 들어, Retrofit을 사용한 네트워크 클라이언트는 공유 레이어에서 관리할 수 있습니다.
object RetrofitClient {
private val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com")
.addConverterFactory(GsonConverterFactory.create())
.client(OkHttpClient.Builder().build())
.build()
val api: ApiService = retrofit.create(ApiService::class.java)
}
3. 결론
FSD의 각 계층을 살펴보고, 간단한 코드를 통해 각 계층의 역할을 설명했습니다. FSD는 기능 중심의 코드 구조를 제공하여 확장성과 유지보수성을 높이는 강력한 아키텍처 패턴입니다. 기존의 MVVM, 클린 아키텍처에서 명확하지 않았던 부분을 보완하면서도, 실무에서 적용하기 쉬운 가이드를 제공합니다.
이제 FSD의 각 계층의 역할을 이해했으니, 다음 글에서는 실제 프로젝트에서 FSD를 어떻게 적용할 수 있는지에 대해 살펴보겠습니다.
'SW 개발 일반 > 아키텍처' 카테고리의 다른 글
(1) FSD란 무엇인가? (0) | 2025.02.08 |
---|---|
클린 아키텍처란 무엇인가? (0) | 2025.01.16 |