티스토리 뷰

이전 글: 앱 구조 설계하기
관련 Git Pull Request: https://github.com/helloworldjay/daumcafesearch/pull/7
[DaumCafeSearch 앱] 앱 구조 설계하기
이전 글: 프로젝트를 시작하며 구조 설계하기 앞선 글에서 언급한 것처럼, 프로젝트를 MVVM 구조로 설계를 진행했어요. MVVM은 무엇이 다른가? 설계에 앞서 구조에 대해 MVVM의 이론에 대해 학습을
jayb-log.tistory.com
Model 정의하기
MVVM에서 모델의 개념을 이해할 때 Data Store의 역할로 생각했어요.
"데이터에 관한 처리를 맡는 객체" 정도로 이해를 했는데, 실제로 프로젝트들을 살펴보니 Model이라는 디렉터리 하에 있는 것들은 대부분 DTO에 가까웠어요.
물론 구조가 복잡해지고 처리해야할 데이터가 많아질수록 그 데이터를 가지고 있고, 데이터 처리와 연관된 작업을 담당하는 독립된 객체의 필요성이 커질 수 있다고 생각해요.
하지만 검색한 대부분의 프로젝트가 토이 프로젝트 수준이고, 이번에 진행하는 프로젝트 역시 규모가 작다 보니 "모델"이라는 이름에 포함되는 개념은 DTO로 충분하다고 판단했어요.
Entity 구현하기
우선 Decoding을 위해 ObjectMapper를 사용할 지, Decodable을 사용할지 고민했어요.
현업에서는 ObjectMapper를 사용했었는데, Codable을 사용하지 않고 ObjectMapper를 사용하는 선택 기준이 궁금해 히스토리를 검색해보고 팀원들과 대화해봤었어요.
그 과정에서 읽었던 글들이 있는데, 그 중 하나가 War on JSON in Swift라는 글이에요.
결론은 "기능상의 큰 차이가 없다"로 났었는데, GitHub에서 프로젝트를 살펴보면 ObjectMapper를 사용한 경우도, Codable을 사용한 경우도 있었어요.
레거시가 ObjectMapper로 구현되어있거나 ObjectMapper가 특별히 필요한 상황이 아니라면 Swift 기본 기능인 Codable을 사용하는 것이 더 낫다고 판단해서 Codable을 사용했어요.
또한 현 프로젝트에서 Encoding하여 Post 하는 기능은 구현 계획이 없기 때문에 굳이 Codable일 필요가 없다고 판단했어요. 그래서 Decodable을 채택해서 Entity를 구현했어요.
마지막으로 당연히 JSON에서 키 값이 Snake Case로 된 네이밍들을 Swift에 맞게 Camel Case로 변경했어요.
Entity가 아닌 Model이 추가로 필요한가?
이 PR에서 가장 고민했던 부분이에요.
다른 프로젝트에서 경험했을 때에는 API에서 제공받은 JSON에 앱에서 필요하지 않은 정보가 있는 경우가 많았어요. Kakao API에서 제공하는 카페 검색 결과에는 딱 필요한 정보만 존재했어요. 물론, 그걸 전부 사용하려는 의도도 있었지만요 :]
제가 구현한 DaumCafeArticle은 아래와 같아요.
struct DaumCafeArticle: Decodable {
let cafeName: String
let content: String
let dateTime: Date
let thumbnail: String
let title: String
let url: String
enum CodingKeys: String, CodingKey {
case cafeName = "cafename"
case content = "contents"
case dateTime = "datetime"
case thumbnail
case title
case url
}
}
다음은 앱에서 사용할 구조체인 CafeArticle이에요.
struct CafeArticle {
let cafeName: String?
let content: String?
let datetime: Date?
let thumbnailURL: URL?
let title: String?
let url: URL?
}
구조를 언뜻 보면 매우 흡사해요. 프로퍼티의 개수와 내용이 완전히 같기 때문이죠!
그래서 "CafeArticle로 변환하지 않고 DaumCafeArticle로 사용해도 되지 않나?"라는 생각이 들 수 있어요.
그런데 저는 몇 가지 이유로 CafeArticle을 구현하기로 했어요.
1. 앱의 기능이 API에서 받아오는 JSON에 독립적이어야 한다.
가장 중요한 이유라고 생각해요.
팀원들과 외부 라이브러리 사용과 API 접근에 대해 이야기한 적이 있어요. 외부 의존도가 높아진다면 외부에서 변화가 생겼을 때 대응할 것이 많아진다는 의미이고, 앱의 유지보수에 부담이 간다는 대화였어요.
이 선택에서 그 이야기를 근거로 삼았어요.
만약 Kakao API에서 변경점이 생겨 제공받는 JSON이 달라진다면, DTO와 Entity -> Model의 변경점에서만 코드 수정이 일어나면 돼요. 그런데 만약에 앱 내에서 JSON의 정보를 모두 사용한다는 이유로 Entity를 그대로 가져다 쓴다면 변경에 대해서 앱 내의 모든 기능에 접근해서 변경을 해야 돼요.
그래서 외부 의존성을 줄이기 위해서라도 비슷한 구조의 Model 객체를 갖게 하는 것이 맞다고 판단했어요.
2. 요소들의 타입이 전부 같은 것은 아니다.
우선, 옵셔널 여부예요. API에서 받아오는 정보는 Optional이 없기 때문에 nil의 가능성이 없지만 앱 내에서 사용될 때에는 URL 등의 변환이 필요하기 때문에 nil의 가능성이 있어요.
또 받아온 데이터를 URL 등으로 타입 변환해야 하기 때문에, 매번 데이터에 접근할 때마다 타입 변환 작업이 추가된다면 가독성 측면에서 크게 안 좋다고 생각했어요.
3. 의도에 맞지 않는 사용처
DaumCafeArticle은 Decodable을 채택해요. 그렇기 때문에 DTO로서 역할한다는 사실을 명확히 알 수 있어요.
그런데 사용 가능하다는 이유로 앱 내에서 모델처럼 사용한다면 DaumCafeArticle이라는 구조체가 여러 가지 역할을 갖게 된다고 판단했어요. 기능상에 가능하더라도 단일한 역할과 책임을 갖게 하기 위해 CafeAriticle이라는 모델을 추가해야 된다고 판단했어요.
'iOS 앱개발 > Daum Cafe 검색 앱 프로젝트' 카테고리의 다른 글
[iOS] 배열의 요소 안전하게 접근하기 (0) | 2022.01.03 |
---|---|
[DaumCafeSearch 앱] 네트워크 기능 구현하기 (0) | 2022.01.03 |
[DaumCafeSearch 앱] 앱 구조 설계하기 (0) | 2022.01.02 |
[DaumCafeSearch 앱] 프로젝트를 시작하며 (0) | 2022.01.01 |
- Total
- Today
- Yesterday
- django
- 텀 프로젝트#백준알고리즘#Python
- 종이자르기#분할정복#BOJ#Python
- 암호코드#dp#BOJ#Python
- 리모컨#완전탐색#BOJ#Python
- 섬의개수#백준알고리즘#Python
- 랜선자르기#이분탐색#BOJ#Python
- Brackets#Stacks and Queues#Codility#Python
- 쿼드트리#BOJ#분할정복#Python
- API#lazy#
- Triangle#Sorting#Codility#Python
- 공유기 설치#BOJ#이분탐색#Python
- 토마토#백준알고리즘#Python
- 터틀비치#리콘#xbox#controller
- NumberofDiscIntersections#Codility#Sort#Python
- 파이썬알고리즘인터뷰#4장
- 백준 알고리즘#BackTracking
- Swift#Tuples#Range
- 날짜 계산#BOJ#완전탐색#Python
- 배열합치기#분할정복#BOJ#Python
- PassingCars#Codility#Python
- N으로 표현#DP#Programmers#Python
- 미로 탐색#백준알고리즘#Python
- 반복수열#백준알고리즘#Python
- Distinct#Codility#Python
- 나무자르기#BOJ#이분탐색#Python
- 병든 나이트#BOJ#탐욕법#Python
- filter#isalnum#lower
- 순열사이클#BOJ#Python
- django#slicing
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |