레이어 패널의 성능 개선 | Figma 블로그 (새 탭에서 열림)
Figma는 대규모 파일에서 레이어 패널의 느린 상호작용을 해결하기 위해 아키텍처를 전면 재설계했다. 행 목록 계산과 노드 상세 정보 계산을 분리하고, 파생 속성(derived properties)을 활용해 변경된 부분만 다시 계산한 결과, 가장 복잡한 파일에서 일부 상호작용이 30~50% 빨라졌다. 핵심은 보이지 않는 레이어까지 계산하지 않고, 필요한 데이터만 지연 계산·캐싱하는 것이다. ## 레이어 패널 성능 저하의 원인 - 레이어 패널은 Figma 파일의 노드 트리를 중첩된 목록으로 표현한다. - 초기 아키텍처는 파일의 각 노드에 대해 이름, 아이콘, 표시 여부, 잠금 상태 등 UI에 필요한 데이터를 하나의 큰 JavaScript 객체로 구성했다. - 레이어가 변경될 때마다 확장된 모든 노드에 대해 데이터를 처음부터 다시 계산했다. - 파일이 수만 개의 레이어를 포함하게 되면서 두 가지 문제가 발생했다. - **계산량 과다:** 화면에 실제로 보이는 행은 보통 20~30개뿐인데, 확장된 모든 노드의 데이터를 계산했다. - **재계산 빈도 과다:** 레이어 하나를 확장하거나 변경해도 전체 데이터를 다시 생성했다. ## 1단계: 두 번에 나누어 계산하기 - 데이터 수집 과정을 두 단계로 분리했다. - 첫 번째 단계에서는 패널에 표시될 **행 ID의 순서**만 계산한다. - 이 과정도 단순하지 않으며 다음과 같은 제품 규칙을 반영해야 한다. - 오토 레이아웃 프레임의 자식은 역순으로 표시될 수 있다. - 위젯이나 FigJam 스티키처럼 자식 노드를 패널에 표시하지 않는 노드가 있다. - 프로토타이핑 프레임의 고정 헤더와 스크롤 헤더는 자식을 두 영역으로 나눈다. - 최상위 프레임과 컴포넌트는 고정된 위치에 표시된다. - 두 번째 단계에서는 첫 단계에서 얻은 행 ID 중 현재 화면에 보이는 노드만 대상으로 상세 데이터를 계산한다. - 기존에도 화면 밖 항목을 렌더링하지 않는 윈도잉(windowing)을 사용했지만, 데이터 계산 자체는 모든 확장 노드에 대해 수행되고 있었다. - 새 구조에서는 이름, 아이콘, 잠금·표시 상태, 선택 상태 등을 실제로 필요한 수십 개 행에 대해서만 계산한다. - 그 결과 수십만 개 노드의 데이터를 계산하던 작업을 화면 주변의 작은 범위로 줄였다. ## 2단계: 파생 데이터 캐싱 - 변경되지 않은 레이어를 다시 그리거나 재계산하지 않고, 바뀐 부분만 갱신하도록 개선했다. - 이를 위해 Figma가 플랫폼 차원에서 개발한 **파생 속성(derived properties)** 기능을 사용했다. - Figma 노드는 직접 저장·조회할 수 있는 필드(fields)를 가진다. - 하지만 일부 속성은 직접 저장하지 않고 다른 필드와 속성으로부터 계산된다. - 예를 들어 노드는 부모 기준의 상대 위치만 저장하고, 절대 위치는 다음과 같이 계산할 수 있다. ```text Self.AbsolutePosition = Parent.AbsolutePosition + Self.RelativePosition ``` - 파생 속성 시스템은 이런 계산 관계를 명시적으로 선언하고, 의존하는 값이 바뀌면 최신 상태를 유지하도록 한다. - 시스템의 장점은 다음과 같다. - 각 파생 속성이 어떤 필드와 다른 파생 속성에 의존하는지 추적한다. - 의존 관계가 최적화된 그래프 형태로 컴파일된다. - 속도와 메모리 사용량 사이의 선택을 고려한 여러 캐싱 정책을 제공한다. - 기본적으로 지연 계산(lazy evaluation) 방식이어서 실제로 읽을 때만 계산한다. - 레이어 패널은 부모-자식 트리 구조를 갖기 때문에 파생 속성과 자연스럽게 결합된다. - 이전에는 트리 어디에서든 변경이 발생하면 노드 데이터를 전체적으로 다시 계산했지만, 새 구조에서는 의존 관계를 바탕으로 영향을 받은 데이터만 갱신할 수 있다. ## 성능 개선의 의미 - 대규모 Figma 파일에서 레이어 패널의 스크롤, 확장·축소, 선택 등의 상호작용이 더 빨라졌다. - 레이어 패널의 계산 비용이 줄어들면서 드래그나 텍스트 입력 같은 에디터의 다른 작업에도 영향을 주던 지연이 완화됐다. - 윈도잉만 적용하는 것보다, **계산 대상 자체를 가시 영역으로 제한하는 것**이 중요하다는 점을 보여준다. - UI 성능을 높이려면 다음 두 문제를 별도로 해결해야 한다. - 불필요한 항목까지 계산하는 문제 - 같은 항목을 반복해서 계산하는 문제 ## 실용적인 결론 대규모 트리형 UI에서는 렌더링만 가상화하는 것으로 충분하지 않다. 먼저 화면에 필요한 항목의 ID나 구조만 계산한 뒤, 실제 표시되는 항목의 상세 데이터만 지연 계산하고, 의존성이 변한 부분만 캐시를 무효화하는 방식이 효과적이다.