클린 아키텍쳐(이하 CA), layered 아키텍쳐에서는 View 단에서 DTO를 바로 쓰지 않는다.
관심사 분리와 계층화(기타 등등 리팩토링)를 하기 전까지는 DTO를 바로 꽂아서 써도 불편함을 느끼지 않았지만, 점차 코드를 리팩토링하면서 DTO를 바로 쓰는 것이 아니라, View에서 필요한 정보만을 담은 별도의 Model로 매핑한 다음에 사용해야 함을 몸소 깨달았다.
개인적으로 느낀 그렇게 해야하는 이유가 몇가지 있는데 적어보겠다.
DTO는 서버 측에서 받아오는 Data Transfer Object이다. data layer의 모델 위치하며, 서버 개발자가 정의한 json을 바탕으로 kotlin data class로 정의하면 된다.
DTO는 주로 데이터 전송을 위해 설계된 객체이다.
json
{
"nickname": "jumukzzang"
}
kotlin data class
data class UserNicknameResponse (
@SerializedName("nickname" ) var nickname : String? = null
)
참고로 https://json2kt.com/ 사이트를 애용한다.
Entity는 앱의 도메인 계층(Domain Layer)에서 핵심 비즈니스 로직을 표현하는 데이터 모델이다.
이는 앱이 제공하는 주요 기능과 직접적으로 연결된 데이터를 의미하며, 비즈니스 규칙을 구현하거나 데이터의 상태를 표현하는 객체로 사용된다.
서버 개발의 관점에서 DTO는 같지만, 엔티티는 살짝 느낌이 다르다.
Entity는 DB 테이블에 존재하는 Column들을 필드로 가지는 객체이다.
특성 | Entity | DTO |
---|---|---|
목적 | 비즈니스 로직 및 데이터의 상태를 표현. | 데이터 전송 및 외부 시스템(API, DB 등)과의 데이터 교환을 위해 설계됨. |
위치 | 도메인 계층(Domain Layer)에 존재. | 데이터 계층(Data Layer)에서 주로 사용. |
의존성 | 앱 내 도메인에 종속. | API나 외부 데이터 소스의 구조에 종속. |
책임 | 비즈니스 규칙, 계산, 데이터 검증 등을 포함. | 외부 데이터의 전송 및 직렬화/역직렬화에 최적화. |
구조 변경 | 비즈니스 요구사항 변화에 따라 수정됨. | 외부 API의 변경에 따라 수정됨. |
사용 대상 | Use Case, ViewModel에서 주로 사용. | Repository, Service 계층에서 주로 사용. |
예시 | - 속도, 거리 계산 로직이 포함된 Bike 클래스. | - 서버 응답 데이터를 표현하는 BikeDto 클래스. |
뷰 전용 데이터 모델인 UI 모델 (또는 ViewModel)을 사용해 DTO 데이터를 뷰에 맞게 가공합니다.
DTO to Entity를 하기 위한 방법을 설명하겠다.
data class UserResponse(
val firstName: String,
val lastName: String,
val email: String
)
data class User(
val fullName: String,
val email: String
)
fun UserResponse.toUser(): UserUiModel {
return UserUiModel(
fullName = "$firstName $lastName",
email = email
)
}
class UserViewModel(private val userService: UserService) : ViewModel() {
val userUiState = MutableLiveData<UserUiModel>()
fun fetchUser() {
viewModelScope.launch {
val response = userService.getUserInfo()
response?.let {
userUiState.value = it.toUser()
}
}
}
}
DTO -> mapper -> Entitiy로의 흐름은 클린 아키텍처의 목표인 유지보수성, 테스트 용이성, 모듈화를 극대화합니다.