c-plus-plus

7 개의 포스트

google4분 읽기큐레이션 요약

선형 탄력적 캐싱으로 클라우드 비용 효율성 최적화

인메모리 캐시는 성능을 높이지만, 고정된 메모리 크기로 운영하면 수요가 낮을 때 비용이 낭비되고 수요가 많을 때 캐시 미스로 성능이 저하된다. 선형 탄력적 캐싱은 메모리 점유 비용과 캐시 미스 비용의 균형을 ‘스키 대여 문제’로 모델링해, 워크로드에 따라 페이지별 보관 시간과 캐시 크기를 동적으로 조정한다. Spanner 실험에서는 메모리 사용량을 15.5%, 총소유비용(TCO)을 약 5% 줄이면서 캐시 미스 증가는 5.5%에 그쳤다. ## 고정 크기 캐시의 비용 문제 - 기존 캐시는 미리 정한 메모리 용량 안에서 LRU 같은 정책으로 데이터를 제거한다. - 캐시가 너무 작으면 디스크나 다른 저장 시스템에 대한 접근이 늘어 성능이 떨어진다. - 반대로 피크 수요에 맞춰 캐시를 크게 잡으면 평상시 사용하지 않는 메모리 비용이 발생한다. - 특히 클라우드와 서버리스 환경에서는 메모리 용량과 사용 시간이 직접 비용으로 연결된다. ## 스키 대여 문제로 모델링한 캐싱 - 각 데이터 페이지는 다음 두 선택지 사이에서 판단된다. - **대여:** 데이터를 RAM에 유지하면서 메모리 비용을 계속 지불한다. - **구매:** 데이터를 제거해 메모리 비용을 아끼지만, 재요청 시 캐시 미스에 따른 지연 및 I/O 비용을 부담한다. - 페이지를 너무 오래 보관하면 메모리 비용이 커지고, 너무 빨리 제거하면 캐시 미스 비용이 커진다. - 전통적인 스키 대여 알고리즘은 누적 대여 비용이 재취득 비용과 같아지는 시점에 데이터를 제거하는 손익분기 전략을 사용한다. - 연구진은 최악의 경우를 보장하는 방식뿐 아니라, 실제 워크로드의 반복적인 접근 패턴을 학습해 더 나은 TTL을 예측하는 방법을 적용했다. ## TTL과 물리적 캐시 용량의 분리 - 이론적으로 캐시의 핵심 문제를 다음 두 부분으로 나눌 수 있음을 보였다. - 각 페이지를 얼마나 오래 보관할지 결정하는 문제 - 캐시가 실제로 가득 찼을 때 어떤 페이지를 제거할지 결정하는 문제 - 페이지 요청 시 스키 대여 알고리즘이 해당 페이지의 TTL을 계산한다. - TTL이 만료되기 전 재접근이 없으면 페이지를 자동으로 제거한다. - 캐시가 물리적으로 가득 차면 LRU 같은 전통적인 제거 정책이 보조적으로 작동한다. - 이 분리 덕분에 동적 캐시 크기 조절을 기존 캐시 시스템에 비교적 간단히 통합할 수 있다. ## Spanner의 경량 머신러닝 적용 - Spanner의 초당 수십억 건 요청을 처리하기 위해 TTL 예측 모델은 매우 가벼워야 했다. - 연구진은 몇 줄의 C++ 코드로 변환 가능한 얕은 결정 트리를 사용했다. - 모델이 고려한 주요 특징은 다음과 같다. - 데이터 페이지의 크기 - 캐시 미스 발생 시 데이터를 다시 가져오는 비용 - 수행되는 데이터베이스 연산의 유형 - 페이지의 과거 접근 패턴 - 결정 트리는 해석 가능하므로, 어떤 데이터가 오래 캐시할 가치가 있는지도 분석할 수 있다. ## Spanner 운영 환경의 실험 결과 - 고정 크기 캐시와 비교했을 때: - 메모리 사용량 **15.5% 감소** - 캐시 미스 **5.5% 증가** - 총소유비용(TCO) 약 **5% 감소** - 캐시 미스 증가는 비용이 낮은 데이터에 집중됐다. - 저장 시스템에 실제로 발생한 I/O 비용 증가는 약 **0.5%**에 불과했다. - 즉, 모든 캐시 미스를 동일하게 줄이기보다, 재취득 비용이 큰 데이터는 유지하고 저렴한 데이터는 적극적으로 제거하는 비용 인식형 전략이 효과적이었다. ## 공개 캐시 트레이스 검증 - Google 인프라에만 특화된 결과인지 확인하기 위해 다양한 공개 캐시 추적 데이터를 사용했다. - 고정 크기 캐시의 기준 정책으로는 페이지 크기가 서로 다른 상황을 처리할 수 있는 GDSF를 사용했다. - 여러 탄력적 캐시 변형을 비교했다. - 손익분기 스키 대여 정책 - 무작위화된 스키 대여 정책 - 학습된 TTL을 사용하는 정책 - 애플리케이션 수준의 특징이 없는 공개 데이터에서는 각 페이지별 최적 TTL을 학습했다. - 트레이스를 학습과 테스트로 나누고, 테스트 전에 일정 기간 캐시를 채우는 워밍업 절차를 적용했다. - 학습 데이터에서 관찰된 페이지는 미리 계산한 TTL을 사용하고, 처음 등장한 페이지는 기본 스키 대여 정책으로 처리했다. ## 다양한 워크로드에서의 효과 - 실험 결과, 탄력적 캐싱은 다양한 워크로드에서 고정 크기 캐시보다 일관되게 낮은 비용을 보였다. - 메모리 비용이 캐시 미스 비용보다 비싸질수록 탄력적 캐싱의 절감 효과가 커졌다. - 비슷한 메모리 규모를 사용하는 경우에도 탄력적 정책이 더 낮은 캐시 미스율을 보였다. - 캐시 크기를 수요에 맞춰 자동 조정하기 때문에 유휴 메모리 낭비를 줄이면서 성능을 유지할 수 있다. 실무에서는 모든 페이지를 동일하게 취급하는 LRU만 사용하기보다, 페이지 크기와 재조회 비용을 반영해 TTL을 차등 설정하는 방식이 유용하다. 특히 메모리 비용이 높고 데이터별 재취득 비용 차이가 큰 클라우드 데이터베이스에서는 선형 탄력적 캐싱을 적용해 비용 절감 효과를 측정해볼 만하다.

