2024. 11. 7. 05:02ㆍ🍏/Architecture
들어가기 앞서...
오늘은 SwiftUI에서 가장 인기있고 맛있다고 소문난 TCA를 경험해보려고 합니다.
아키텍쳐를 사용해보기 이전에 먼저 이 아키텍쳐는 어떤 이점이 있고, 어떤 점이 중점적으로 다뤄지고 있고 무슨 기저를 가지고 아키텍쳐를 구성했는지에 대해서 생각해보려고 합니다.
혹시 잘못 이해하고 있거나 글에 잘못된 점이 있으면 피드백 부탁드리겠습니다. 🙇♂️
The Composable Architecture (TCA, for short) is a library for building applications in a consistent and understandable way, with composition, testing, and ergonomics in mind. It can be used in SwiftUI, UIKit, and more, and on any Apple platform (iOS, macOS, visionOS, tvOS, and watchOS).
TCA 공식 Github에 가보면 위와 같이 "TCA를 구성, 테스트 및 인체 공학을 염두에 두고 일관되고 이해하기 쉬운 방식으로 애플리케이션을 구축하기 위한 라이브러리다." 라고 정의하고 있습니다. 공식 Readme를 차근차근 읽어보면서 TCA에 대해서 톺아보도록 하겠습니다.
컴포저블 아키텍쳐란 ?
이 라이브러리는 다양한 목적과 복잡성을 가진 앱을 빌드하는 데 사용할 수 있는 몇 가지 핵심적인 도구를 제공합니다. 일상적으로 직면 하는 많은 문제를 해결하기 위해 따라할 수 있는 매력적인 스토리를 제공합니다.
- State Management - 상태 관리
- 단순한 값 타입을 사용하여 앱의 상태를 관리하고, 여러 화면 간에 상태를 공유하여 한 화면에서의 상태 변화가 즉시 다른 화면에서 관찰될 수 있도록 하는 방법을 제공합니다.
- Composition - 구성
- 큰 기능을 더 작은 구성 요소로 나누고, 이를 독립된 모듈로 추출하여 쉽게 사용하거나 다시 조합하여 큰 기능을 구성할 수 있는 방법을 제공합니다.
- Side effects - 사이드 이펙트
- 애플리케이션의 특정 부분이 외부 세계와 가장 테스트하기 쉽고 이해하기 쉬운 방식으로 상호작용할 수 있도록 하는 방법을 제공합니다.
- Testing - 테스팅
- 아키텍처에 구축된 기능을 테스트할 뿐만 아니라 여러 부분으로 구성된 기능에 대한 통합 테스트를 작성하고, 종단간 테스트(end-to-end test)를 작성하여 부작용이 애플리케이션에 미치는 영향을 파악하는 방법도 배울 수 있습니다. 이를 통해 비즈니스 로직이 예상한 대로 실행되고 있는지 강력하게 보장할 수 있습니다.
- Ergonomics - 인간공학(사용성)
- 가능한 최소한의 개념과 움직이는 부분을 사용하여 간단한 API로 위의 모든 작업을 수행하는 방법.
더 알고 싶다면
Pointfree.co 여기에서 모든 에피소드를 볼 수 있으며, TCA에 관한 부분은 여기에 있습니다.
예제들.
This repo comes with lots of examples to demonstrate how to solve common and complex problems with the Composable Architecture. Check out this directory to see them all, including:
- Case Studies
- Getting started
- Effects
- Navigation
- Higher-order reducers
- Reusable components
- Location manager
- Motion manager
- Search
- Speech Recognition
- SyncUps app
- Tic-Tac-Toe
- Todos
- Voice memos
Looking for something more substantial? Check out the source code for isowords, an iOS word search game built in SwiftUI and the Composable Architecture.
기본 사용법
여기에서 TCA Tutorial에 관한 부분이 나오는데, Readme를 정독해보고 나서 튜토리얼을 진행할 예정입니다.
컴포저블 아키텍처를 사용하여 기능을 구축하려면 도메인을 모델링하는 몇 가지 유형과 값을 정의합니다:
- State : 기능의 로직을 수행하고 UI를 렌더링하는 데 필요한 데이터 구조를 설명하는 타입입니다.
- Action : 사용자 행동(액션), 알림(Notification), 이벤트 소스(Event sources) 등 기능 내에서 발생할 수 있는 모든 액션을 나타내는 타입입니다.
- Reducer : 액션(Action)이 주어졌을 때 앱의 현재 상태(State)를 다음 상태로 변화시키는 방법을 설명하는 함수입니다. 리듀서는 API 요청과 같이 실행해야 하는 모든 Effect를 반환하는 역할도 담당하며, 이는 Effect 값을 반환함으로써 수행할 수 있습니다.
- Store : 실제로 기능을 구동하는 런타임입니다. 모든 사용자 작업(액션)을 스토어로 전송하고, 스토어가 Reducer와 Effect를 실행하며, 스토어에서 상태 변화를 관찰하여 UI를 업데이트할 수 있습니다. (하단 작동 방식에서 설명)
이렇게 정의를 하게 되면 기능의 테스트 가능성을 즉시 확보할 수 있고 크고 복잡한 기능을 작은 도메인 영역으로 나누어 서로 붙여 조합할 수 있다는 이점이 있습니다.
Github readme의 이하 코드 베이스의 설명들은 튜토리얼 혹은 프로젝트를 진행하면서 해당하는 내용들로 따로 포스팅하여 설명하도록 하겠습니다.
TCA의 작동 방식
간단하게 TCA에 대해서 풀어낸 과정의 플로우입니다.
- View에서 Action 발생
- sends: View(Presenter)는 사용자 이벤트(UI 로직), 알림, 네트워크 응답등 다양한 행위로 Action을 보내는 역할을 합니다.
- Reducer에서 State 변환
- received by: Action은 Reducer에 의해 받아들여(received) 처리됩니다.
- Reducer는 특정 Action을 받았을 때 현재 State를 다음 상태로 변환하는 역할을 합니다.
여기서 두 가지 가능성이 있습니다:
- State를 직접 변경하는 경우(mutate): 이 경우, 외부 의존성이나 네트워크 요청 없이 앱 내 로직에 따라 간단히 State를 업데이트합니다. 예를 들어, count += 1와 같이 State의 값을 변경하는 로직이 여기에 포함됩니다.
- Environment와 상호작용(interacts with): 외부 의존성(API 호출 등)을 처리하기 위해, Reducer는 Environment와 상호작용하여 특정 Effect를 실행합니다.
- Environment ?
- Environment는 외부 의존성을 담고 있는 구조로, 여기서 API 요청 등 외부 시스템과 통신을 수행합니다.
- returns: Effect는 이 상호작용의 결과로서 성공 또는 실패 데이터를 반환합니다. 이 반환된 Effect는 다시 Action을 발생시키고, 이를 통해 새로운 상태로의 변화를 일으킬 수 있습니다.
- Effect 결과를 통해 추가 Action 발생
- Effect의 결과로 새로운 Action이 발생하면, 다시 Reducer를 통해 State가 변화됩니다.
- 성공적인 결과인 경우 비즈니스 로직에 맞는 State 변화를 일으키고, 실패(예: 네트워크 에러)가 발생한 경우에는 에러 State로 변경하여 Alert와 같은 UI 요소에 반영될 수 있습니다.
- 변경된 State가 View에 반영
- triggers update: 최종적으로 변화된 State는 View에서 반영됩니다. 이렇게 하여 사용자가 Action을 발생시키고, 그 결과를 실시간으로 UI에 반영하는 흐름이 완성됩니다.
요약
- View → Action 발생 → Reducer로 State 변경 시도
- 외부 상호작용이 필요 없는 경우, State를 직접 업데이트
- 외부 상호작용이 필요한 경우, Environment를 통해 Effect 실행 후 Action을 재발생
- Effect 결과에 따라 추가 State 변환 후 View에 반영
Environment가 Effect를 반환하여 Action으로 들어가는 부분이 특히 중요한데, 이 방식 덕분에 외부 의존성을 쉽게 테스트할 수 있게 됩니다.
TCA에 대한 견해
TCA에 대해서 읽고 도입부에서 언급한 내용들을 꽤 오랫동안 생각해 보게 되었습니다.
주요 이점과 기저에 대해서는 아래와 같습니다.
1. TCA의 주요 이점
- 일관된 상태 관리: TCA는 앱의 모든 상태를 일관된 방식으로 관리할 수 있도록 합니다. 이를 통해 기능이 많고 복잡한 애플리케이션에서 각 기능 간의 상태가 불일치하거나 불안정해지는 것을 방지합니다. 모든 상태 변화가 Reducer 내에서 이루어지기 때문에, 어디서든 동일한 로직과 방식으로 상태를 관리할 수 있습니다.
- 테스트 가능성: TCA는 테스트 가능성을 강화하는 아키텍처입니다. State, Action, Reducer, Environment 등 기능의 각 부분이 명확하게 정의되어 있어, 특정 상태에서 특정 액션이 주어졌을 때 상태가 어떻게 변화할지를 쉽게 테스트할 수 있습니다. 특히, 외부 API와의 상호작용을 모의(Mock) 환경에서 테스트할 수 있도록 의존성 주입(Dependency Injection)을 적극 활용합니다.
- 모듈화와 재사용성: TCA는 큰 기능을 작은 구성 요소로 나누어 구성할 수 있어, 복잡한 애플리케이션도 작은 기능들로 분리하여 관리할 수 있습니다. 이로 인해 코드의 재사용성과 모듈화가 쉬워지며, 기능이 추가되거나 확장될 때에도 다른 기능과 충돌 없이 조합할 수 있습니다.
- 명확한 비동기 작업 처리: 비동기 작업을 Effect로 명확하게 표현하여, 비동기 작업의 흐름을 쉽게 파악할 수 있고, 외부 시스템과의 상호작용을 효율적으로 관리할 수 있습니다. 또한, 효과가 발생한 시점과 그에 따른 액션 처리도 명확하게 정의할 수 있어 코드 가독성이 향상됩니다.
2. TCA의 중점 요소
- 일관된 상태 변화 패턴: 모든 상태 변화는 Reducer 내에서 이루어지며, Reducer는 Action을 통해서만 상태 변화를 유발하도록 설계됩니다. 이렇게 일관된 상태 변화 패턴은 상태 관리의 복잡성을 줄이고, 상태 변경의 예측 가능성을 높입니다.
- 의존성 주입을 통한 테스트 가능성 강화: Environment에 의존성을 모듈화하여 외부 API 요청, 데이터베이스 접근 등을 필요에 따라 실제 환경 또는 모의 환경으로 쉽게 변경할 수 있습니다. 이를 통해, 외부 의존성으로 인한 테스트의 어려움을 해결하고, 테스트 환경을 독립적으로 유지할 수 있습니다.
- 모듈화된 구조: State, Action, Reducer, Environment로 나누어 기능을 정의하는 구조는 코드의 재사용성을 높이고 유지보수를 용이하게 합니다. 특히, 복잡한 기능을 작은 단위로 분리해 관리할 수 있어 코드의 복잡성을 줄일 수 있습니다.
- Side Effect의 명확한 분리: TCA는 부수 효과(Side Effect)를 Effect로 명확하게 분리하고, Reducer가 처리할 수 있도록 합니다. 외부 시스템과의 상호작용이나 비동기 작업을 Effect로 관리하면서 Action과의 연결을 통해 이를 UI에 쉽게 반영할 수 있습니다.
3. TCA 아키텍처의 기저
- Unidirectional Data Flow(단방향 데이터 흐름): TCA는 Redux와 같이 단방향 데이터 흐름을 따릅니다. Action이 발생하여 Reducer가 상태를 업데이트하고, 업데이트된 상태가 View에 반영되는 일방향 흐름을 통해 데이터와 상태의 예측 가능성을 유지합니다. 이 구조는 상태 변경과 관련된 모든 로직을 Reducer에 집중시켜 상태 변화의 추적을 쉽게 만듭니다.
- Functional Programming(함수형 프로그래밍) 원칙: TCA는 함수형 프로그래밍의 영향을 많이 받았습니다. 특히, 순수 함수로서의 Reducer와, 의존성을 외부로부터 주입받는 방식을 통해 테스트 가능성과 예측 가능성을 확보합니다.
- Declarative UI(선언적 UI): SwiftUI와 같은 선언적 UI와 잘 맞물려 동작하도록 설계되었습니다. State 변화에 따라 View가 자동으로 업데이트되기 때문에 코드가 더 직관적이고 간결해지며, UI와 로직의 분리가 쉬워집니다.
요약
TCA는 상태 관리, 모듈화, 테스트 가능성, 코드 재사용성을 중점적으로 다룬 아키텍처입니다. 단방향 데이터 흐름과 함수형 프로그래밍의 원칙을 기저로 하여, 앱의 상태를 예측 가능하고 일관되게 관리하며, 테스트와 유지보수의 편의성을 극대화하는 데 중점을 둡니다.
TCA에 관한 설명을 읽고 느낀점
제가 TCA에 관심을 갖게 된 이유 중 가장 큰 이유는 테스트 코드 작성의 용이성 때문이었습니다. 솔직히 말하면, 그동안 제대로 된 테스트 코드를 작성해본 적이 거의 없었는데, TCA는 이 부분을 TestStore와 같이 테스트를 고려한 구조를 미리 갖추고 있어서, 테스트 코드를 일관성 있고 쉽게 작성할 수 있게 지원해 준다는 점이 상당히 매력적이었습니다.
또한, 단방향 데이터 흐름을 잘 유지하면서 상태를 관리하는 방식이 정말 깔끔하다고 느꼈습니다. 정확한 것들은 튜토리얼 또는 프로젝트를 진행하면서, TCA를 경험해 보면서 글로 남길 예정입니다.
이후에 다음 TCA로 찾아 뵙겠습니다. 긴글 읽어주셔서 감사합니다.
'🍏 > Architecture' 카테고리의 다른 글
[Architecture] Modular Architecture VS Clean Architecture (0) | 2024.09.18 |
---|---|
[Clean Architecture, SwiftUI] SwiftUI를 위한 클린 아키텍처 (2) | 2024.09.07 |
[Clean Architecture] Presentation(MVVM), Domain, Data (0) | 2024.08.30 |
[Architecture] 프로젝트에 Modular Architecture를 적용하는 이유 (0) | 2024.05.25 |
[Architecture] Modular Architecture iOS 개념 정리 (0) | 2024.05.24 |