* 본 포스팅 내용은 2025.01에 실적용한 기술이며, 도입 과정에서 작성해둔 내용을 기반으로 서술하였습니다.
✏️ 개요
사내에서 처음으로 프로젝트/테크 리더를 맡아 주도적으로 개발을 진행했던 🔗JA Korea - Finance Park 프로젝트에서 Three.js를 도입한 서비스를 개발하다 겪은 직접 QA를 하다 발견했던 Corner case Fix 경험담입니다.
우선 Three.js를 활용하게 된 계기부터 말씀드리자면 초기 기획에서 사용자가 학생이라는 점을 고려하여 재미있고 동적이었으면 좋겠다. 라는 의견이 나와 3D오브젝트의 활용까지 고려 가능한 Three.js를 도입하는 것이 좋을 것 같아 기술 제안을 하였고 "확장 가능성과 애니메이션 최적화를 고려했을 때 적합하다" 라는 의견으로 취합되어 채용하게 되었습니다.
사실 해당 프로젝트는 긴급하게 수주한 건이었고 약 2개월만에 MVP를 완성해야 하는 프로젝트였기 때문에 Three.js의 도입을 처음에는 망설였지만, 취업준비 당시 Thee.js를 독학하여 🔗3D 포트폴리오를 만들어본 경험이 있어 주도하여 대표님께 프로젝트를 맡겠다고 제안하였고 채택되었습니다. 긴급하게 고객사에 제공해야 하는 만큼 빠르게 개발하기 위해 Next.js + Prisma 기반 서버리스 아키텍처를 선택하여 긴급하게 시작했습니다.
❓ 나는 어떤 서비스를 개발하는가
우선 Finance Park에 대해서 소개드리자면 JA Worldwide 글로벌 재단이 존재하고 한국 지부로 JA Korea 사업단에서 주도하는 경제 학습 플랫폼입니다.
총 9가지 섹션의 소비 컨텐츠가 Map Object위에 존재하고 상호작용을하며 경제 활동 시뮬레이션을 통해 체험하고 예측 불가한 지출/수입에 대한 이벤트도 존재하며 현금과 신용카드를 활용하고 투자/예금 등 다양한 경제 활동을 시뮬레이션 할 수 있는 플랫폼입니다.
국제 사업단인 만큼 다양한 나라에서 저학년 학생들에게 학습 목적으로 Finanace Park 플랫폼을 만들어 서비스를 하고 있습니다.
저희가 레퍼런스로 잡은 플랫폼은 홍콩에서 제작한 🔗Finance Park - Hong Kong이었습니다.
기본적으로 시뮬레이션 입장 시 Map같은 화면을 움직이며 클릭하고 경제활동을 시뮬레이션할 수 있는 학습 서비스를 제공하고 있었습니다.
🚨 시작부터 난관
무난하게 첫 세팅을 끝내고 서버 작업을 본격적으로 시작하려 했지만 이전부터 주 SI/SM 고객사에서 추가적인 고도화 작업을 요구하여 서버작업은 일시 중단 되어 작업기간이 더욱 더 촉박해질 수 밖에 없는 상황이었습니다.
다행이 이를 인지한 대표님께서 인원을 추가 채용하여 제가 프론트엔드에 주력할 수 있도록 백엔드 포지션인 동료를 함께 참여 시켜주셨습니다. 덕분에 빠듯하고 빠른 이터레이션을 요구하는 상황에서도 좀 더 신경써서 프로젝트를 진행할 수 있게 되었습니다.
하지만 같이 프로젝트를 진행하게 된 새로운 동료분께서 현재 Next.js의 버전이 14인데 앞으로 유지보수를 생각하면 15버전으로 진행하는게 좋다고 하였고, 조금 걱정이 되었지만 수용하는 태도 또한 중요한 덕목이니 도전하는 마음으로 "이 또한 나의 성장의 밑거름이다!" 생각하며 즉시 15버전으로 마이그레이션을 하고 작업을 진행하였습니다.
허나, 이 것이 화근이었고 React + Three.js와 활용하기 좋은 React Three Fiber( 일명 R3F )가 아직 Next15를 지원하지 않는 것이었습니다. 그래도 괜찮을 것이라 굳게 믿으며 작업을 진행했는데 결국 모든 기능을 Next/React 스럽지 못하게 개발을 하게 되었습니다...
마치 Vanilla JS처럼 구현하게 되었습니다ㅠㅠ
다음 마이그레이션을 기약하며 아쉬운 마음으로 우선 작업기간이 짧은 만큼 기능 구현에 힘을 싣고 개발을 진행했습니다.
🛠️ Three.js Camera 포지션 제한, 제어 구현하기
우선 이왕 만드는거 레퍼런스 사이트보다는 더 향상된 품질로 만들고 싶었습니다.
저희 팀에서 확인했을 때 크게 3가지 문제가 두드러지게 나타났습니다.
1. 시뮬레이션 화면에 입장 시 미친 듯이 돌기 시작하는 노트북의 팬
➔ 기본적으로 구현에 급급하였는지, 메모리 누수가 심각한 수준
2. 사이드바에 가려지는 경제활동 컨텐츠
➔ 3가지 컨텐츠를 Map화면에서 즉시 볼 수 없고 사이드바를 접거나 직접 사이드바에서 접근해야 함
3. 줌인과 줌아웃, 포커싱 등 Three.js를 활용한 Map화면 장점의 부재
➔ 동적이고 재미요소를 줄 수 있는 장점이 있음에도 활용하지 않고 단순하게 표현 부분이 아쉬웠음
우선 기본적으로 디자인 된 Map형태 이미지를 최대한 최적화하여 Webp로 추출하였고 Three.js를 활용하여 Plane Mesh를 만들어 이미지를 Map의 바닥 오브젝트로 구현하였습니다.
그리고 맵의 크기 만큼 카메라 포지션이 고정되도록 계산하여 제한하는 함수를 만들었고
문제는 이제부터 시작이었습니다.
💫 NaN... 이 수모를 잊지 않겠다...

분명 제대로 한 것 같았습니다.
만약 x, y, distanceZ params가 제대로 number형이 아니라면 typescript가 컴파일에서부터 에러를 발생시키기 때문에 제대로 문제가 생기면 에러를 발생시키기 때문에 디버깅은 문제 없을거라고 생각했습니다.
하지만... 이상하게 단위 테스트를 진행하며 개발하는데 어느 순간 제대로 작동하지 않고 카메라 핸들링 기능 자체가 멈춰버리는 상황이 생겨버렸습니다.
상세히 테스트를 해 보았고 기나긴 케이스 테스트 끝에 x, y, distanceZ가 마우스를 드래그한 채 브라우저 바깥영역으로 나갔다가 들어오는 경우에 브라우저 내 이벤트 입력 간격이 매우 짧아 졌을 때 x, y, distanceZ에서 NaN이 들어오게 되는 엣지케이스를 발견하게 되었습니다.
NaN는 number타입이기 때문에 typescript에서 에러를 발생시키지 않은 것이었습니다...
typescript로 number니까 undefined나 null이면 제대로 디버깅이 될 것이라는 생각을 한 것 자체가 안일했구나... 하며 반성을 하게 되는 계기였습니다.ㅠ
만약 String을 Number로 형변환을 강제하는 로직이라면 반드시 isNaN으로 검증하자! 라는 교훈을 얻었습니다.

이렇게 isNaN을 통해 x, y, distanceZ의 타입을 초입에 검증하는 방식으로 어느 순간 카메라가 핸들링 되지 않는 코너케이스를 해결한 경험을 쌓았습니다...
🧨 이번에는 맵 이탈...
이번에도 단위 테스트를 진행하다가 얻게된 코너케이스 경험담입니다.
줌 기능을 추가로 구현하고 여러 케이스를 테스트를 하다보니 어느 순간 맵 바깥 영역이 보이기 시작했습니다.
바로 최대로 줌인을하고 모서리 끝으로 이동 후 줌아웃을 하면 제한된 영역 바깥이 보이는 코너케이스가 발견되었습니다.
이 문제는 단순히 드래그앤 드랍으로 카메라 포지션을 x, y 축으로 제한 이동하던 프로세스를 기반으로 아이디어를 만들어 단위 정복하여 기능을 추가하고 해결했습니다.
- 휠 이벤트가 발생 시 줌 레벨을 기반으로 수치화된 값을 얻는다
- 수치화된 값을 제한된 Map 바깥 영역 수치에 넘어서지 않는지 검증한다.
- 검증을 기반으로 넘치는 수치와 방향을 저장한다.
- 저장된 방향과 수치를 Commit하여 실제 기능을 수행한다.
위와 같은 4가지 단계로 나누어 설계하고 프로세스를 구현하여 성공적으로 문제가 되던 코너케이스를 해결하였습니다.
🔗 코너케이스가 해결된 시연 영상
🚩결과
가장 큰 성과로 첫 번째는 "Number로 형변환 되는 경우 반드시 isNaN을 통한 검증 거치자"라는 교훈을 얻은 것이었습니다.
Typescript가 만능은 아니다. 라는 것을 깨닫고 zod를 활용하는 이유에 대해서도 더 알아보는 계기가 되었습니다.
두 번째로는 기능을 구현 할 때에는 단위정복을 해 나아가는 동시에 [ 계산단계 ] ➔ [ 커밋단계 ] 처럼 계산 후 마지막으로 적용하는 관심사 분리 설계에 대한 중요성을 다시금 깨닫는 계기였고, 이를 통해 React의 Fiber 아키텍처에서 Render phase와 Commit phase로 나누어 설계된 의미를 작게나마 이해 할 수 있었습니다.
'Dev Logs' 카테고리의 다른 글
| [ React + Vite & NginX: Gzip Compression ] 번들 사이즈 최적화로 UX향상 시키기 (2) | 2025.11.22 |
|---|---|
| [ React: PDF Generator ] 맞춤형 PDF 렌더링 성능 최적화 (2) | 2025.11.20 |
| [ Python: Async HTTP ] 사내 LLM 챗봇 서버 비동기 전환을 통한 요청 취소 및 논블로킹 구조 개선기 (3) | 2025.11.15 |
| [ openapi-generator-cli ] 사내 API 생성 자동화 도입기 (3) | 2025.11.13 |
| [ Error Fix ] Unable to find git in your PATH. (2) | 2025.01.01 |