원문 읽기(새 탭에서 열림)
gitlab3분 읽기큐레이션 요약

Claude Code와 GitLab: 실제 배포로 이어지는 세 가지 워크플로

Claude Code는 코드 작성과 디버깅을 빠르게 수행하지만, 실제 배포에는 CI/CD, 보안 검사, 코드 리뷰, 승인 등 추가 과정이 필요하다. 이 글은 Claude Code와 GitLab을 결합해 버그 수정부터 머지 리퀘스트, 검증, 리뷰, 배포까지 연결하는 세 가지 워크플로를 소개한다. GitLab MCP와 Duo Agent Platform을 활용하면 AI가 로컬 코드뿐 아니라 이슈와 과거 개발 맥락까지 반영할 수 있다. ## 코드 수정과 GitLab 검증 파이프라인 연결 - C++로 작성된 Arduino IoT Collector가 `/dev/ttyACM0` 장치가 없을 때 충돌하는 버그를 예제로 사용한다. - `cmake`로 프로젝트를 빌드하고 실행해 문제를 재현한다. - Claude Code에 버그 수정을 요청하면 코드베이스를 탐색해 `main.cpp`의 `std::runtime_error` 예외가 애플리케이션을 즉시 종료시키는 원인임을 찾는다. - 수정 방향은 예외로 프로세스를 중단하는 대신 사용자 친화적인 설정 오류를 기록하고 애플리케이션은 계속 실행하도록 바꾸는 것이다. - 수정 후 Claude Code 또는 직접 Git 명령으로 다음 작업을 수행한다. - 수정 브랜치 생성 - 변경 사항 커밋 - 원격 저장소에 푸시 - 머지 리퀘스트 생성 - MR이 생성되면 GitLab이 자동으로 다음을 수행한다. - 빌드 및 테스트를 위한 CI/CD 파이프라인 실행 - 새 취약점이 추가되지 않았는지 보안 스캔 - GitLab Duo Code Review를 통한 코드 정확성 및 스타일 검토 - 코드 리뷰에는 프로젝트의 C++ 개발 규칙과 사용자 정의 리뷰 지침도 적용할 수 있다. ## GitLab MCP로 이슈와 개발 이력 활용 - 로컬 저장소만 이용하면 Claude Code가 버그 리포트, 디버깅 논의, 과거 MR의 해결 방식 등을 알 수 없다는 한계가 있다. - GitLab MCP Server를 연결하면 Claude Code가 GitLab의 SDLC 맥락을 함께 조회할 수 있다. - 관련 이슈와 설명 - 이슈 댓글 및 논의 - 과거 머지 리퀘스트 - 유사한 버그의 수정 이력 - 프로젝트 내 개발 정보 - GitLab 인스턴스 또는 최상위 그룹에서 MCP Server를 활성화한 뒤, Claude Code에 HTTP 방식으로 추가한다. ```bash claude mcp add --transport http GitLab https://gitlab.example.com/api/v4/mcp ``` - 새 Claude Code 세션에서 `/mcp`를 실행하고 브라우저 OAuth 인증을 완료한다. - MCP 도구 목록과 서버 버전을 질의해 연결 상태를 확인할 수 있다. - MCP는 Claude에 추가적인 맥락을 제공할 뿐 권한을 상승시키지 않는다. - Claude Code는 인증한 사용자가 원래 접근할 수 있는 프로젝트와 이슈만 볼 수 있다. - GitLab의 프로젝트·그룹 멤버십과 가시성 설정을 우회하지 않는다. - 별도의 관리자 권한을 자동으로 부여하지 않는다. ## Claude Code와 GitLab Duo Agent Platform의 역할 분담 - Claude Code는 터미널이나 IDE에서 코드 탐색, 버그 수정, 기능 구현을 담당한다. - GitLab은 변경 사항을 실제로 출하하기 위한 중앙 플랫폼 역할을 한다. - CI/CD - 보안 검사 - 코드 리뷰 - 승인 절차 - 감사 가능한 변경 이력 - 세 번째 워크플로에서는 GitLab Duo Agent Platform의 외부 에이전트가 Claude를 활용해 MR의 코드 리뷰 피드백을 직접 반영한다. - 따라서 개발자가 리뷰 댓글을 수동으로 해석하고 수정하는 대신, 에이전트가 MR 맥락에서 코드를 변경하고 후속 검증까지 진행할 수 있다. ## 필요한 개발 환경 - 터미널에서 실행 가능한 Claude Code - 버그와 기능 제안 이슈가 등록된 GitLab 프로젝트 - 필요에 따라 GitLab MCP Server와 GitLab Duo Agent Platform 외부 에이전트 - C++ 예제 실행 시: - CMake - Make - gcc 또는 clang++ - Java 프로젝트를 다룰 경우 Maven - 예제 프로젝트를 클론한 뒤 `claude` 명령으로 Claude Code를 실행하고 프로젝트 목적을 먼저 질의할 수 있다. 실무에서는 Claude Code를 코드 작성과 문제 해결에 사용하고, GitLab을 CI/CD·보안·리뷰·승인의 통합 관문으로 두는 방식이 효과적이다. 특히 GitLab MCP를 연결하면 AI가 단순히 현재 파일만 보고 추측하지 않고, 실제 이슈와 과거 변경 이력을 근거로 더 일관된 수정을 제안할 수 있다.

