THE STEADY COMPANY
FirebaseFirestore 모듈 추상화 cover image

FirebaseFirestore 모듈 추상화

Timestamp 디코딩 문제와 해결 방법

2025-01-08 21:00

·
  • iOS
  • Firebase
  • Dependency Injection

들어가며

FirebaseFirestore 모듈을 추상화해서 외부 의존성을 분리하고,
테스트와 Preview 환경에서 유연하게 사용할 수 있도록 만들고 싶었어요.


추상화 진행

기존에 사용하던 CollectionReference, Document, Query 등의 코드를
최소화하기 위해 Protocol 기반 추상화를 진행했어요.

Firestore에서 제공하는 기능을 모두 Protocol로 만들어 준수시켜줬는데,
이 부분은 큰 문제 없이 진행되었어요.


Timestamp 문제 발생

그런데 문제는 Timestamp에 있었어요.

FirebaseCore에서 제공하는 Timestamp는 내부에 seconds 같은 정보를 가지고 있고,
Decodable을 준수하고 있어요.
당연히 동일한 형태로 Decodable을 만들면 디코딩이 잘 될 거라 생각했는데,

Timestamp는 내부에서 동작하는 별도의 디코딩 방식이 존재해서 불가능했어요.


해결: TimestampBuilder

TimestampBuilder를 별도로 만들어서 해결했어요.

AS-IS (기존 방식)

struct SomeResponse: Decodable {
  let value: Int
  let timestamp: Timestamp
}

let response = try snapshot.data(as: SomeResponse.self)

TO-BE (변경된 방식)

@DependencyClient
struct TimestampBuilder: Sendable {
  var build: @Sendable (_ value: Any?) throws -> CustomTimestamp
}

struct SomeResponse: Decodable {
  let value: Int
}

@Dependency(TimestampBuilder.self) var builder
let timestamp = try builder(snapshot.data("timestamp"))
let response = try snapshot.data(as: SomeResponse.self)

Timestamp를 사용하는 부분을 별도로 분리하고,
TimestampBuilder는 추상화된 모듈로 관리하고 있어요.


마치며

Timestamp의 내부 디코딩 로직 때문에 단순한 Decodable 준수만으로는 해결이 안 됐고,
TimestampBuilder를 별도 모듈로 추상화해서 의존성 주입 방식으로 풀었어요.
더 좋은 방법이 있으면 나중에 전환할 예정이에요.

현재는 Timestamp에 대한 Response가 3개 정도밖에 없어서
유지 보수에 큰 문제가 없을 것으로 판단하고 있어요.