안드로이드 개발자의 Entity와 DTO에 대한 고찰

유진·2024년 11월 19일
0

클린 아키텍쳐(이하 CA), layered 아키텍쳐에서는 View 단에서 DTO를 바로 쓰지 않는다.

관심사 분리와 계층화(기타 등등 리팩토링)를 하기 전까지는 DTO를 바로 꽂아서 써도 불편함을 느끼지 않았지만, 점차 코드를 리팩토링하면서 DTO를 바로 쓰는 것이 아니라, View에서 필요한 정보만을 담은 별도의 Model로 매핑한 다음에 사용해야 함을 몸소 깨달았다.

개인적으로 느낀 그렇게 해야하는 이유가 몇가지 있는데 적어보겠다.

  1. DTO에 뷰에서는 불필요한 정보가 포함되어 있을 수 있다.
  2. 개방폐쇄(OCP)의 원칙에 따라 확장에 열려있고, 변경에는 닫혀있게 하기 위해서 이다.
    서버에서 DTO를 바꾼다고 해서 (사실 DTO를 수정하는 것은 매우 위험한 일이다.) presentation layer의 코드가 변경되어서는 안된다. 이를 막기위해서 둘을 분리하고, 매핑하는 작업이 필요하다.
  3. 계층 분리가 어렵다.
    presentation layer에서 data layer의 클래스를 알아야하는가?
    아니다. 몰라야한다. 계층분리를 안하다면 모르겠지만, 점점 커져가는 프로젝트의 규모와 유지보수를 생각하면 계층분리를 하는게 정신건강에 이롭다는걸 깨닫게 된다.
  4. 그냥 책임 자체가 다르다.
  • DTO: 외부 시스템(API, 데이터베이스 등)과의 데이터 교환에 최적화된 구조.
    예) JSON 형식의 데이터, API 응답/요청에 종속적.
  • 엔티티(Entity): 앱 내에서 데이터의 핵심 비즈니스 로직을 표현하는 도메인 객체.
    예) 비즈니스 규칙, 계산, 데이터 검증 등을 포함.

DTO

DTO는 서버 측에서 받아오는 Data Transfer Object이다. data layer의 모델 위치하며, 서버 개발자가 정의한 json을 바탕으로 kotlin data class로 정의하면 된다.

DTO는 주로 데이터 전송을 위해 설계된 객체이다.

  • DTO는 API 또는 데이터 소스와의 통신을 위한 목적으로 사용된다.
  • 뷰 단에서는 UI 상태 관리에 초점을 맞춰야 하며, 데이터 통신의 세부 사항을 알 필요가 없다.

json to kotlin

  • json

    {
      "nickname": "jumukzzang"
    }
  • kotlin data class

    data class UserNicknameResponse (
    
      @SerializedName("nickname" ) var nickname : String? = null
    
    )
  • 참고로 https://json2kt.com/ 사이트를 애용한다.


Entity

Entity는 앱의 도메인 계층(Domain Layer)에서 핵심 비즈니스 로직을 표현하는 데이터 모델이다.
이는 앱이 제공하는 주요 기능과 직접적으로 연결된 데이터를 의미하며, 비즈니스 규칙을 구현하거나 데이터의 상태를 표현하는 객체로 사용된다.

서버 개발자로서의 Entity

서버 개발의 관점에서 DTO는 같지만, 엔티티는 살짝 느낌이 다르다.

Entity는 DB 테이블에 존재하는 Column들을 필드로 가지는 객체이다.

  • DB의 테이블과 1대 1로 대응되며, 때문에 테이블이 가지지 않는 컬럼을 필드로 가져서는 안된다.
  • 다른 클래스를 상속받거나 인터페이스의 구현체여서는 안된다.

DTO vs Entity in Mobile

특성EntityDTO
목적비즈니스 로직 및 데이터의 상태를 표현.데이터 전송 및 외부 시스템(API, DB 등)과의 데이터 교환을 위해 설계됨.
위치도메인 계층(Domain Layer)에 존재.데이터 계층(Data Layer)에서 주로 사용.
의존성앱 내 도메인에 종속.API나 외부 데이터 소스의 구조에 종속.
책임비즈니스 규칙, 계산, 데이터 검증 등을 포함.외부 데이터의 전송 및 직렬화/역직렬화에 최적화.
구조 변경비즈니스 요구사항 변화에 따라 수정됨.외부 API의 변경에 따라 수정됨.
사용 대상Use Case, ViewModel에서 주로 사용.Repository, Service 계층에서 주로 사용.
예시- 속도, 거리 계산 로직이 포함된 Bike 클래스.- 서버 응답 데이터를 표현하는 BikeDto 클래스.

UI 모델과 매퍼 사용

뷰 전용 데이터 모델인 UI 모델 (또는 ViewModel)을 사용해 DTO 데이터를 뷰에 맞게 가공합니다.

DTO to Entity를 하기 위한 방법을 설명하겠다.

API에서 받아온 DTO:

data class UserResponse(
	val firstName: String,
	val lastName: String,
	val email: String
)

UI 모델 정의

data class User(
    val fullName: String,
    val email: String
)

매퍼(Mapping) 함수

fun UserResponse.toUser(): UserUiModel {
    return UserUiModel(
        fullName = "$firstName $lastName",
        email = email
    )
}

ViewModel에서 변환

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()
            }
        }
    }
}

장점

  1. 계층 독립성: UI 모델이 API 변경에 영향을 받지 않음.
  2. 테스트 용이성: 매핑 로직과 비즈니스 로직을 독립적으로 테스트 가능.
  3. 가독성: UI에 필요한 데이터를 명확히 정의.

DTO -> mapper -> Entitiy로의 흐름은 클린 아키텍처의 목표인 유지보수성, 테스트 용이성, 모듈화를 극대화합니다.

profile
안드로이드 학생 개발자 에디 / 유진입니다

0개의 댓글