원문 읽기(새 탭에서 열림)
discord3분 읽기큐레이션 요약

Discord의 소셜 SDK

Discord는 게임 개발자가 Discord의 소셜 기능을 게임 안에 직접 통합할 수 있도록 Discord Social SDK를 무료로 공개했다. C++, Unreal Engine, Unity 기반 게임에서 친구 목록, 초대, 리치 프레즌스, 메시지와 음성 채팅을 연결해 게임 안팎의 소셜 경험을 강화하는 것이 목표다. 현재 Windows 11 이상과 macOS를 지원하며, 콘솔과 모바일 지원은 추후 제공될 예정이다. ## Discord Social SDK의 목적 - 플레이어가 게임과 Discord 사이를 오가며 친구·팀원과 소통할 수 있도록 지원한다. - Discord 계정이 없는 플레이어도 게임 내에서 통합된 소셜 기능을 이용할 수 있다. - Discord의 2억 명 이상 월간 활성 사용자 기반에서 검증된 커뮤니케이션 기능을 게임에 적용할 수 있다. - 개발자는 소셜 기능을 직접 구축하는 부담을 줄이고, 멀티플레이어 참여와 플레이어 유지율을 높일 수 있다. ## 기본 제공 기능 - **통합 친구 목록** - 게임 안에서 Discord 친구 목록을 확인할 수 있다. - Discord에서도 게임 내 친구와 연결할 수 있다. - 게임 밖에서도 플레이어 관계를 유지할 수 있다. - **딥링크 게임 초대** - 게임 내 친구 목록에서 Discord 친구를 직접 초대한다. - 초대받은 플레이어는 특정 파티, 로비 또는 세션으로 바로 이동할 수 있다. - 게임 참여 절차를 줄여 멀티플레이어 세션과 플레이어 잔존율을 높인다. - **리치 프레즌스** - 현재 플레이 중인 게임과 활동 정보를 Discord 프로필에 표시한다. - 다른 사용자가 플레이 중인 게임을 발견하고 관심을 가질 수 있다. - 설정에 따라 프로필에서 한 번의 클릭으로 게임에 참여할 수 있다. - PC뿐 아니라 콘솔과 모바일에서도 사용할 수 있다. - **유연한 계정 요건** - Discord 계정 없이도 게임 내 소셜 기능을 이용할 수 있다. - 원하는 플레이어는 Discord 계정을 게임 계정과 연결할 수 있다. - 계정 연결을 통해 게임 외부에서도 대화와 관계를 이어갈 수 있다. ## 클로즈드 베타 기능 다음 기능은 모든 개발자가 이용할 수 있지만 현재는 제한적으로 제공되며, 클로즈드 베타에 참여하면 전체 기능을 사용할 수 있다. - **크로스 플랫폼 메시징** - 게임과 Discord 양쪽에서 동일한 대화를 이어갈 수 있다. - Discord 계정이 없는 사용자와도 게임 안에서 소통할 수 있다. - 개인 메시지가 게임과 Discord 양쪽에 지속된다. - **연결된 채널** - 게임 내 채팅을 특정 Discord 서버 채널과 연결한다. - 길드, 그룹, 스쿼드가 게임 안팎에서 지속적으로 대화할 수 있다. - 특정 게임 세션에 종속되지 않는 커뮤니티 공간을 제공한다. - **Discord 음성 채팅** - Discord 클라이언트와 동일한 음성 채팅 기술을 게임에 통합한다. - 길드, 매치, 로비에서 실시간 고품질 음성 대화를 지원한다. - 게임별 음성 시스템을 별도로 구축하지 않고 Discord의 음성 인프라를 활용할 수 있다. ## 지원 환경과 개발 방식 - C++ 프로젝트를 비롯해 Unreal Engine과 Unity 게임을 지원한다. - 현재 지원 운영체제는 Windows 11 이상과 macOS다. - 콘솔과 모바일 플랫폼 지원은 향후 추가될 예정이다. - Discord는 Unity 샘플과 파트너 피드백을 통해 통합 절차와 플레이어 경험을 개선했다고 설명한다. ## 초기 파트너 사례와 개선점 - **Rust** - Facepunch Studios는 Unity 샘플이 핵심 기능과 설정 절차를 이해하는 데 유용했다고 평가했다. - 샘플을 기반으로 Rust의 요구사항에 맞게 기능을 수정·통합할 수 있었다. - **SUPERVIVE** - Theorycraft Games는 직접 메시지, 로비, 세션 초대 기능을 쉽게 구현했다고 밝혔다. - 임시 계정(provisional account)을 활용해 Discord 계정이 없는 플레이어에게도 소셜 기능을 제공했다. - 초기 파트너 테스트를 통해 다음과 같은 부분이 보완됐다. - 자신의 온라인 상태와 게임 플레이 정보 공개 범위를 플레이어가 직접 제어하도록 개선했다. - Discord 계정이 없는 사용자의 임시 계정 처리 방식을 개선했다. - 계정 유형과 관계없이 일관된 플레이어 경험을 제공하도록 조정했다. 게임에 Discord 기반 소셜 기능을 빠르게 추가하려는 개발자라면 친구 목록, 딥링크 초대, 리치 프레즌스부터 도입하는 것이 현실적이다. 게임 내 채팅과 음성 채팅을 Discord와 완전히 연결하려면 현재 제한된 클로즈드 베타 참여가 필요하므로, 지원 플랫폼과 계정 정책을 확인한 뒤 적용하는 것이 좋다.

