자주 묻는 질문

원문: Frequently asked questions

The Composable Architecture와 관련해 자주 나오는 질문과 의견을 모았습니다.

개요

TCA에 관한 글과 토론 중에는 오래되었거나 일부가 부정확한 내용이 있습니다. 특히 최신 TCA에서 단점으로 보이는 선택을 받아들일 때 얻는 장점은 충분히 다루지 않은 채 단점에만 집중하는 경우가 많습니다.

하지만 단점만 보는 것은 본질을 놓치는 일입니다. 예를 들어 Swift 값 타입에는 class처럼 안정적인 identity가 없다는 단점만 지적할 수 있지만, 가볍게 복사하고 비교할 수 있다는 큰 장점을 빠뜨리게 됩니다.

앱 아키텍처에는 언제나 trade-off가 있습니다. 선택마다 얻고 잃는 것을 깊이 고민해야 하므로, 여기에서는 자주 제기되는 우려를 정리하고 오해를 바로잡습니다.

모든 종류의 앱에 TCA를 사용해야 하나요?

Swift나 SwiftUI를 처음 배우는 사람에게는 TCA 사용을 권하지 않습니다. TCA는 SwiftUI를 대체하는 도구가 아니라 SwiftUI와 함께 사용하는 도구입니다. 따라서 TCA를 올바르게 사용하려면 SwiftUI의 표준 개념을 잘 알고 있어야 합니다.

또한 네트워크에서 JSON을 받아 표시하는 정도의 단순한 reader 앱에서는 TCA의 강점이 크게 드러나지 않을 수 있습니다. 이런 앱은 복잡한 로직이나 부수 효과가 적기 때문입니다. 간결한 도메인 모델링을 중심으로 일반 SwiftUI로 시작하고, TCA의 기능이 필요해졌을 때 전환하는 방법도 괜찮습니다.

앱 아키텍처에 서드 파티 라이브러리를 도입해야 하나요?

서드 파티 라이브러리 도입은 팀이 신중히 논의해 내려야 할 큰 결정입니다. 라이브러리의 핵심 원칙이 앱을 만드는 우선순위와 맞는다면 합리적인 선택이 될 수 있습니다.

다만 “직접 만들지 않았다”는 이유만으로 배제해서는 안 됩니다. 유지 보수 이력이 일관되고 커뮤니티가 강한 도구를 채택하는 일은, 인터넷에 흩어진 여러 블로그 글의 기법을 조합하는 일보다 반드시 더 위험하다고 보기 어렵습니다. 블로그 글은 특정 시점에 유용했던 방법일 수 있지만 실제 앱의 다양한 edge case를 검증했는지, 수년 뒤에도 작성자가 쓰는지 알기 어렵습니다.

TCA는 SwiftUI의 방식에 어긋나나요?

TCA는 SwiftUI를 잘 보완한다고 생각합니다. TCA의 설계는 SwiftUI에서 많은 영감을 받았고 다음과 같은 유사점이 있습니다.

  • SwiftUI의 @Observable처럼 TCA 기능도 @ObservableState로 필요한 상태 변화만 최소한으로 관찰합니다. Observation 도구는 iOS 16 이하에서도 사용할 수 있도록 backport했습니다.
  • SwiftUI 기능을 조합하듯 body 프로퍼티와 result builder 문법으로 TCA 기능을 조합합니다.
  • @Environment처럼 동작하지만 뷰 밖에서도 사용할 수 있는 @Dependency 프로퍼티 래퍼로 의존성을 선언합니다.
  • @Binding과 비슷하지만 뷰 밖에서도 작동하고 100% 테스트 가능한 공유 상태 도구를 제공합니다.

TCA는 SwiftUI의 강점을 더 폭넓게 활용하게 합니다. 값 타입으로 Observation 도구를 쓸 수 있고, sheet(item:), popover(item:), NavigationStack 같은 SwiftUI 내비게이션 도구를 쓰면서도 enum과 optional처럼 간결한 도메인으로 내비게이션을 구동할 수 있습니다. 또한 Preview에서 안전하지 않거나 사용할 수 없는 의존성을 처음부터 제어하고, 의존성 실행과 결과까지 포함해 기능을 테스트할 수 있습니다.

TCA는 Redux를 옮긴 것일 뿐인가요? 라이브러리가 필요한가요?

TCA는 Redux와 일부 아이디어와 용어를 공유하지만 서로 크게 다릅니다. Redux는 JavaScript 라이브러리이며, 여러 앱 아키텍처 문제를 위한 하나의 의견 있는 해법으로 만들어진 라이브러리가 아닙니다.

TCA는 간결한 도메인 모델링, 값 타입 활용, SwiftUI·UIKit·AppKit 등 Apple 플랫폼 통합, 내비게이션, 강력한 의존성 관리, 부수 효과의 실행과 결과까지 철저히 검증하는 테스트 도구까지 아우릅니다. 각 iOS 주요 릴리스에 맞춰 동시성, NavigationStack, Swift 5.9 Observation, 공유 상태 등을 계속 지원하며 커뮤니티와 GitHub Discussions, Slack도 제공합니다.

TCA 기능에는 boilerplate가 많지 않나요?

TCA의 boilerplate는 주로 과거 ViewStore 개념을 기준으로 말하는 경우가 많습니다. ViewStore는 Swift 5.9 Observation 프레임워크가 나온 뒤 오래전에 지원 중단되었습니다. 현대적인 TCA 기능은 ViewStore 없이 Store에서 상태를 직접 읽고, 일반 SwiftUI처럼 뷰가 필요한 상태만 관찰합니다.

