ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [포케덱스] - TCA의 Action을 관리해보자(feat. @CasePathable)
    프로젝트/포케덱스 2025. 8. 18. 20:18
    728x90
    반응형

    기존에 포케덱스는 MVVM 아키텍쳐로 구현되어 있었다.

    하지만 최근에 SwiftUI+MVVM의 사용은 그닥 효율적이지 못하다는 글을 보고 나도 생각에 잠겼다.

    이유는 이해를 했다. 애초에 ViewModel은 View와 데이터를 바인딩하기 위해 존재하는 것이지만 SwiftUI는 @State 등의 프로퍼티 래퍼가 있기 때문에 ViewModel이 존재할 필요가 없다.

     

    그래서 비즈니스 로직과 사이드 이펙트를 단방향 흐름을 준수하며 어떤 아키텍쳐를 준수할 수 있을까 고민하던 중 SwiftUI와 잘 맞는다는 TCA를 이용해 리펙토링을 새로 해보기로 다짐했다.

     

    TCA사용에 대한 회고는 나중에 포스팅할 것이다.

     

    오늘은 TCA의 내용 중 Action에 대한 내용에 대해 다뤄볼 것이다.

     

    위의 코드를 보자 Action이라고 정의는 했지만, 각각 어느 곳에서 사용하는 건지 너무 모호하다 주석으로 써놓긴 했지만 한 Feature에 너무 많은 액션이 존재하면 다음과 같은 문제가 생긴다. TCA를 처음 사용했을 때 나의 목표는 주석없이도 읽히는 코드를 짜는 것이 목적이였지만, 만든지 2주후 내 코드를 보니 다시 헷갈리기 시작했다.

     

    이런 문제를 해결하기 위해 나는 각각의 액션을 더 세부적으로 나누기로 했다.

    일단 액션을 종류별로 분리해야하는데, 정리하자면 크게 6가지로 나눌 수 있다.

     

    1. 사용자 Interaction 관련 Action

    2. 하위뷰의 사용자 Interaction 관련 Action

    3. 사용자 Interaction으로 인해 내부적으로 Effect를 구현해야할 Action

    4. 상위 Feature에서 호출해야할 Action

    5. 하위 Feature에서 일어난 Effect를 핸들링할 Action

    6. 각각의 셀의 Effect 액션 정의

     

    자 그럼 이제 이렇게 나눈 액션의 분류로 새로운 enum을 만들어보자

    이 정도면 충분한 것 같다

    이건 특히나 많이 쓸 것 같기에 코드 스니펫으로 등록했다.

    이제 이렇게 분류한 액션에 아까 보였던 이벤트를 각각 종류에 맞게 배치해보자.

    이 정도면 매우 흡족한 것 같다.

    참고로 이렇게 분리를 하면 각가의 액션 네이밍 컨벤션이 매우 중요한데 아직은 정리 중이다. 

     

     

    이렇게 액션을 나눌 수 있다.

    아주 쉽고 간편한 방법인것 같다.

     

    근데 여기서 자꾸 눈에 밟히는 것이 있다.

     

    @CasePathable

     

    @CasePathable은 열거형의 특정 케이스에 'Key Path'처럼 접근할 수 있게 해주는 매크로다.

    원래 Swift에서 구조체(Struct)의 프로퍼티는 \User.name처럼 키 경로로 쉽게 접근할 수 있지만, 열거형의 케이스는 switch나 if case let 구문을 사용해야만 그 안의 연관값을 꺼낼 수 있다.

     

    지금의 내 코드처럼 상위 액션을 구현하고 하위 액션의 연관값을 사용하는 경우가 바로 이 경우다.

     

    @CasePathable은 이 불편함을 해결하기 위해, 각 케이스에 대한 Case Path를 컴파일 시간에 자동으로 생성해 준다.

    이를 통해 열거형을 마치 구조체처럼 간결하고 일관된 방식으로 다룰 수 있게 된다.

    비유 🔑: 구조체의 키 경로가 특정 방(프로퍼티)을 바로 여는 마스터 키라면, 케이스 경로는 여러 문(케이스) 중 하나의 문을 지정해서 열고 그 안의 물건(연관값)을 가져오는 '전용 열쇠'와 같습니다. @CasePathable은 이 '전용 열쇠'들을 자동으로 만들어주는 도구입니다.

    form. Gemini

     

    그렇다고 한다.

     

    정의는 알았고 만약 그럼 @CasePathable을 준수하지 않았을 때 생기는 문제점은 뭐가 있을까?

     

    리듀서 통합이 불가능하다!

     

    TCA의 핵심은 작게 나눈 리듀서들을 Scope, IfLet, ForEach같은 연산자를 사용해서 하나로 합치는 것이다.

    이 모든 연산자들은 내부적으로 케이스 경로를 사용해 부모의 액션에서 자식의 액션을 정확히 식별하고 전달한다. 

     

    @CasePathable을 준수하지 않으면 케이스 경로가 없으므로 이러한 리듀서 연산자들을 전혀 사용할 수 없다.

    이렇게 뜬다는 말이다..

     

    또한 매크로라서 사용해도 성능저하가 거의 없는 것이 매우 장점이다!

     

    오늘도 새로운 지식들과 구조적인 안정화를 이뤄내서 아주 마음에 든다. 더 나은 코드를 만들기 위해 앞으로도 열심히 달려보자

Designed by Tistory.