원문 읽기(새 탭에서 열림)
figma원문

피그마의 TypeScript (새 탭에서 열림)

피그마(Figma)는 자사의 모바일 렌더링 엔진의 핵심 언어였던 자체 개발 언어 'Skew'를 산업 표준인 TypeScript로 완전히 전환하는 데 성공했습니다. 과거 성능 최적화를 위해 도입했던 Skew가 팀 규모 확장에 따라 생산성 저해와 생태계 부재라는 한계에 부딪히자, 피그마는 일상적인 개발 흐름을 방해하지 않으면서도 자동화된 마이그레이션을 완수했습니다. 결과적으로 피그마는 성능 손실 없이 더 나은 개발 환경과 최신 JavaScript 생태계의 이점을 누릴 수 있게 되었습니다. ### 자체 개발 언어 Skew의 도입과 한계 * **성능 중심의 탄생:** 초기 피그마는 웹과 모바일 모두에서 프로토타입 뷰어를 구현하기 위해 Skew를 개발했습니다. 당시 Skew는 정적 타이핑과 더불어 상수 폴딩(constant folding), 가상 함수 호출 최적화(devirtualization) 등 고급 컴파일러 최적화를 통해 JavaScript보다 뛰어난 성능을 제공했습니다. * **확장의 걸림돌:** 하지만 팀이 커지면서 Skew는 신규 입사자의 적응을 어렵게 만들고, 린터(linter)나 정적 분석기 같은 현대적인 개발 도구 생태계를 활용할 수 없다는 단점이 부각되었습니다. * **기능의 부재:** async/await와 같은 현대적인 JavaScript 기능이 부족했고, 피그마 내부의 다른 코드베이스와 통합하는 데에도 높은 비용이 발생했습니다. ### TypeScript 전환이 가능해진 기술적 배경 * **WebAssembly(Wasm)의 보편화:** 2018년 이후 모바일 브라우저에서 WebAssembly 지원이 확대되었고, 2020년경에는 모바일에서도 안정적인 성능을 발휘하게 되었습니다. * **C++ 엔진으로의 교체:** Skew로 작성되었던 파일 로딩 등 핵심 성능 경로를 WebAssembly로 컴파일되는 C++ 엔진으로 대체함으로써, 나머지 로직을 TypeScript로 전환하더라도 전체 성능에 미치는 영향이 미미해졌습니다. * **팀 규모의 성장:** 개발 경험(DX) 개선에 전념할 수 있는 리소스를 확보할 만큼 팀이 성장하면서 자동화된 마이그레이션 도구 개발이 가능해졌습니다. ### 안전한 전환을 위한 3단계 자동화 프로세스 * **1단계 (Skew 작성, Skew 빌드):** 기존 빌드 프로세스를 유지하면서 Skew 코드를 TypeScript로 변환하는 트랜스파일러를 개발했습니다. 변환된 TypeScript 코드를 깃허브에 체크인하여 개발자들이 미래의 코드 모습을 확인할 수 있게 했습니다. * **2단계 (Skew 작성, TypeScript 빌드):** 개발자는 여전히 Skew로 코드를 짜지만, 실제 프로덕션 빌드는 트랜스파일러를 거친 TypeScript 코드로 진행했습니다. 이 과정에서 유닛 테스트를 통과시키고 타입 오류를 점진적으로 수정하며 안정성을 확보했습니다. * **3단계 (TypeScript 작성, TypeScript 빌드):** 특정 시점에 Skew 코드 생성을 중단하고 모든 Skew 소스 파일을 삭제했습니다. 이후 모든 개발자는 TypeScript를 직접 작성하게 되었으며, CI/CD 파이프라인도 TypeScript 기반으로 완전히 전환되었습니다. ### 실용적인 결론 및 시사점 피그마의 사례는 서비스 초기 성능을 위해 도입한 커스텀 기술이 성숙기에는 오히려 부채가 될 수 있음을 보여줍니다. 특히 대규모 코드베이스를 전환할 때는 **'점진적인 롤아웃'**과 **'자동화된 트랜스파일링'**이 핵심입니다. Skew와 TypeScript 간의 시맨틱 차이(예: 네임스페이스 초기화 순서 등)로 발생할 수 있는 런타임 오류를 방지하기 위해, 자체 컴파일러를 수정하여 제어권을 확보한 점은 기술적 난관을 극복한 훌륭한 전략으로 평가됩니다.

