저희는 최근 성공적으로 쇼케이스를 마무리한 이후, 사용자 피드백을 바탕으로 서비스 전반에 대한 재기획을 진행했고, 현재 그 과정을 진행 중에 있습니다.
리팩토링
리팩토링은 코드 개선 -> 기능 추가 및 서비스 품질 향상 -> macOS 확장이라는 단계적인 목표를 중심으로 계획되었습니다. 다만 본격적인 기능 추가와 서비스 개선에 앞서, 개발자간 코드 이해도의 차이와 구조 파악의 어려움이 있다는 문제를 인식하게 되었습니다. 이에 따라 팀 내부의 공통된 이해를 형성하고, 이후 코드 개선을 보다 효율적으로 진행하기 위해 현재 코드 구조를 도식화하는 작업을 먼저 진행하기로 결정했습니다.
도식화 및 문서화
지금 탭탭 코드에는 이를 설명해 줄 문서나 구조를 한눈에 파악할 수 있는 도식화된 자료가 거의 없는 상태입니다. 그로 인해 리팩토링을 진행하려는 시점에서 코드 이해와 전체 구조 파악에 어려움이 있다는 점을 명확히 인지하게 되었습니다. 사실 개발 초기 단계에서 문서화의 필요성에 대해 개발자들 간에 충분히 공감하고 계획을 세웠음에도, 본격적인 개발 페이즈에 돌입하면서 데드라인에 대한 압박과 기능 구현에 집중하다 보니 체계적인 문서 작성을 진행하지 못했습니다.
이 부분에 대해 개발팀 모두가 아쉬움과 책임을 인지하고 있으며, 동일한 문제가 반복되지 않도록 개선이 필요하다는 데 의견을 모았습니다. 탭탭 개발팀은 원활한 리팩토링, 기능 확장, 장기적인 유지보수를 고려해 현재 코드 구조를 도식화하는 작업을 우선적으로 진행하기로 결정했습니다.
어떤 방식으로 그릴 것인가?
도식화 작업을 시작하면서 가장 먼저 부딪힌 문제는 "어떤 방식으로 그릴 것인가"였습니다. 탭탭의 코드는 전반적으로 TCA 기반으로 구성되어 있으며, 이 구조는 명확한 단방향 데이터 플로우를 전제로 합니다. TCA는 State, Action, Reducer, Store, Environment라는 구성 요소를 중심으로 동작하며, 모든 상태 변화는 Action을 통해서만 발생하고 Reducer가 이를 처리하는 방식으로 흐름이 이루어집니다.

위처럼 단방향으로 흐르는 TCA구조를 효과적으로 표현하기 위해 여러 도식화 방법을 검토했습니다.
1. 상태 다이어그램

먼저 상태 다이어그램의 경우, 특정 상태와 그 전이 관계를 표현하는 데에는 직관적이었고, 사용자 관점에서 화면이 어떻게 변하는지 표현하기에도 적합했습니다. 하지만 실제로 상태 다이어그램으로 그려보니 문제가 있었습니다. TCA의 State가 상태 머신과는 다르다는 점이었습니다. 상태 다이어그램에서 "검색중", "검색 완료"와 같은 상태를 정의하고 싶지만, 실제 TCA 코드에는 이런 명시적인 상태가 존재하지 않습니다. State는 그냥 데이터 구조체일 뿐입니다. searchResult 배열에 값이 있는지 없는지, query 문자열이 비어있는지 아닌지 같은 속성들의 조합으로 상태가 결정됩니다. 이런 추상화된 상태를 다이어그램으로 표현하면, 다이어그램과 실제 코드 사이에 간극이 생길 수 있습니다.
또 다른 문제는 TCA의 핵심인 Action-Reducer-Effect-State 변경 흐름을 제대로 표현하기 어렵다는 점입니다. 한 액션 안에서 State 변경과 Effect 실행이 동시에 일어나는데, 상태 다이어그램으로는 이 동시성을 명확히 드러내기가 어렵습니다. entry/do/exit 같은 표기법을 써도 순차적으로 일어나는 것처럼 보여서 오해의 소지가 있었습니다.
2. 시퀀스 다이어그램

시퀀스 다이어그램은 객체간 메세지 흐름을 시간 순서대로 표현하는 데 강점이 있습니다. 특히 비동기 작업이나 여러 객체가 얽긴 복잡한 구조를 표현할 때 유용합니다. 마찬가지로 TCA 구조를 시퀀스 다이어그램으로 나타냈을 때 몇 가지 문제가 있었습니다.
TCA의 대부분 액션은 비슷한 구조를 가집니다. 사용자가 액션을 발생시키면, Store가 State를 변경하고, 필요하면 Dependency를 호출하고, 결과를 받아서 다시 State를 업데이트하는 구조를 가집니다. 이 패턴이 모든 액션마다 반복되다 보니, 다이어그램이 세로로 길어지게 됩니다. 예를 들어, 5개의 액션이 있으면 거의 똑같은 시퀀스가 5번 반복되어 세로로 길어지게 됩니다. 길이가 길어지다보니 가독성의 문제도 있고 핵심을 파악하기 어렵다는 문제가 있었습니다
3. 플로우 차트

