2025년도 개발 회고
2024년 9월에 Vueron 에 합류 후 PCD 기반 3D 라벨링 툴을 웹 버전으로 프로토타입 제작하였고, 2025년 1월이 되어 팀을 이동하였다. 혼자서 프로젝트를 이끌어가기에는 기술적 한계가 명확했고, 이를 스스로 극복하기 위한 역량 또한…
2025년도 개발 회고

X Factory
2024년 9월에 Vueron 에 합류 후 PCD 기반 3D 라벨링 툴을 웹 버전으로 프로토타입 제작하였고, 2025년 1월이 되어 팀을 이동하였다. 혼자서 프로젝트를 이끌어가기에는 기술적 한계가 명확했고, 이를 스스로 극복하기 위한 역량 또한 보완이 필요함을 느꼈다. 다행히 사내에 SW 개발자가 있는 플랫폼 팀이 있었기에 플랫폼 팀으로 인사 이동을 하였다.
2025년도의 팀 미션은 단순명쾌 하였다. 바로 “사내 데이터 라벨링 시스템 구축 및 제품화(SaaS)를 위한 플랫폼 개발(X Factory)”
사내에서 사용하던 기존 라벨링 툴은 내가 딥네츄럴(라벨링 크라우드 서비스) 당시에 만들었던 라벨링 툴과는 다르게 훨씬 단순한 라벨링 툴(라벨링 툴 기능이 단순한 것이 아닌 시스템이 단순하다는 의미)이었다. 사용자가 직접 프로그램을 설치하여 사용하는 것이었고, 사용자 인증 및 권한, 데이터 관리 등 현재 대부분의 라벨링 서비스들이 제공하는 것들 없이 단순히 라벨링만 가능했다.
다만, 단순하다고 해서 라벨링 툴 자체가 문제가 있는 것은 아니었다. 라벨링을 위한 PCD 파일은 작으면 2, 3MB 고 크면 20MB 에 육박했다. 그리고 PCD 파일은 100개, 200개 정도가 아닌 최소 1000개 이상이었다. 기존 툴은 로컬에 설치를 하는 방식이었고 툴 자체도 C-based 언어로 만들어진 툴이라 파일 IO 와 PCD 파일의 파싱이 빨랐고, 그런 부분에 있어서는 확실히 강점이 있었다.
그렇지만 딱 거기까지였다. 기존에는 시스템이 없었다. 라벨링 데이터는 NAS 를 통해 수동으로 관리 되고 있었고, 라벨링 작업 일지는 스프레드시트를 통해 수동으로 관리 되고 있었다. 라벨링 시스템에서 당연히 필요한 검수(리뷰)는 다른 사람이 작업한 결과물 파일을 자신의 PC로 옮겨서 확인해야 했고 검수에 대한 피드백은 그림판으로 스크린샷을 첨부하여 공유하는 방식이었다.
라벨링 툴 기능을 웹에서 사용 가능하도록 하는 것과 라벨링 시스템을 체계적으로 할 수 있도록 웹 기반의 라벨링 시스템을 구축하는 것이 25년도에 해야할 가장 큰 미션이었다.
이러한 미션을 달성하기 위해 어려움을 겪었던 부분은 크게 두 가지였다.
- PCD 파일 관리
- 3D 렌더링
PCD 파일 관리는 Object Storage(MinIO — 사내 전용 / S3 — SaaS 고객 전용) 를 통해 이뤄졌다. 처음에는 라벨링 서비스를 이용하는 사용자가 직접 Object Storage 에 파일 업로드/다운로드를 할 수 있도록 구현을 했었다. Client 레벨에서 직접 Object Storage 에 접근 했는데, 추후 여러 문제와 추가 기능(페이지네이션 문제 및 폴더 다운로드, presigned url 을 통한 파일 업로드 등)으로 인해 다운로드 이외에는 전부 어플리케이션 서버를 통해 수행 하도록 변경이 됐다.
특히 다운로드 구현 과정에서 기술적으로 공유하고 싶은 시행착오가 많았다. 단순히 파일을 다운로드 받는 것은 큰 문제가 없었지만, 라벨링 툴에서 렌더링 해야 하는 PCD 파일을 다운로드 하는 것은 많은 시행착오가 있었다.
PCD 파일 용량이 크기 때문에 사용자가 파일 다운로드 횟수를 최소화하는 것과 파일을 최대한 빨리 받을 수 있도록 하는 것이 관건이었다. 두 가지의 목표를 이루기 위해서는 캐싱 전략은 당연히 필요했다. 전자의 경우에는 브라우저의 indexedDB 를 활용하여 한 번 받은 PCD 를 로컬에서 즉시 꺼내오도록 했고, 후자의 경우에는 CloudFront 를 이용해 비교적 쉽게 해결을 하였다.
indexedDB 를 활용한 캐싱 전략은 내가 이전부터 종종 사용하던 전략이었다. localStorage 와는 다르게 TypedArray 를 그대로 보존시켜 활용 가능하고 Web Worker 를 통한 제어가 가능하기 때문에 이번에도 알차게 잘 활용하였다.
“CF(CloudFront) 를 통해 캐싱이 되어 있다면 굳이 indexedDB 를 사용해야 하는가?” 라는 의문이 있을 수 있다. CF 가 적용되어 캐싱이 된 상태라고 해도 PCD 파일 용량 자체가 크기 때문에 최소 50ms 정도는 걸렸다. 거기에 더해서, 그렇게 받아온 PCD 파일은 다시 파싱 과정을 거쳐야 하기 때문에 추가로 시간이 소요됐다.
라벨링 툴 진입 후 PCD 파일 다운로드는 또다른 문제를 발생 시켰는데, 바로 다음 frame 에 해당하는 PCD 파일을 prefetch 를 해와야 하는 것이었다. 원활한 작업을 위해 현재 frame 에서 뒤로 1개 앞으로는 10개, 총 11 개의 PCD파일을 prefetch 해와야 했다. 다운로드와 파싱을 모두 main thread 에서 하다보니 PCD 렌더링에서 많은 fps 하락이 있었고 결국 PCD 다운로드 부터 파싱, indexedDB 적재 하는 것 까지 전부 Web Worker 에서 수행하도록 했다.
3D 렌더링 역시 많은 난관이 있었다.
웹에서 PCD 파일의 렌더링은 이미지 처럼 과정은 단순하지만, 막상 해보면 그렇게 단순하지는 않았다. PCD 파일을 파일 서버에서 다운로드를 받은 후 받은 PCD를 렌더링 하기 위해 Float32 형태로 파싱하는 과정이 필요했다. three.js 에서 제공해주는 PCDLoader 를 이용하면 위 과정을 코드 한 줄로 쉽게 끝낼 수 있지만, PCDLoader 는 실제 라벨링 툴에서 사용하기에는 쉽지 않았다.
PCDLoader 는 PCD 파일을 매번 불러올 때 마다 Geometry 객체를 새롭게 생성했다. three.js 가 기본적으로 제공하는 모든 객체들이 대체로 많은 메모리를 차지하는데, Geometry 는 그 중에서도 제법 많은 메모리를 차지 하는 객체다. 따라서 1000여 개가 넘는 PCD 를 PCDLoader 를 통해 불러오면 Geometry 역시 PCD 파일과 1:1 대응하여 생성이 되는 치명적인 문제가 있었다. 물론 해당 Geometry 를 dispose 를 해주면 되지만, 생성 -> dispose 가 빠르게 반복되면 브라우저의 GC 가 즉각적으로 이뤄지지 않는 문제가 발생하여 GC 가 한번에 몰아서 발생하였다.
따라서 PCDLoader 의 코드에서 PCD 파싱 부분만 가져오고 그 외 Geometry, Material 은 PCD 개수가 몇 개던 하나만 사용하는 방법으로 직접 커스텀하게 작성을 했다. Geometry 의 attribute(position, color buffer)를 직접 업데이트를 해주면 매번 Geometry 를 생성할 필요 없이 새로운 PCD 를 렌더링 할 수 있었기 때문이다.
3D 렌더링은 위의 작업에 더해 라벨링 박스(cuboid / 3d bounding box) 를 렌더링 하는 것과, 해당 라벨링 박스 안의 PCD 포인트 색상을 변경하는 것, Semi Annotation 을 위한 PCD 포인트 자료 구조화 작업이 추가로 더 있었다.
라벨링 박스 렌더링은 비교적 쉬운 작업에 속했다. 다만 연말까지 끝까지 발목을 잡은 것이 있었는데, 바로 메모리 누수였다. 라벨링 박스 렌더링 역시 Geometry 를 생성하여 렌더링 하는 것인데, frame 변경, 박스 자체의 변경(추가/삭제)이 이뤄질 때마다 생성 -> dispose 가 반복되었는데, 이 때 dispose 가 제 때 되지 않아 메모리가 계속 쌓이는 문제가 있었다. 지금은 Object pool 방식을 이용하여 최대한 불필요한 사이클을 줄이기 위해 작업 하고 있다.
라벨링 박스 안의 PCD 포인트 색상 변경은 초기에는 CPU 레벨에서 어떻게든 처리를 해보려고 했으나, 포인트가 60만(20MB 정도 되는 PCD 파일)개가 넘어가고 라벨링 박스도 100여개가 넘어 가는 경우 너무 긴 수행 시간 때문에 결국 GPU 레벨로 넘겼다. Shader 를 통해 GPU 리소스를 사용하도록 하였고, 눈에 띄는 성능 개선이 이뤄졌다.
PCD 포인트 자료 구조화는 Quad Tree 와 K-D Tree 를 사용하였다. 초기에는 두 작업 모두 Client 레벨에서 수행했는데, 역시나 많은 리소스를 사용하였다. 현재 Quad Tree 는 어플리케이션 서버에서 미리 처리하여 지금은 K-D Tree 구조화만 진행하고 있다. 이러한 구조화는 Semi Annotation 을 위해 필요했다. 라벨링 박스를 추가하고 싶은 PCD 영역에 드래그를 하여 자동으로 라벨링 박스를 추가하는 기능인데, 어플리케이션 서버를 거치지 않고 해야 했기 때문에 저러한 구조화가 필수적이었다.
파일관리와 렌더링 이외에 SaaS 지원을 위한 멀티 테넌트 인증, 라벨링 툴에서 라벨링 박스 편집을 위한 각종 이벤트 관리, 기존 사내 제품과 동일한 UI/UX 를 제공하기 위한 디자인 시스템 기반 UI 컴포넌트 구축 등 여러 쉽지 않은 요소들이 많았지만 팀 동료들 덕분에 제법 괜찮게 개발을 했던 것 같다.
2026년의 미션은 전년도와 마찬가지로 단순명쾌하다. “제품의 안정적인 운영과 성능 개선”
지난 한 해 함께 고생한 팀 동료들에게 감사의 마음을 전하며, 25년의 회고를 마치려고 한다.
X Factory 의 FE 개발 스택
- Core —
React,TypeScript,Vite,pnpm - 3D Rendering —
three.js,@react-three/fiber,@react-three/drei - State Management —
Zustand - Event Management—
RxJS,mitt - Data Fetching —
@tanstack/react-query,axios - Performance —
Web Worker,SharedWorker - Styling & UI —
TailwindCSS - Testing & QA —
vitest,playwright,unleash,msw
메타데이터
- post_id
- 4c907eaa04ed
- slug
- 2025년도-개발-회고-4c907eaa04ed
- url
- https://medium.com/@toaonly/2025%EB%85%84%EB%8F%84-%EA%B0%9C%EB%B0%9C-%ED%9A%8C%EA%B3%A0-4c907eaa04ed
- canonical_url
- https://medium.com/@toaonly/2025%EB%85%84%EB%8F%84-%EA%B0%9C%EB%B0%9C-%ED%9A%8C%EA%B3%A0-4c907eaa04ed
- author_url
- https://medium.com/@toaonly
- status
- ok
- fetched_at
- 2026-06-22 00:13:37