figma3분 읽기큐레이션 요약

다크 모드 밝히

Figma의 다크 모드는 색상만 어둡게 바꾸는 단순한 프런트엔드 작업이 아니라, 제품 전반의 UI 상태와 접근성, 향후 테마 확장성을 함께 해결해야 하는 시스템 구축 프로젝트였다. Figma는 사용자 요청에 대응하는 동시에 시각적 접근성을 높이고, 새로운 기능이 처음부터 다크 모드를 지원하도록 만드는 것을 목표로 했다. 이를 위해 전체 UI를 조사하고 여러 팀의 공통 컴포넌트를 체계적으로 refactoring하는 방식을 택했다. ## 다크 모드가 필요했던 이유 - 다크 모드는 Figma 사용자들이 가장 많이 요청한 기능 중 하나였다. - 야간 작업 시 밝은 화면으로 인한 불편을 줄일 수 있었다. - 시각 장애나 특정 시각적 질환이 있는 사용자에게 다크 모드가 더 읽기 쉬울 수 있었다. - 색상 대비는 WCAG 접근성 지침의 핵심 요소이므로, 다크 모드는 Figma의 “디자인을 모두에게 accessible하게 만든다”는 목표와도 연결됐다. - 일반적으로는 라이트 모드가 시각적 수행 능력에 유리하지만, 백내장 등 특정 질환이 있는 사람은 다크 모드에서 더 나은 성능을 보일 수 있다. ## 단순한 색상 교체가 아니었던 이유 - 처음에는 모든 밝은 색을 어두운 색으로 바꾸면 된다고 생각했지만, 실제로는 UI의 상태와 맥락을 함께 고려해야 했다. - 다크 모드 전환 시 다음 요소를 결정해야 했다. - 밝은 편집기 패널을 어둡게 바꾸고 아이콘과 텍스트를 밝게 할지 - 라이트 모드에서도 이미 어두운 툴바와 메뉴를 그대로 유지할지 - 캔버스 배경처럼 사용자가 만든 콘텐츠까지 테마에 따라 변경할지 - C++ 렌더링 엔진이 그리는 투명도 격자 등의 색상도 변경할지 - Figma 전체가 아니라 편집기 등 특정 영역만 지원할지에 대한 제품 범위 결정도 필요했다. ## 전체 UI 감사와 범위 설정 - 개발에 앞서 각 팀원이 Figma 앱의 UI 표면을 조사하고, 다크 모드로 재구성하기 어려운 부분을 파악했다. - 프로젝트 시작 당시 Figma에는 10개의 제품 엔지니어링 팀이 있었고, 각 팀이 모달, 패널, 툴바 등 주요 UI 영역을 담당했다. - 하나의 UI 요소도 여러 상태와 복잡한 예외 상황을 포함할 수 있었다. - 특정 조건에서만 나타나는 상태 - 여러 뷰와 화면 - 숨겨진 서브모달과 드롭다운 - 따라서 표면적으로 보이는 화면뿐 아니라 모든 상태와 엣지 케이스까지 다크 모드 범위에 포함해야 했다. ## 확장 가능한 테마 시스템의 목표 - 목표는 현재 다크 모드만 구현하는 것이 아니었다. - 두 가지 장기 목표를 세웠다. - 개발자가 새로운 기능을 다크 모드 지원과 함께 바로 만들 수 있도록 하기 - 향후 Figma와 FigJam에 새로운 테마를 쉽게 추가할 수 있도록 하기 - 공통 UI 컴포넌트는 다크 모드를 지원해야 하지만, 다크 모드가 적용되지 않는 화면에서는 기존 동작과 외관을 유지해야 했다. - 구현 과정에서 기존 기능을 깨뜨리지 않는 회귀 방지(regression-proof) 구조가 중요했다. - 새로운 엔지니어의 온보딩과 향후 예측하지 못한 요구사항 대응까지 고려해, 적용과 유지보수가 쉬운 방식이 필요했다. ## 프로젝트 규모가 만든 엔지니어링 과제 - Figma의 UI가 여러 팀에 분산되어 있어 소수의 엔지니어만으로 전체를 처리하기 어려웠다. - 각 팀이 소유한 컴포넌트와 화면을 공통 원칙에 맞게 바꿔야 했다. - 단순히 색상 값을 교체하는 것이 아니라, 컴포넌트가 어떤 표면과 상태에서 사용되는지까지 체계적으로 분리해야 했다. - 이 경험은 개별 기능을 추가하는 방식보다, 제품 전체에서 재사용할 수 있는 디자인·엔지니어링 시스템을 구축하는 접근이 필요하다는 점을 보여준다. 다크 모드처럼 겉보기에는 간단한 기능도 실제로는 UI 상태, 접근성, 팀 간 소유권, 공통 컴포넌트, 향후 확장성을 함께 설계해야 한다. 유사한 기능을 구현할 때는 특정 화면의 색상부터 바꾸기보다 전체 범위를 먼저 감사하고, 테마 토큰과 공통 컴포넌트를 중심으로 회귀를 방지할 수 있는 구조를 마련하는 것이 바람직하다.

원문 읽기(새 탭에서 열림)
figma3분 읽기큐레이션 요약

피그마는 웹어

WebAssembly 도입으로 Figma는 애플리케이션 초기화, 디자인 파일 다운로드, 첫 렌더링을 포함한 전체 로드 시간을 약 3배 단축했다. 특히 C++ 기반 코드를 브라우저에서 실행할 때 asm.js보다 전송·파싱·네이티브 코드 변환·캐싱 측면에서 유리했다. 다만 압축 후 다운로드 크기 감소 효과는 작았고, 당시에는 브라우저별 구현 및 캐싱 지원 차이로 적용 범위가 제한됐다. ## WebAssembly의 특징과 asm.js와의 차이 - WebAssembly는 브라우저 실행을 위해 설계된 바이너리 형식의 머신 코드다. - 기존에는 C++ 코드를 asm.js라는 JavaScript 부분집합으로 변환해 실행했다. - 숫자와 포인터만 사용할 수 있으며, 포인터는 숫자 배열의 인덱스로 표현된다. - DOM 조작이나 네트워크 연결 등 브라우저 기능은 JavaScript를 호출해야 한다. - WebAssembly도 asm.js와 동일한 제약과 브라우저 샌드박스를 공유하지만, 실행 형식이 더 효율적이다. - C++처럼 이미 LLVM으로 최적화된 코드는 브라우저가 별도 최적화를 많이 수행하지 않고 네이티브 코드로 변환할 수 있다. ## WebAssembly가 빠른 이유 - **작은 바이너리 형식** - 동일한 코드의 JavaScript보다 네트워크 전송에 유리하다. - 다만 압축하면 asm.js와 WebAssembly의 크기 차이는 크게 줄어든다. - **빠른 파싱** - 사람이 작성하는 JavaScript에는 문법과 중복 정보가 많다. - WebAssembly는 브라우저가 빠르게 해석하도록 설계되어 asm.js보다 약 20배 빠르게 파싱된다. - **효율적인 네이티브 코드 변환** - LLVM이 사전에 C++ 코드를 최적화하므로 브라우저의 런타임 최적화 부담이 작다. - **변환 결과 캐싱** - 브라우저가 WebAssembly 모듈의 네이티브 코드 변환 결과를 쉽게 캐시할 수 있다. - 같은 애플리케이션을 다시 열 때 변환 시간이 거의 사라질 수 있다. - **64비트 정수 지원** - WebAssembly는 64비트 정수를 직접 지원한다. - JavaScript는 정수 정밀도가 53비트로 제한되어 64비트 정수를 에뮬레이션해야 한다. ## Figma에서의 적용과 성능 개선 - Figma는 C++로 작성된 대규모 2D WebGL 렌더링 엔진을 사용한다. - 측정한 로드 시간에는 다음 과정이 모두 포함됐다. - 애플리케이션 초기화 - 디자인 파일 다운로드 - 디자인의 최초 전체 렌더링 - WebAssembly로 전환한 뒤 문서 크기와 관계없이 로드 시간이 3배 이상 개선됐다. - 큰 디자인 문서를 자주 만들고 전환하는 Figma 사용자에게 특히 큰 효과가 있었다. - 앱을 한 번 실행한 뒤에는 WebAssembly의 네이티브 변환 결과가 캐시되므로, 이후 로드 시간은 애플리케이션 코드 크기에 덜 영향을 받는다. ## 다운로드 크기와 실제 개선의 차이 - WebAssembly로 전환하면 전송 크기도 크게 줄어들 것으로 예상했지만 실제 감소 폭은 작았다. - asm.js 코드도 압축하면 WebAssembly와 비슷한 크기까지 줄어들기 때문이다. - 따라서 Figma에서 가장 큰 이점은 파일 크기 감소가 아니라 파싱, 코드 변환, 캐싱에 따른 실행 및 로드 시간 단축이었다. ## 브라우저 지원의 한계 - 당시 WebAssembly는 Firefox와 Chrome에서 기본 활성화되어 있었다. - Edge와 Safari는 아직 구현 중이어서 브라우저별 지원 상황을 확인해야 했다. - Figma는 Chrome에서도 WebAssembly를 사용할 수 있었지만, 구현상의 문제 때문에 실제로는 Firefox에서만 활성화했다. - 특히 Chrome의 네이티브 변환 코드 캐싱 방식이 Firefox와 달라 페이지를 열 때마다 애플리케이션 전체를 다시 변환해야 하는 문제가 있었다. WebAssembly는 대규모 C/C++ 코드베이스를 웹으로 옮길 때 특히 효과적이다. 단순히 다운로드 용량을 줄이는 기술이라기보다, 빠른 파싱과 네이티브 코드 변환, 실행 결과 캐싱을 통해 초기 로드 시간을 줄이는 기술로 보는 것이 적절하다.

