Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- swift custom ui
- swift bottomsheet
- task cancellation
- custom ui
- swift 점선
- domain data
- paragraph style
- UIKit
- 버튼 피드백
- RxSwift
- traits
- uikit toast
- task cancel
- DP
- identifiable
- button configuration
- SWIFT
- swift concurrency
- coordinator
- custombottomsheet
- reactorkit
- Tuist
- 타임라인 포맷팅
- swift navigationcontroller
- BFS
- swift 백준
- swift dashed line
- claen architecture
- custom navigation bar
- rxdatasources
Archives
- Today
- Total
김경록의 앱 개발 여정
[Clean Architecture] DTO와 도메인 모델의 차이와 분리해서 사용해야하는 이유 본문
소프트웨어 아키텍처를 설계하다 보면
DTO(Data Transfer Object)와 도메인 모델(Domain Model)이라는 용어를 자주 접하게 됩니다.
이 두 가지 개념은 비슷해 보일 수 있지만, 각자의 역할과 책임이 명확하게 구분되어 있습니다.
어느 순간 이 둘의 개념 명확히 분리하지 않고 사용하던 제 모습을 발견해서
오늘은 DTO와 도메인 모델의 차이점, 그리고 왜 이들을 분리해서 사용해야 하는지에 대해 알아봤습니다.
1. DTO (Data Transfer Object)
역할 및 특징
- 데이터 전송 전용: DTO는 주로 네트워크 요청/응답, API 통신, 데이터베이스 결과 등의 외부 시스템과의 데이터 교환에 사용됩니다.
- 단순 데이터 컨테이너: 비즈니스 로직이나 행동이 포함되지 않고, 오직 데이터를 담아 전달하는 역할만 수행합니다.
- 유연성: 외부 시스템의 변경(예: API 스펙 변경)에 민감하지만, 그 변경사항을 한 곳(DTO)에서만 관리하면 되므로 전체 시스템에 미치는 영향을 최소화할 수 있습니다.
사용 예시
struct UserDTO: Decodable {
let id: Int
let name: String
let email: String
}
위 예시에서 UserDTO는 API로부터 전달받은 JSON 데이터를 디코딩하기 위한 모델로 사용됩니다. 단순히 데이터를 전달할 목적(Data Carrier)으로 만들어졌기 때문에, 비즈니스 로직은 전혀 포함되어 있지 않습니다.
2. 도메인 모델 (Domain Model)
역할 및 특징
- 비즈니스 로직의 핵심: 도메인 모델은 애플리케이션의 핵심 비즈니스 로직과 규칙을 구현하는 객체입니다. 이는 단순히 데이터를 담는 역할을 넘어, 해당 데이터에 대한 행동과 연관된 규칙을 포함할 수 있습니다.
- 순수성 유지: 도메인 모델은 외부 시스템(네트워크, 데이터베이스 등)의 구현 세부사항과 분리되어 있어야 합니다. 이를 통해 비즈니스 로직은 외부 변화에 영향을 받지 않고, 독립적으로 유지보수될 수 있습니다.
- 구조화된 데이터: 여러 속성이나 복잡한 비즈니스 규칙이 결합되어 있을 때, 도메인 모델을 통해 이를 하나의 객체로 관리하면 코드의 가독성과 관리성이 향상됩니다.
사용 예시
struct User {
let id: Int
let name: String
let email: String
// 비즈니스 로직 예: 이메일 도메인 검사
func isCorporateEmail() -> Bool {
return email.hasSuffix("@company.com")
}
}
위 예시에서 User는 도메인 모델로, 사용자의 정보를 담을 뿐만 아니라, 특정 이메일 주소가 기업용 이메일인지 검사하는 비즈니스 로직을 포함하고 있습니다.
클린 아키텍처에서 DTO와 도메인 모델 분리의 필요성
테스트 용이성 및 유지 보수성 등 많은 이유가 있지만 가장 큰 이유는 클린 아키텍처의 본질과 같은 관심사의 분리 때문입니다.
관심사의 분리 (Separation of Concerns)
- DTO는 외부 시스템(API, 데이터베이스, 네트워크 등)과의 데이터 교환을 위해 존재합니다. 외부 응답 형식, JSON 스키마, 데이터베이스 레코드 구조 등을 그대로 반영하는 경우가 많습니다.
- 도메인 모델은 애플리케이션의 핵심 비즈니스 로직과 규칙을 캡슐화하는 객체입니다. 도메인 모델은 외부 시스템의 구현 세부사항과 무관하게, 순수한 비즈니스 요구사항만 반영해야 합니다.
- 이를 분리함으로써, 외부 시스템의 변경(예: API 스펙 변경)이 도메인 로직에 직접적인 영향을 주지 않도록 할 수 있습니다.
매핑 예시
struct UserDTO: Decodable {
let id: Int
let name: String
let email: String
}
// 도메인 모델 (Domain Layer)
struct User {
let id: Int
let name: String
let email: String
func isCorporateEmail() -> Bool {
return email.hasSuffix("@company.com")
}
}
//DTO
struct UserDTO: Decodable {
let id: Int
let name: String
let email: String
}
// DTO → 도메인 모델 변환
extension UserDTO {
func toDomain() -> User {
return User(id: id, name: name, email: email)
}
}
// Repository 예시 -> Domain Model
protocol UserRepository {
func fetchUser(with id: Int) -> Single<User>
}
final class UserRepositoryImpl: UserRepository {
func fetchUser(with id: Int) -> Single<User> {
return apiService.getUser(id: id)
.map { (response: UserDTO) in
return response.toDomain()
}
}
}
결론
도메인 모델 | DTO | |
역할 | 비즈니스 로직 포함 | API에서 받은 데이터의 전달(Data Carrier |
위치 | Domain Layer | Data Layer |
데이터 구조 | 앱 내부에서 최적화 된 상태 | API 응답 형식 그대로 유지 |
비즈니스 로직 포함 여부 | 있음 | 없음 |
API 응답 변경 시 영향 | 없음 | 있음 |
참조
'TIL' 카테고리의 다른 글
[Swift] Identifiable (0) | 2025.03.28 |
---|---|
[RxSwift] Single<Void> 와 Completable (0) | 2025.03.13 |
[Swift] 유튜브처럼 타임라인 포맷팅하기 (1) | 2025.03.10 |
[Swift UIKit] Button Configuration 사용 시 의도치않은 inset 줄이기 (0) | 2025.02.07 |
[Swift] 행간, 첫 줄 들여쓰기 등 적용하기 Paragraph Style (0) | 2025.01.13 |