반응형

TCA Study - Swift 개발자가 TCA를 알아야 하는 이유 

 

SwiftUI가 도입된 이후 iOS 개발 환경은 큰 변화가 있었습니다.
선언형 UI는 개발 생산성을 높였고, 복잡한 UIKit 기반 레이아웃 작업을 단순화했습니다.
하지만 앱 규모가 커질수록 SwiftUI만으로는 해결하기 어려운 구조적 문제가 드러났습니다.이 문제를 해결하며, SwiftUI와 가장 자연스럽게 결합되는 아키텍처로 많은 개발자가 선택하는 것이

바로 The Composable Architecture(TCA) 입니다.


1. SwiftUI의 간결함 뒤에 숨어 있는 구조적 한계

SwiftUI는 다음과 같은 장점을 갖고 있습니다.

  • 선언형 UI
  • 상태 변화에 따른 자동 UI 업데이트
  • 코드량 감소와 높은 가독성
  • 빠른 프로토타이핑

그러나 앱 규모가 깊어지면 SwiftUI만의 단순한 구조는 아래와 같은 복잡성을 드러냅니다.

1.1 @State, @ObservedObject, @EnvironmentObject의 무분별한 혼용

SwiftUI는 다양한 상태 관리 속성을 제공합니다.

작은 화면에서는 큰 문제가 없지만, 앱 전체가 커지면 문제가 발생합니다.

예시 문제:

  • 어떤 View가 어떤 상태를 소유하는지 파악이 안 됨
  • 동일한 상태가 여러 View에서 중복 관리됨
  • EnvironmentObject 주입이 누락되어 런타임 크래시 발생
  • 상태 변경 책임이 View마다 흩어져 있어 디버깅 난도가 상승

1.2 사이드 이펙트가 ViewModel에 집중되며 테스트 어려움 증가

SwiftUI + MVVM 구조에서는 네트워크·파일 I/O·타이머 같은 사이드 이펙트가

ViewModel로 몰리는 경향이 있습니다.

문제점:

  • ViewModel이 비대해짐 (Massive ViewModel)
  • 비즈니스 로직과 UI 상태 로직이 섞임
  • 테스트하려면 실제 API 호출을 걸어야 하는 경우가 많음
  • 장기 비동기 작업 중 취소(cancellation) 처리가 어려움

1.3 화면 간 상태 전달이 복잡해짐

SwiftUI에서 화면 간 데이터 전달은 다음 패턴처럼 다양합니다.

  • NavigationLink(value:)
  • @StateObject 생성 시점 공유
  • @Binding 전달
  • @EnvironmentObject 전역 공유

이 구조는 작은 프로젝트에서는 효과적이지만,

실제 서비스 수준 앱에서는 상태 추적 비용이 매우 높아집니다.


2. MVC·MVVM 시대의 문제가 SwiftUI 시대에 다시 등장한다

UIKit 시대에도 개발자들은 한 가지 문제를 늘 겪었습니다.

“초기에는 단순해 보였던 구조가, 기능 추가로 커지면서 통제가 불가능해진다.”

SwiftUI는 UI 선언 방식만 바뀌었을 뿐,

앱의 전체 구조를 어떻게 설계할지에 대해서는 어떠한 가이드도 제공하지 않습니다.

그래서 SwiftUI와 함께 아래 문제가 되풀이됩니다.

2.1 “상태의 소유권”이 명확하지 않음

2.2 “상태 변경의 흐름”이 통제되지 않음

2.3 “기능 단위 모듈화”가 어렵고 재사용이 힘듦

2.4 “Side Effect 통제”가 되지 않음

2.5 “테스트가 어려움”

이 문제는 SwiftUI 자체의 한계가 아니라,

앱 전체 구조를 설계할 프레임워크가 없기 때문에 발생하는 문제입니다.

그리고 그 문제를 해결하기 위해 등장한 것이 바로 TCA입니다.


3. TCA가 해결하려는 근본적인 문제 5가지