원문 읽기(새 탭에서 열림)
figma4분 읽기큐레이션 요약

Emscripten으로 데이터

Figma의 저장 파일이 간헐적으로 손상되는 문제는 재현이 어려운 비결정적 이벤트와 C++의 메모리 안전성 문제 때문에 장기간 해결되지 않았다. 일반적인 메모리 디버깅 도구로 원인을 찾지 못한 뒤, 키보드·마우스 입력을 생성하는 퍼저로 이벤트를 반복 실행해 문제를 재현하는 데 성공했다. 최종 수정은 FlatBuffers의 잘못된 메모리 접근을 고치는 세 줄짜리 커밋이었지만, 원인을 추적하는 과정에서 Emscripten과 브라우저의 메모리 모델까지 분석해야 했다. ## 간헐적으로 발생한 저장 파일 손상 - Figma는 때때로 다시 읽을 수 없는 잘못된 저장 파일을 생성했다. - 당시 저장 형식은 다음 구조였다. - ZIP 파일 - 내부에 Google FlatBuffers로 인코딩된 문서 - 파일의 전체 바이트 구조는 대체로 정상처럼 보였지만, 뒤쪽 데이터를 가리키는 일부 오프셋이 0으로 변해 있었다. - 데이터가 원래 위치가 아닌 곳에 기록된 현상은 다음과 같은 메모리 안전성 위반을 의심하게 했다. - 초기화되지 않은 메모리 사용 - 해제된 메모리 접근(use-after-free) - 배열 범위를 벗어난 읽기·쓰기 ## C++ 메모리 오류의 추적 난이도 - Figma 에디터는 C++로 작성되어 있었다. - C++는 다음과 같은 장점 때문에 그래픽 소프트웨어에 적합하다. - FreeType, HarfBuzz, Skia 같은 저수준 라이브러리 활용 - 하드웨어와 직접 연결되는 언어 기능 - 성숙한 디버깅 및 최적화 도구 - 높은 성능과 세밀한 메모리 제어 - 반면 C++는 언어 자체가 메모리 안전성을 보장하지 않는다. - 복잡한 언어 설계, 오류가 발생하기 쉬운 표준 라이브러리 API, C에서 물려받은 레거시가 결합되어 대규모 프로젝트에서 메모리 오류를 완전히 피하기 어렵다. ## 일반적인 디버깅 방법의 한계 개발팀은 다음과 같은 방법을 시도했지만 문제를 발견하지 못했다. - 메모리를 해제하지 않아 use-after-free 가능성 제거 - macOS의 malloc 디버깅 옵션 활성화 - Valgrind가 보고한 모든 문제 수정 - 컴파일러 업그레이드 - Clang 정적 분석기가 발견한 문제 수정 이런 도구들은 많은 오류를 찾아내지만, 실행 조건에 따라 드물게 발생하거나 특정 메모리 배치에서만 나타나는 문제까지 항상 잡아내지는 못한다. ## 이벤트 기록과 퍼징으로 재현성 확보 - 문제의 핵심은 비동기 타이머와 네트워크 이벤트 등 웹 앱의 비결정성이었다. - 해결 전략은 다음과 같았다. - 사용자 이벤트를 기록한다. - 동일한 이벤트를 순서대로 재생한다. - 문제가 발생할 때까지 세션을 반복 실행한다. - 이벤트를 무작위로 제거하면서도 문제가 유지되는 최소 테스트 케이스를 만든다. - 실제 사용자 세션에는 너무 다양한 이벤트가 포함되므로, 범위를 키보드와 마우스 이벤트로 제한했다. - 실제 세션을 수집하는 대신 퍼저가 무작위 키보드·마우스 입력을 생성하도록 했다. - 며칠 동안 실행한 결과 여러 건의 저장 실패를 재현할 수 있었고, 이후 반복 가능한 입력 시퀀스를 기반으로 본격적인 디버깅이 가능해졌다. ## Emscripten이 C++를 브라우저에서 실행하는 방식 - Figma는 플러그인 없이 브라우저에서 실행되는 웹 앱이다. - C++ 코드는 Emscripten을 통해 JavaScript로 컴파일된다. - JavaScript는 기본적으로 메모리 안전성과 가비지 컬렉션을 제공하지만, WebGL과 Typed Arrays 덕분에 C의 메모리 모델을 흉내 낼 수 있다. - Typed Array의 특징은 다음과 같다. - 고정된 크기를 가진다. - 모든 원소가 같은 타입이다. - 여러 Typed Array가 하나의 ArrayBuffer를 공유할 수 있다. - 같은 메모리를 `Float32Array`와 `Uint8Array` 등 서로 다른 타입으로 해석할 수 있기 때문에 C/C++의 포인터 캐스팅과 유사한 동작을 구현할 수 있다. ## Emscripten의 포인터와 메모리 변환 Emscripten은 C++의 주요 요소를 JavaScript 구조로 변환한다. - 포인터 읽기: Typed Array 읽기 - 포인터 쓰기: Typed Array 쓰기 - 레지스터: JavaScript 지역 변수 - 스택: `STACKTOP`이라는 스택 포인터로 관리 - 타입 변환: 동일한 ArrayBuffer를 공유하는 Typed Array를 통해 구현 - 생성된 코드는 asm.js라는 제한적인 JavaScript 부분집합을 사용해 JIT 컴파일러가 타입을 추론하고 빠르게 최적화하도록 한다. - 예를 들어 `+$value`는 값을 double로 취급하도록 JIT에 힌트를 주며, 비트 연산은 정수 연산으로 최적화될 가능성을 높인다. ## 실용적인 결론 재현이 어려운 데이터 손상 문제는 도구를 하나씩 추가하는 것만으로 해결되지 않을 수 있다. 비결정적 입력을 통제하고, 퍼징과 이벤트 재생으로 실패 조건을 반복 가능하게 만드는 것이 핵심이며, 컴파일된 실행 환경에서는 원본 언어뿐 아니라 Emscripten의 메모리 모델과 런타임 동작까지 함께 이해해야 한다.

원문 읽기(새 탭에서 열림)