경험상 표준 TCA 기능은 동등한 일반 SwiftUI 기능보다 코드가 훨씬 길 필요가 없습니다. 테스트하거나 기능을 통합할 때는 TCA 도구 덕분에 오히려 더 적은 코드가 필요할 수 있습니다.

별도의 Action enum을 유지하는 일은 불필요하지 않나요?

사용자 액션을 객체의 메서드가 아니라 enum으로 모델링하는 선택에는 분명 비용이 있지만 중요한 장점이 있습니다.

  • 기능 로직을 뷰에서 강하게 분리합니다. 기존 reducer를 감싸 동작을 추가하거나 변경할 수 있어, 예를 들어 온보딩 기능이 게임 기능의 액션을 가로채 단계별 로직을 더할 수 있습니다.
  • 기능의 모든 액션이 데이터 타입으로 표현되므로 _printChanges()로 시스템에 들어온 액션과 상태 변화를 읽기 쉽게 출력하고, signpost 같은 성능 도구나 서드 파티 추적 도구를 만들 수 있습니다.
  • TestStore로 사용자 흐름의 모든 액션과 effect가 되돌려 주는 액션을 보내고 검증하는 철저한 테스트를 작성할 수 있습니다. 자세한 내용은 Testing을 참고하세요.

앱 상태를 하나의 큰 타입에 보관하면 TCA 기능의 성능이 나쁘지 않나요?

실제 TCA 앱은 모든 화면의 상태를 한 번에 보관하지 않습니다. 대부분의 기능은 sheet, drill-down, 다른 내비게이션으로 점진적으로 표시되며, 이런 표현은 optional 상태로 제어됩니다. 표시하지 않는 기능의 상태는 nil이므로 앱 상태에 들어 있지 않습니다.

뷰가 과도하게 다시 렌더링되나요?

뷰는 @Observable을 쓰는 일반 SwiftUI와 마찬가지로 뷰에서 접근한 상태에 따라 필요한 최소 횟수만 다시 계산합니다. Observation을 iOS 13까지 backport했으므로 iOS 16 지원을 종료할 때까지 기다릴 필요도 없습니다.

큰 값 타입을 변경하는 비용이 크지 않나요?

Swift의 in-place mutation에서는 큰 값 타입 변경이 특별히 비싸다고 보이지 않습니다. inout을 통한 변경은 테스트에서 충분히 효율적이었으며, Swift의 borrowing·consuming 도구가 이를 더 개선할 가능성도 있습니다.

큰 값 타입이 stack overflow를 일으키지 않나요?

큰 값 타입이 stack overflow를 일으킬 수 있는 것은 사실이지만, 라이브러리의 내비게이션 도구를 사용하면 실제로는 거의 발생하지 않습니다. 내비게이션 도구는 앱 상태의 각 presentation node에 heap 할당 copy-on-write wrapper를 넣습니다. 따라서 기능 A가 기능 B를 표시해도 A의 상태가 B의 상태를 그대로 포함하지 않습니다.

TCA 기능은 Action이 지나치게 많이 왕복하지 않나요?

여러 Effect를 수행하려고 여러 Action을 보내는 “ping-pong”을 우려하는 경우가 있습니다. 상태 변경과 비동기 작업을 교차해야 할 때는 여러 액션이 필요할 수 있습니다. 하지만 중간 상태 변경 없이 비동기 작업만 여러 개 실행한다면 하나의 Effect에서 모두 처리하고 마지막 결과 액션 하나만 보낼 수 있습니다.

상태 변경을 비동기 작업 사이에서 정말 수행해야 한다면 일부 왕복은 생깁니다. 그 대신 액션 데이터 모델로 얻는 로직·뷰 분리, 디버깅 도구, 모든 동작을 테스트하는 능력을 얻습니다. 비 TCA 앱에서 같은 능력을 재현하려고 해도 결국 비슷한 구조에 이르게 됩니다.

값 타입 기능은 복사되므로 상태를 공유할 수 없지 않나요?

과거에는 사실이었지만 라이브러리 1.10에서 여러 기능 간 상태를 쉽게 공유하고 사용자 기본값이나 파일 시스템 같은 외부 시스템에 영속화할 수 있는 새 공유 상태 도구를 추가했습니다.

공유 상태는 참조 의미론을 도메인에 도입하므로 어느 앱에서나 이해하기 어려워질 수 있습니다. TCA는 공유 상태의 변경도 100% 테스트 가능하고 철저히 검증할 수 있도록 추가 작업을 했습니다.

TCA를 배우거나 사용하려면 Point-Free 구독이 필요한가요?

Point-Free 웹사이트에는 구독 전용 자료도 많지만, 무료로 제공하는 자료도 매우 많습니다. TCA 문서에는 여러 글과 튜토리얼이 있으며, 도메인 모델링·내비게이션·의존성·테스트 등을 보여 주는 대규모 튜토리얼도 제공합니다.

함수형 프로그래밍을 알아야 하나요?

TCA는 자신을 함수형 프로그래밍 라이브러리라고 설명하지 않으며, 그렇게 설명한 적도 없습니다. Swift는 함수형 언어가 아니므로 순수 함수 같은 패턴을 컴파일 타임에 강제할 수 없습니다. 따라서 함수형 프로그래밍 경험은 필수가 아닙니다.

다만 함수형 언어의 몇 가지 개념은 라이브러리 설계에 중요하게 반영되었습니다. 예를 들어 참조 타입처럼 멀리 떨어진 곳에 영향을 주는 동작을 허용하는 타입 대신 이해하기 쉽고 동작을 가지지 않는 값 타입으로 도메인 대부분을 구성합니다. 또한 부수 효과를 순수한 로직 변환과 분리해, effect의 실행과 결과가 시스템으로 돌아오는 과정까지 훌륭하게 테스트할 수 있게 합니다.