랠리에디터 / 2024.06 ~ 2025.05
랠리에디터 flatTree 상태 모델
TL;DR
랠리에디터는 여러 타임라인과 Rally motion을 엮어 하나의 큰 인터랙션 모션을 만드는 내부 에디터였어요. 상태는 Zustand 기반의 id → node map으로 관리했고 각 노드가 parentId, childrenIds, isRoot 같은 관계 정보를 담는 flatTree에 가까운 구조였어요.
문제 정의 Problem
랠리에디터에서는 프리뷰나 외부 저장 구조에 맞춰야 하는 제약이 거의 없었어요. 데이터 형식과 저장 방식도 우리가 직접 정했고 하나의 SSOT를 기준으로 타임라인, 좌측 패널, 설정창이 같은 데이터를 바라보게 했어요. 처음부터 거창한 상태관리 아키텍처를 설계한 건 아니에요. 익숙한 Zustand로 기능을 하나씩 만들기 시작했는데 수정이 자주 일어나는 에디터 특성상 id로 노드를 찾고 관계를 관리하는 구조가 자연스럽게 자리 잡았어요.
여러 타임라인과 Rally motion을 연결해 하나의 큰 인터랙션 모션 타임라인으로 구성해야 했기 때문에, 특정 노드를 빠르게 찾고 수정하는 상태 구조가 중요했어요.
접근 방식 Approach
Zustand store 안에 id → node map을 두고 각 노드의 관계를 parentId와 childrenIds로 표현하는 flatTree 구조로 접근했어요. 각 노드는 id 기반 map에 저장하고 parentId, childrenIds, isRoot 같은 관계 정보로 계층을 표현했어요. 이렇게 연결한 여러 타임라인과 Rally motion이 하나의 큰 인터랙션 모션 타임라인을 이루도록 데이터 구조를 잡았어요. 세 화면은 이 데이터를 기준으로 필요한 부분만 나눠 구독하는 구조로 뒀어요.
수정할 노드의 id만 알면 map에서 O(1)에 가까운 방식으로 접근했고 값 수정도 단순했어요. 삭제나 복제처럼 관계를 따라가야 하는 동작은 parentId와 childrenIds를 기준으로 처리했어요. 중간 노드를 삭제할 때는 연결된 child를 따라 leaf 노드까지 내려가며 함께 제거했어요. 세 화면이 같은 SSOT에서 필요한 데이터만 나눠 구독했고 추가·수정·삭제처럼 반복되는 편집 동작은 공통 모듈로 묶어 재사용했어요.
핵심 결정 Decision
트리 객체 대신 flatTree에 가까운 id map 구조를 썼어요. Zustand 기반 id → node map을 두고 parentId와 childrenIds로 관계를 관리했어요. 이 구조가 아니면 불가능한 기능이 있던 건 아니에요. 트리 구조로도 타임라인 편집, DnD, 설정 변경 같은 기능은 만들었을 거예요. 다만 랠리에디터처럼 데이터 소유권이 우리에게 있고 프리뷰나 외부 데이터 구조와 계속 동기화할 제약이 적은 환경에서는 flatTree가 꽤 잘 맞았어요.
트리 형태로 다시 재구성해야 하는 순간에는 복잡도가 생겼어요. 예를 들어 중간 노드를 삭제하면 leaf 노드까지 타고 내려가며 제거해야 했고 관계 정합성도 직접 관리해야 했어요.
해결 결과 Result
세 화면이 같은 SSOT를 보고 있다 보니, 타임라인에서 값을 바꾸면 그 값을 쓰는 UI가 함께 최신 상태로 갱신됐어요. id 기반 map 덕분에 특정 데이터를 수정하는 것도 빠르고 단순했어요. 비슷한 형태로 반복되는 편집 동작은 공통 모듈로 묶기 쉬웠고 이 점은 개발 경험 측면에서도 좋았어요.
배운 점 Learning
처음부터 flatTree라는 개념을 알고 적용한 건 아니에요. 자료구조를 공부하며 봤던 Linked List처럼, 수정이 자주 일어나는 구조라면 앞뒤 연결이나 부모-자식 관계를 들고 있으면 편하지 않을까 생각하며 만든 구조였어요. 나중에 확인해보니 이 방식이 flatTree라고 부르는 구조에 가까웠어요. 공부했던 자료구조가 실제 구현 판단으로 이어졌다는 점이 기억에 남아요.
이 작업을 다시 한다면 Next
다시 만든다면 데이터 구조나 인터페이스 설계를 먼저 하고 시작할 것 같아요. 당시에는 기능을 하나씩 만들다 보니 운 좋게 랠리에디터에 잘 맞는 구조가 자리 잡았지만 다음에도 같은 방식으로 최적의 구조가 나온다고 장담하긴 어려워요. 처음부터 데이터가 어떻게 저장되는지, 어떤 화면에서 어떤 형태로 읽히는지, 어떤 동작에서 자주 바뀌는지를 먼저 정의하면 더 빠르게 안정성을 확보할 수 있다고 생각해요.