TCA 패턴을 이용한 SwiftUI Sample App 제작 소감

Flamozzi·2023년 1월 19일
1
post-thumbnail

SwiftUI를 이용해 iOS 앱 개발을 하면서 TCA 패턴을 사용해 본 배경

  • SwiftUI는 선언형 UI로써, ViewModel의 존재 필요 여부에 대해서 부정적인 시각이 많았고, 기존에 관습처럼 쓰이던 MVVM 패턴을 벗어나고자 하는 시도가 애플 디벨로퍼 포럼을 포함해 여러 개발자들 사이에서 일어나고 있었다.
  • 나 또한 당연하게 기업 곳곳에서 쓰고 있으며, 앱 개발을 할 때 다른 패턴에 비해 보다 진화 되고 장점이 많다고 생각한 MVVM 패턴을 사용해 사이드 프로젝트인 Paperful 프로젝트를 사용해왔다.
  • TCA 패턴에 대해서 문서를 작성하며 고민을 해보았으며, 아직 SwiftUI는 Best practice로 여겨지는 아키텍처 패턴이 없기에 새롭게 주목받고 있는 TCA 패턴을 이용해 샘플 앱을 제작해보고 심플하게 기록을 남기고자 한다.

TCA 패턴을 사용해 간단한 Counter 앱을 만들어 봤다

코드 내에 있는 주석은 코드를 작성해보며 매우 주관적으로 적은 내용으로, 참고하면 파일 구조 파악에 도움이 된다. 유튜브에 올라와 있는 참고 영상에서 사용하는 용어 및 주석을 참고하였으며, deprecated된 부분을 공식 문서를 참고하여 재구성하였다.

  • CounterView.swift
    //
    //  CounterView.swift
    //  TCA_Simple_tutorial
    //
    //  Created by Tony on 2022/10/27.
    //
    
    import SwiftUI
    import ComposableArchitecture
    
    // Feature 자체가 Reducer Protocol을 준수하며, 내부에서 실제 reduce function을 통해 실제 논리와 동작을 처리함
    struct CounterFeature: ReducerProtocol {
        // 도메인(어떤 걸 만들 때 거기에 대한 데이터) + 상태
        struct CounterState: Equatable {
            var count = 0
        }
         
        // 도메인 + 액션
        enum CounterAction: Equatable {
            case addCount
            case subtractCount
        }
        
        // 리듀서: 액션과 상태를 연결시켜주는 역할
        func reduce(into state: inout CounterState, action: CounterAction) -> EffectTask<CounterAction> { // 외부에서 일어난 일을 다시 store로 가져와서 상태를 변경 시킬 때 Effect 씀
            // 들어온 액션에 따라 상태를 변경
            switch action {
            case .addCount:
                state.count += 1
                return .none
                
            case .subtractCount:
                state.count -= 1
                return .none
            }
        }
    }
    
    struct CounterView: View {
        
        // store: Feature(Reducer Protocol을 준수하는)의 스토어임, 상태, 액션을 가지고 있음 - 커맨드 센터 역할
        let store: StoreOf<CounterFeature>
        
        var body: some View {
            WithViewStore(self.store) { viewStore in
                VStack {
                    Text("count: \(viewStore.state.count)")
                        .padding()
                    HStack {
                        Button("더하기", action: {viewStore.send(.addCount)}) // send: 커맨드센터인 store에 액션을 주문함
                        Button("빼기", action: {viewStore.send(.subtractCount)})
                    }
                }
            }
        }
    }
    
    //struct CounterView_Previews: PreviewProvider {
    //    static var previews: some View {
    //        CounterView()
    //    }
    //}
    • ReducerProtocol을 따르는 Feature를 정의해줌으로써, 내부에 State와 Action 그리고 실제 reducer가 수행할 내용을 reduce function으로 정의하며 하나의 구조로 묶을 수 있다.
    • 실제 View struct에서 store를 StoreOf와 같은 형태로 정의하여 body 내에서 손 쉽게 사용 할 수 있게 된다.
    • 또한 하나의 View 파일에서 매우 유연하게 상태관리와 업데이트, 디스플레이가 가능하기 때문에 인체공학적(사람이 이해하기 쉬운)이고 심플한 구조를 가질 수 있다.
  • TCA_Simple_tutorialApp.swift (rootApp.swift)
    //
    //  TCA_Simple_tutorialApp.swift
    //  TCA_Simple_tutorial
    //
    //  Created by Tony on 2022/10/27.
    //
    
    import SwiftUI
    import ComposableArchitecture
    
    @main
    struct TCA_Simple_tutorialApp: App {
        var body: some Scene {
            WindowGroup {
                CounterView(
                    store: Store(
                        initialState: CounterFeature.CounterState(),
                        reducer: CounterFeature() // Feature 자체가 Reducer Protocol을 준수하기 때문에 reducer parameter에 그대로 CounterFeature()를 넣음
                    )
                )
            }
        }
    }
    • View 파일에서 정의한 store를 rootview에 심플하게 추가함으로써, 성공적으로 TCA 패턴을 사용할 수 있게 된다.

간단한 소감

  • TCA 패턴을 통해 단방향 데이터플로우를 매우 심플하고 깔끔한 구조로 구현할 수 있었다.
  • 실제로 SwiftUI의 View는 이미 View + ViewModel의 역할을 하고 있기에 의도적으로 ViewModel을 끼워넣는 상황을 방지할 수 있었다.
  • 위와 같이 심플한 구조를 가짐에도 불구하고 비즈니스 로직은 store를 통해 따로 관리가 가능하기 때문에 비즈니스 로직을 위해 굳이 MVVM 패턴을 채용할 이유가 없었다.
  • 실제 기업에서는 MVVM 패턴을 아직 사용하고 있기에 무작정 TCA 패턴을 고집할 수는 없겠지만, Best practice 혹은 standard way로 여겨지는 아키텍처가 없는 SwiftUI가 앞으로 나아갈 방향성 중 좋은 한 가지 패턴임에는 틀림없는 듯 하다.
  • UIKit과 RxSwift, MVVM을 주요 기술 스택으로 사용하는 기업이 많은 현재 상황에서는 앞서 말한 기술스택을 꾸준히 갈고 닦을 필요가 있지만, SwiftUI를 새로운 프로젝트에 이용해야 하는 경우 매우 유용하게 쓰일 수 있을 듯 하다.
  • 개인적으로 진행하는 사이드 프로젝트 수준에서는 TCA 패턴을 진지하게 더 사용해봐도 괜찮겠다는 입장이다.

참고 자료

profile
개발도 하고, 글도 적고

0개의 댓글