-
Notifications
You must be signed in to change notification settings - Fork 0
[소켓통신] Any Type과의 싸움
오리 서비스에서 체크리스트 동시편집 을 위해 iOS는 웹 소켓으로 서버와 통신을 진행 했습니다.
서버와 본격적인 구현에 앞서서 iOS 측은 다음과 같은 요구를 했습니다
- iOS - "JSON 데이터 타입을 지정해주세요!!"
- BE - "저희는 데이터 타입 그냥
Any로 해서 보내는데요?"
iOS의 요청은 JSON 패킷 데이터 타입을 바이너리 데이터 로 지정해 달라는 요청이었습니다.
반면 서버가 이해한 것은 조금 달랐습니다
소통의 오류로 인해 iOS의 고통은 이때부터 시작이었습니다.
서버 측에서 보내주는 JSON 내부의 Any 타입은 파싱하는데에 굉장히 까다로웠습니다.
struct CRDTResponseDTO: Decodable {
let event: Event
let data: [Any]
}
기존에는 이런식으로 [Any] 타입으로 선언해두고 다음과 같은 코드로 경우에 따라 파싱을 했어야 했습니다.
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.event = try container.decode(Event.self, forKey: .event)
if let message = try? container.decode(CRDTMessageResponseDTO.self, forKey: .data) {
self.data = [message]
} else if let messages = try? container.decode([CRDTMessageResponseDTO].self, forKey: .data) {
self.data = messages
} else {
self.data = []
}
}
여기에 Socket에 대한 다양한 이벤트 처리를 해야했습니다
- 양방향 소켓통신 중 로컬 사용자의 CRDT 문서작성(event: Send)
- 양방향 소켓통신 중 다른 사용자의 CRDT 문서작성(event: Listen)
- 사용자가 중간에 소켓통신에 참가할 때 CRDT 전체 전송(event: History)
이렇게 이벤트에 따라 생기는 다양한 데이터 타입들이 발생했습니다
struct CRDTRequestDTO: Encodable {} // 글자 하나에 대한 요청
struct CRDTDocumentRequestDTO: Encodable {} // TextField 하나에 대한 요청
struct CRDTMessageRequestDTO: Encodable {} // 전체 History를 보내는 요청
struct CRDTCheckListToggleRequestDTO:Encodable {} // 체크리스트 체크 이벤트 요청
struct CRDTResponseDTO: Encodable {} // 글자 하나에 대한 응답
struct CRDTDocumentResponseDTO: Encodable {} // TextField 하나에 대한 응답
struct CRDTMessageResponseDTO: Encodable {} // 전체 History를 보내는 응답
struct CRDTCheckListToggleResponseDTO:Encodable {} // 체크리스트 체크 이벤트 응답
CRDT 관련 이벤트가 늘어 남에 따라 데이터를 처리하는 것이 어려웠고 다음과 같이 추상화를 진행했습니다
protocol CRDTData {
var id: UUID { get }
var number: Int { get }
}
그리고 기존에 CRDTRequestDTO, CRDTResponseDTO가 가지고 있던 data 타입을 CRDTData 타입으로 추상화 했습니다.
let data: [Any] // 기존
let data: [CRDTData] // 추상화 이후
이렇게 추상화를 진행한뒤 다른 CRDT 관련 Response 데이터 타입들이 CRDTData 프로토콜을 채택하게 함으로써 CRDTResponseDTO 한곳에서 파싱을 진행할 수 있었습니다.
물론 해당 코드 부분이 어지럽기는 합니다. Any Type으로 오다 보니 어쩔 수 없더군요
작성자는 소켓 프로그래밍도 처음이고 이렇게 복잡한 타입의 데이터 파싱도 처음인데 팀원들과 함께 추상화를 고민하며 해결할 수 있었던 좋은 경험이었습니다. 또한 BE 캠퍼들과 조금 더 소통이 원활했다라고 한다면 수월하지 않았을까 생각이 들며 소통의 중요성을 깨달았습니다!
- [ADR] 아키텍처 의사 결정 기록: iOS 애플리케이션 아키텍처 채택하기
- [ADR] 아키텍처 의사 결정 기록: SwiftLint 채택
- [ADR] 아키텍처 의사 결정 기록: UI 영역에서 Combine 사용 결정
- [ADR] 아키텍처 의사 결정 기록: Presentation영역의 ViewModel에서 Input Output 패턴 도입 결정
- [ADR] 아키텍처 의사 결정 기록: 코디네이터 패턴 도입 결정
- [ADR] 아키텍처 의사 결정 기록: 로컬 스토리지로 코어 데이터 사용 결정
- [ADR] 아키텍처 의사 결정 기록: Custom Network Foundation 라이브러리 구현 및 모듈화 결정
- [ADR] 아키텍처 의사 결정 기록: 이미지캐셔 라이브러리 구현 및 모듈화 결정