최종적으로, 탭탭 개발팀은 아래와 같은 이유로 플로우 차트를 채택하였습니다.
1. 조건 분기 표현이 가장 명확하다고 판단 하였습니다.
-> if-else는 다이아몬드 모양으로 표현되고, 각 분기가 어떻게 처리되는지 화살표를 따라가면 바로 알 수 있습니다. 위의 플로우 차트에서 카테고리 선택 시 "전체"인지 "특정 카테고리"인지에 따라 다르게 처리되는 로직도, if-else 다이아몬드 구조 하나로 명확하게 표현됩니다.
2. TCA의 단방향 플로우를 그대로 시각화할 수 있어, 이해하기 쉽다고 판단 하였습니다.
-> Action을 시작점으로 해서 Reducer에서의 분기 처리, Effect 실행 여부, State 변경 흐름을 위에서 아래로 직관적으로 표현됩니다.
3. 비교적 간단한 구조로, 복잡도 증가에도 확장에 있어서 무리가 없다고 판단 하였습니다.
-> 상태 다이어그램은 상태가 많아지면 화살표가 사방으로 뻗어나가 가독성이 떨어지고, 시퀀스 다이어그램은 액션이 늘어날수록 세로로 길어져서, 결국 여러 개의 다이어그램으로 쪼개야합니다. 하지만 플로우 차트는 비교적 간단한 구조로 되어있어 복잡도 증가에도 확장이 자연스럽습니다.
4. 직관적인 구조로 되어 있어 이해하기가 가장 쉽다고 판단 하였습니다.
-> 코드와 거의 1:1로 매칭되어 있어, 코드를 읽으면서 다이어그램을 따라갈 수 있고, 반대로 다이어그램을 보면서 코드를 이해할 수 있습니다. 예를 들어, 코드에서 state.query = query라고 작성되어 있으면, 다이어그램에도 "State.query = query"라는 박스가 있습니다.
개선점이 보이다
사실 도식화를 시작하기 전까지는 개인적으로 회의적인 입장이었습니다. 이미 구현이 끝난 코드를 다시 도식화해서 무엇을 얻을 수 있을까, 더군다나 리팩토링 과정에서 상당 부분이 바뀌거나 아예 갈아엎어질 코드인데 굳이 시간을 들일 필요가 있을까라는 생각이 지배적이었습니다. 당장 눈앞의 리팩토링 작업이 더 중요해 보였고, 도식화는 다소 형식적인 작업처럼 느껴지기도 했습니다.
하지만 실제로 도식화를 진행하면서 이런 생각은 빠르게 바뀌었습니다. 도식화를 위해 코드를 처음부터 다시 읽고, 흐름을 따라가며 구조를 정리하는 과정에서 발견하지 못했던 부분들과 개선이 필요한 지점들이 눈에 띄기 시작했기 때문입니다. 예를 들어, state.searchSuggestion.searchText = query와 같은 코드가 있습니다. 이 부분은 기능적으로는 문제가 없었지만, 도식화 과정에서 다시 보니 구조적으로 꽤 특이한 형태라는 것을 알게 되었습니다. 일반적으로 TCA에서는 부모 State가 자식 State 내부 값을 직접 수정하는 방식은 안티패턴에 가깝습니다. 자식 State는 해당 도메인의 Action과 Reducer를 통해 스스로 상태를 변경하는 것이 TCA가 지향하는 구조이기 때문입니다. 평소 기능 구현에 집중할 때는 크게 의식하지 못했던 부분이었지만, 흐름을 그림으로 풀어내려다 보니 이러한 개선점을 발견하게 되었습니다.
이처럼 도식화는 단순히 결과물을 정리하는 작업뿐만 아니라, 코드를 다시 이해하는 과정이었습니다. 처음에는 회의적으로 시작했지만, 결과적으로 리팩토링을 시작하기 전에 반드시 거쳐야 할 중요한 단계였다는 것을 체감하게 되었습니다.
'탭탭 - TapTap > 리팩토링' 카테고리의 다른 글
| [리팩토링] 05. Swift Concurrency로 메모리 누수와 Callback 지옥을 해결해보자 (온보딩 리팩토링). (0) | 2026.01.19 |
|---|---|
| [리팩토링] 03. 구조개선 - App진입점을 TCA로 컨버팅 (1) | 2026.01.15 |