TCA(The Composable Architecture)는 단순한 상태 관리 프레임워크가 아닙니다.

TCA는 아래 5가지 문제를 근본적으로 해결하는 아키텍처입니다.


3.1 문제 1: 상태 관리의 혼란 → 해결: “명확한 단일 상태 모델”

TCA에서는 모든 Feature(기능)에 대해 다음을 명확히 정의합니다:

  • State: 이 기능에서 필요한 모든 상태
  • Action: 발생 가능한 모든 이벤트
  • Reducer: 상태가 Action에 따라 어떻게 변하는지
  • Store: 상태를 보존하고 Action을 Reducer로 전달

이 4요소가 명확히 구분되므로 상태가 흩어지지 않습니다.


3.2 문제 2: View가 로직을 소유하는 구조 → 해결: “Reducer 중심 구조”

SwiftUI는 View가 다양한 역할을 맡습니다.

  • UI 렌더링
  • 이벤트 처리
  • 상태 변경
  • 비동기 작업
  • 에러 처리

이렇게 되면 유지보수가 어려워집니다.
반면 TCA에서는 이런 로직이 모두 Reducer로 이동합니다.
View는 오직 UI 렌더링에만 집중합니다.


3.3 문제 3: Side Effect(네트워크 등)가 여기저기 흩어짐

→ 해결: “Effect 시스템 + Dependency 주입”

TCA는 모든 비동기 작업을 Effect로 독립시키고,
Dependency 시스템을 이용해 실제 구현(live)과 모킹(mock)을 나눌 수 있게 합니다.

예시:

@Dependency(\.apiClient) var apiClient

이렇게 하면 Reducer에서 네트워크 로직을 직접 호출하지 않습니다.


3.4 문제 4: Feature 간 결합도가 높음

→ 해결: “기능 단위 조립(Composable Architecture)”

앱 전체를 기능(feature) 단위로 분리하고,
부모 Feature가 자식 Feature를 Scope로 조립합니다.
이런 패턴은 점진적인 규모 확장에 매우 적합합니다.


3.5 문제 5: 테스트가 어렵고 비용이 큼

→ 해결: “TestStore 기반 전분야 테스트 자동화”

Reducer는 순수 함수이기 때문에 테스트하기 쉽고,
Effect도 TestStore가 자동 추적하기 때문에 테스트 작성 비용이 적습니다.


4. 실무에서 강력한 이유: 예측 가능한 패턴 + 팀 개발 최적화

TCA는 SwiftUI 생태계에서 가장 강력한 앱 구조 중 하나입니다.

그 이유는 다음과 같습니다.

4.1 기능 단위 분리로 협업에 강함

  • 어떤 파일에 어떤 로직이 있는지 명확함
  • Merge conflict가 줄어듦
  • “이 기능은 누가 소유하는가?”가 명확해짐

4.2 코드 일관성 유지

TCA는 모든 기능이 동일한 구조(State/Action/Reducer)를 사용하기 때문에

신규 팀원의 온보딩 속도가 매우 빠릅니다.

4.3 SwiftUI와 완벽히 맞물리는 구조

SwiftUI의 선언형 개념은 “상태 기반 렌더링”입니다.

TCA는 “상태 기반 애플리케이션 구조”입니다.

두 개념은 자연스럽게 결합됩니다.


5. 결론: Swift 개발자가 TCA를 배워야 하는 이유

요약하면 SwiftUI 시대의 문제는 다음과 같습니다:

  • 상태 관리 혼란
  • 로직이 View와 뒤섞임
  • 테스트가 어려움
  • 대규모 프로젝트 구조화 어려움

TCA는 이 모든 문제를 해결하는 정교한 아키텍처입니다.

TCA는 단순히 앱을 만드는 툴이 아니라

Swift 개발자가 복잡한 앱을 안정적으로 만들기 위한 “체계적인 방법론”입니다.


 

반응형
Posted by 까칠코더
,