software-architecture

8 개의 포스트

Squad가 리포지토리 내에서 협업하는 AI 에이전트를 실행하는 방법 (새 탭에서 열림)

데이터베이스 설계에서 흔히 사용되는 ‘소프트 삭제(Soft Delete, 삭제 플래그 사용)’ 방식은 구현이 간편해 보이지만, 실제로는 시스템의 복잡성을 가중시키고 성능을 저해하는 안티 패턴으로 작용할 위험이 큽니다. 데이터의 이력을 관리해야 한다면 단순히 삭제 여부를 표시하는 컬럼을 추가하는 대신, 데이터베이스의 네이티브 기능인 시간 기반 테이블(Temporal Tables)이나 별도의 보관 아카이브를 활용하는 것이 데이터 무결성과 성능 측면에서 훨씬 유리합니다. **소프트 삭제가 초래하는 아키텍처의 복잡성** - 모든 조회 쿼리에 `WHERE is_deleted = 0`과 같은 필터 조건을 강제하게 되어 개발자의 실수를 유발하고 코드 유지보수 비용을 높입니다. - 소프트 삭제된 데이터가 테이블에 그대로 남아있어 고유 제약 조건(Unique Constraint)을 설정하기가 까다로워지며, 삭제된 값과 동일한 값을 재입력할 때 충돌이 발생합니다. - 외래 키(Foreign Key) 관계에서 '삭제된' 행을 참조하는 논리적 오류가 발생할 수 있어 참조 무결성을 보장하기 어렵습니다. **데이터 무결성 및 인덱스 성능 문제** - 삭제된 데이터가 인덱스에 포함되어 인덱스의 크기가 불필요하게 커지고, 이로 인해 메모리 효율성과 쿼리 스캔 성능이 점진적으로 저하됩니다. - 필터링된 인덱스(Filtered Index)를 사용하여 성능 저하를 방지할 수 있으나, 이는 데이터베이스 엔진에 추가적인 관리 부담을 주며 모든 상황의 근본적인 해결책이 되지 못합니다. - 비즈니스 로직과 데이터 보관 로직이 뒤섞이면서 데이터 모델의 의미가 모호해지는 결과가 나타납니다. **시스템 버전 관리 테이블과 트리거 기반의 대안** - SQL Server 및 Azure SQL에서 제공하는 시스템 버전 관리 테이블(Temporal Tables)을 사용하면, 애플리케이션 로직을 수정하지 않고도 삭제되거나 수정된 데이터의 과거 이

쓰기 쉬운 Toss Front SDK (새 탭에서 열림)

좋은 SDK는 단순히 기능을 제공하는 것을 넘어, 사용자가 올바른 방법으로만 사용하도록 유도하고 휴먼 에러를 구조적으로 방지해야 합니다. 이를 위해 복잡한 내부 로직을 사용자의 ‘의도’를 중심으로 추상화하는 퍼사드(Facade) 패턴을 적용하여, 사용자가 최소한의 코드로도 안정적인 결과물을 만들 수 있는 환경을 구축해야 합니다. 고수준 인터페이스를 통해 대다수의 유즈케이스를 해결하면서도, 특수한 상황을 위한 저수준 인터페이스라는 ‘탈출구’를 마련하는 것이 설계의 핵심입니다. ### 의도 기반의 퍼사드(Facade) 패턴 재정의 - 퍼사드 패턴의 본질은 단순히 복잡한 기능을 숨기는 것이 아니라, 내부 구현을 ‘사용자의 의도(Intent)’를 기준으로 재구성하는 데 있습니다. - "서버를 열고, 핸들러를 등록하고, 에러를 처리한다"는 개별적인 절차를 "서버를 시작한다"는 하나의 자연스러운 목적으로 통합합니다. - 인증, 재시도 로직, 상태 관리, 클린업(Cleanup) 등 인지 부하를 일으키는 요소들을 SDK 내부로 은닉하여 사용자 측의 실수를 원천 차단합니다. ### AWS CDK 사례를 통한 추상화 계층의 이해 - AWS CDK의 L1 구문은 리소스의 모든 속성을 제어하는 저수준(low-level) 인터페이스인 반면, L2 구문은 직관적인 의도 기반의 고수준(high-level) 추상화를 제공합니다. - S3 버킷 생성 시 L1은 모든 세부 설정을 직접 챙겨야 하지만, L2는 자주 쓰이는 옵션을 간단한 프로퍼티로 제공하고 내부적인 변환은 SDK가 담당합니다. - SDK 설계 시에도 이와 같이 복잡한 주변 구성을 자연스러운 API 흐름으로 이어 붙일 수 있도록 설계해야 합니다. ### 파레토 법칙을 적용한 인터페이스 설계 - 전체 사용 사례의 80%에 해당하는 공통 유즈케이스는 고수준 인터페이스(Facade)를 통해 워크플로우를 자동화하여 제공합니다. - 나머지 20%의 특수한 요구사항이나 세밀한 제어가 필요한 상황을 위해 저수준 API인 ‘탈출구(Escape Hatch)’를 함께 유지합니다. - 이러한 이중 구조는 단기적인 개발자 경험(DX) 향상뿐만 아니라, SDK의 장기적인 호환성과 확장성을 보장하는 핵심 전략이 됩니다. ### 편의성과 유연성 사이의 트레이드오프 관리 - 추상화 수준이 높아지면 사용자는 편리해지지만, SDK 내부에서는 더 정교한 오케스트레이션 로직을 관리해야 하는 유지보수 비용이 발생합니다. - 세밀한 제어가 차단될 경우 특정 상황에서 제약이 될 수 있으므로, 고수준 인터페이스에만 의존하지 않고 저수준 조작이 가능한 균형점을 찾는 것이 중요합니다. - 결과적으로 잘 설계된 인터페이스는 사용자가 별도의 가이드 없이도 올바른 패턴을 유지하며 메모리 누수와 같은 장애 상황을 방지하게 합니다. 단순히 "동작하는" SDK를 만드는 단계를 넘어, 사용자가 직관적으로 이해하고 안전하게 사용할 수 있는 "쓰기 쉬운" SDK를 지향해야 합니다. 이를 위해 사용자의 의도를 최우선으로 고려한 추상화 계층을 설계하고, 대다수의 편의성과 소수의 유연성을 동시에 잡을 수 있는 다층적 구조를 도입할 것을 권장합니다.

더 스마트한 광고를 위한 우리의 (새 탭에서 열림)

Spotify는 광고 비즈니스의 다양한 구매 채널 간에 발생하는 의사결정 로직의 파편화 문제를 해결하기 위해 멀티 에이전트 아키텍처를 도입했습니다. 기존의 하드코딩된 워크플로우 대신, 광고주의 의도를 이해하고 공유된 신호를 바탕으로 추론하는 '프로그래밍 가능한 의사결정 계층'을 구축하여 모든 채널에서 일관된 최적화를 달성하고자 합니다. 이를 통해 복잡한 비즈니스 제약 조건을 유연하게 처리하고, 기존 광고 서비스들을 에이전트가 활용하는 도구로 재정의함으로써 시스템 전반의 운영 효율성을 극대화하는 것이 이 글의 핵심입니다. ### 기존 워크플로우의 구조적 한계와 파편화 * **채널별 로직 불일치:** 동일한 백엔드 인프라를 공유함에도 불구하고 Direct, Self-Serve, Programmatic 등 각 구매 채널별로 의사결정 로직과 휴리스틱이 다르게 구현되어 동작의 불일치가 발생합니다. * **중복 구현과 기술 부채:** 예산 할당이나 인벤토리 선택과 같은 핵심 로직이 각 채널 및 사용자 접점(Spotify Ads Manager, Salesforce, Slack 등)마다 중복 구현되어 관리 비용이 증가하고 로직의 변질(Drift)이 일어납니다. * **의도 계층(Intent Layer)의 부재:** 기존 시스템은 "브라질 내 도달 범위 극대화 및 비디오 인벤토리 보호"와 같은 복합적인 목표를 이해하고 이를 실행 가능한 도구 호출 순서로 변환하는 능력이 부족했습니다. ### 멀티 에이전트 기반 의사결정 계층의 도입 * **모듈형 에이전트 구조:** 복잡하고 확률적인 광고 로직을 정적인 규칙 엔진(Rules Engine)에 가두는 대신, 상황에 따라 추론하고 실행하는 독립적인 에이전트들의 집합으로 구성했습니다. * **공유 신호 기반 최적화:** 모든 에이전트는 인벤토리, 오디언스, 성능 이력 등 동일한 기저 신호를 공유하며 광고주의 목표와 Spotify의 비즈니스 제약 조건을 동시에 고려하여 최적의 경로를 찾습니다. * **기존 서비스의 도구화:** 기존 광고 서비스들을 처음부터 다시 만드는 대신, 에이전트가 목적에 따라 호출하여 사용할 수 있는 '도구(Tools)'로 활용함으로써 오케스트레이션 성능을 높였습니다. ### 에이전트 중심 설계를 위한 기술적 패러다임 전환 * **API 설계의 변화:** 단순히 데이터를 생성하고 수정하는 CRUD 방식에서 벗어나, 에이전트가 특정 기능을 실행하기 위해 직관적으로 이해하고 사용할 수 있는 '도구 중심 API'로 재설계했습니다. * **행동 중심의 평가:** 전통적인 유닛/통합 테스트를 넘어, 에이전트가 내린 결정이 비즈니스 목표에 부합하는지 확인하는 '행동 평가(Behavioral Evaluation)' 체계를 구축했습니다. * **추론 과정의 관측성:** 시스템 성능 지표뿐만 아니라 "에이전트가 왜 그런 결정을 내렸는가"에 대한 추론 과정을 추적하여 투명성을 확보했습니다. * **자율성을 제어하는 가드레일:** 입력값 검증 수준을 넘어 반자율적인 에이전트의 결정이 비즈니스 규칙과 안전 가이드라인 내에서 유지되도록 하는 가드레일 메커니즘을 도입했습니다. 복잡한 비즈니스 로직이 여러 플랫폼에 흩어져 있다면, 이를 개별 서비스로 관리하기보다 통합된 '의사결정 엔진'으로서의 에이전트 플랫폼을 구축하는 것이 장기적인 유지보수와 기능 확장 면에서 유리합니다. Spotify는 이를 미디어 플래닝(Media Planning) 영역에 우선 적용하여 복잡한 변수 속에서도 일관된 최적화 성능을 증명하고 있습니다.

현지인처럼 결 (새 탭에서 열림)

Airbnb는 전 세계 220개 이상의 국가에서 결제 편의성을 높이고 전환율을 개선하기 위해 14개월 만에 20개 이상의 지역 결제 수단(LPM)을 성공적으로 도입했습니다. 이를 위해 기존의 모놀리식 시스템을 도메인 주도 서비스 체계로 현대화하고, 다양한 결제 방식을 표준화된 인터페이스로 처리할 수 있는 기술적 기반을 마련했습니다. 결과적으로 복잡한 지역별 결제 환경을 추상화함으로써 확장성 있는 글로벌 결제 플랫폼을 구축하고 비즈니스 성장을 가속화했습니다. **현지 결제 수단(LPM) 도입의 전략적 가치** * **다양한 결제 수단 수용:** 신용카드 외에도 국가별 디지털 지갑(M-Pesa), 실시간 계좌 이체(Pix, UPI), 지역 결제망(Cartes Bancaires) 등 사용자에게 익숙한 수단을 제공합니다. * **접근성 및 전환율 증대:** 신용카드 보급률이 낮은 시장의 잠재 고객을 확보하고, 결제 단계에서의 이탈(friction)을 줄여 예약 전환율을 높입니다. * **체계적인 선정 프레임워크:** 전 세계 300개 이상의 결제 옵션 중 상위 75개 시장을 분석하고, 여행 서비스 적합도와 시장 점유율을 고려해 우선순위가 높은 20여 개를 선정했습니다. **결제 플랫폼 현대화 및 MST 프레임워크** * **서비스 지향 아키텍처(LTA):** 모놀리식 구조를 도메인 주도 아키텍처로 전환하여 결제 처리, 정산, 장부 관리 등 기능을 독립적인 서비스로 분리했습니다. * **커넥터 및 플러그인 구조:** 새로운 결제 서비스 제공업체(PSP)를 연동할 때 코드 재사용성을 높이고 시장 진입 시간을 단축하기 위해 플러그인 방식의 아키텍처를 채택했습니다. * **멀티스텝 트랜잭션(MST):** 업체마다 제각각인 결제 단계를 표준화하기 위해 MST 프레임워크를 도입했습니다. 리다이렉션이나 추가 인증이 필요한 경우 이를 'ActionPayload'로 규격화하여 처리합니다. **세 가지 표준화된 결제 흐름 모델** * **리다이렉트(Redirect) 흐름:** 네이버페이나 GoPay처럼 사용자를 외부 앱이나 웹사이트로 이동시켜 결제를 완료한 후, 다시 에어비앤비로 돌아와 토큰 기반으로 최종 확정하는 방식입니다. * **비동기(Async) 흐름:** Pix나 Blik과 같이 사용자가 QR 코드를 스캔하거나 푸시 알림을 통해 외부에서 결제하면, PSP가 에어비앤비에 웹훅(Webhook) 통보를 보내 상태를 업데이트하는 방식입니다. * **직접(Direct) 흐름:** 애플페이나 특정 로컬 카드처럼 에어비앤비 인터페이스 내에서 직접 결제 정보를 입력하고 실시간으로 처리하는 표준적인 방식입니다. **결제 오케스트레이션 및 데이터 무결성** * **외부 세션 제어:** 타사 앱 전환 시 발생하는 세션 핸드오프와 동기화 문제를 해결하기 위해 견고한 결제 오케스트레이션 로직을 설계했습니다. * **웹훅 기반 상태 관리:** 비동기 결제의 경우, 사용자 화면의 상태와 실제 결제 완료 상태를 일치시키기 위해 안정적인 웹훅 수신 체계를 구축했습니다. * **시장별 최적화:** 한국의 네이버페이처럼 높은 점유율을 가진 수단을 우선 도입하여 현지 사용자의 결제 경험을 네이티브 수준으로 개선했습니다. 글로벌 확장을 준비하는 엔지니어링 팀은 결제 시스템 설계 시 처음부터 '추상화'와 '표준화'에 집중해야 합니다. 지역별 결제 수단은 기술적 구현 방식이 모두 다르지만, 이를 리다이렉트, 비동기, 직접 흐름으로 범주화하여 공통 프레임워크(MST) 내에 수용함으로써 신규 결제 수단 추가에 드는 비용을 획기적으로 낮출 수 있습니다.

기획부터 개발까지 전부 직접 했습니다 – 우테코 7기 크루 서비스 론칭! | 우아한형제들 기술블로그 (새 탭에서 열림)

우아한테크코스 7기 크루들이 기획부터 디자인, 개발 및 운영까지 전 과정을 직접 수행하며 실제 사용자를 위한 서비스를 성공적으로 론칭했습니다. 이번 프로젝트는 단순한 기술 습득을 넘어 개발자가 왜 기획과 디자인에 참여해야 하는지, 그리고 사용자 피드백이 아키텍처와 도메인 설계에 어떤 영향을 미치는지 몸소 체험하는 과정이었습니다. 결과적으로 크루들은 2주 단위의 스프린트와 실시간 모니터링, 배포 환경 구축 등 실무에 근접한 경험을 통해 현장 중심의 문제 해결 역량을 갖춘 개발자로 성장했습니다. **개발자 중심의 기획과 협업 문화의 정착** - 우아한테크코스는 레벨 3, 4 과정을 통해 개발자가 직접 기획과 디자인을 포함한 서비스의 전주기를 책임지는 팀 프로젝트를 진행합니다. - 기술적인 구현뿐만 아니라 말하기, 글쓰기 교육을 병행하여 팀원 간의 의견 조율 및 설득 등 소프트 스킬의 중요성을 강조합니다. - 아키텍처 설계와 같은 기술적 결정이 팀의 목표와 사용자의 가치에 어떻게 부합해야 하는지 고민하며 개발자의 역할을 확장했습니다. **픽잇(Pickeat): 취향과 제약을 반영한 협업형 식사 선택 서비스** - "아무거나"라는 답변 뒤에 숨겨진 기피 음식과 다이어트 등의 제약 사항을 실시간 투표로 해결하여 최적의 식당을 추천합니다. - 위치 정보 기반의 식당 자동 조회 및 템플릿 기능을 도입하여 반복되는 회식이나 미팅 시 의사결정 속도를 높였습니다. - 데모데이와 홍보를 통해 받은 피드백을 바탕으로 UI와 백엔드 도메인 구조를 유연하게 재설계하며 사용자 중심의 반복적인 개선 과정을 거쳤습니다. **보따리(Bottari): 실시간 동기화 기반의 상황별 체크리스트** - 출근, 여행, 이사 등 다양한 상황에 맞춘 템플릿 기반 리스트 생성과 팀 단위의 실시간 협업 체크 기능을 제공합니다. - 단순한 기능 구현을 넘어 사용자가 물건을 잊지 않게 돕는 알림 타이밍과 체크 상태 동기화 등 사용자 경험(UX)의 세부 요소를 정밀하게 다듬었습니다. - '기술은 문제를 해결하는 도구'라는 철학 아래 사용자가 안심하고 기억을 맡길 수 있는 흐름을 구현하는 데 집중했습니다. **커피빵(Coffee Bread): 웹소켓 기반의 실시간 내기 미니게임** - 가위바위보보다 더 큰 재미와 긴장감을 주기 위해 실시간 미니게임과 가중치 적용 룰렛 시스템을 도입한 서비스입니다. - 웹소켓(WebSocket) 기술과 분산 환경이라는 기술적 난제를 극복하며 실시간 상호작용이 끊김 없이 이루어지도록 개발했습니다. - 게임의 공정성과 재미를 위해 룰렛 알고리즘을 수차례 수정하고, 실제 사용자들의 피드백을 반영해 밸런스를 최적화했습니다. 이 서비스들은 단순한 교육용 프로젝트를 넘어 실제 배포와 운영을 거치며 기술적 완성도를 높였습니다. 개발자가 기획 단계부터 깊이 관여할 때 사용자에게 더욱 가치 있는 프로덕트가 탄생한다는 점을 시사하며, 실무적인 문제 해결 역량을 키우고 싶은 주니어 개발자들에게 좋은 협업의 귀감이 됩니다.

100년 가는 프론트엔드 코드, SDK (새 탭에서 열림)

토스페이먼츠는 결제 연동의 복잡성을 해결하기 위해 SDK를 제공하고 있으며, 최근 V1의 한계를 극복하고 안정성과 확장성을 극대화한 V2 SDK를 구축했습니다. 가맹점의 다양한 런타임 환경과 예측 불가능한 요구사항에 대응하기 위해 단순한 기능 구현을 넘어 체계적인 아키텍처와 모니터링 시스템을 도입했습니다. 결과적으로 개발자에게는 쉬운 연동 경험을, 비즈니스에는 견고한 신뢰성을 제공하는 결제 생태계를 완성했습니다. **SDK 개발의 특수성과 V1의 한계** * **환경의 의존성:** SDK는 가맹점의 코드 내에서 실행되므로, 가맹점의 호출 빈도나 네트워크 상태에 직접적인 영향을 받습니다. 일례로 사용량 분석을 위해 추가한 로그 코드가 특정 가맹점의 잦은 호출과 맞물려 네트워크 병목 현상을 일으키고 서비스 전체를 다운시키는 사례가 발생했습니다. * **런타임 예측 불가능성:** 가맹점에서 잘못된 데이터 타입(예: String 대신 Number)을 전달할 경우 `startsWith` 같은 표준 메서드에서 에러가 발생하는 등, 일반적인 프론트엔드 개발보다 훨씬 방어적인 코딩이 요구됩니다. * **커뮤니케이션의 접점:** SDK는 단순히 API를 호출하는 도구가 아니라 가맹점 개발자와 만나는 기술적 창구이며, 가맹점의 수많은 커스텀 요구사항을 수용해야 하는 복잡성을 안고 있습니다. **안정성 확보를 위한 테스트와 모니터링** * **촘촘한 테스트 체계:** 로직 검증을 위한 300개 이상의 단위 테스트와 다양한 유즈케이스를 반영한 500개 이상의 E2E 통합 테스트를 통해 코드 수준의 안정성을 확보했습니다. * **Global Trace ID:** 프론트엔드부터 백엔드까지 결제 전 과정을 하나의 식별자로 추적하는 체계를 도입하여, 장애 발생 시 시스템 레이어 전체를 쉽게 파악할 수 있도록 했습니다. * **모니터링 CLI:** 배포 전후의 결제 성공률을 가맹점 및 런타임 환경(OS, 브라우저, 웹뷰 등)별로 비교 분석하는 자체 도구를 개발했습니다. 이를 통해 특정 환경에서 발생하는 결제 중단 현상을 실시간으로 탐지하고 즉각 대응합니다. **확장성을 위한 레이어드 아키텍처** * **조립 가능한 구조:** 특정 가맹점만을 위한 예외 처리가 `if`문으로 산재되어 코드 복잡도가 올라가는 문제를 해결하기 위해, 기능을 레고 블록처럼 독립적으로 구성했습니다. * **3계층 분리:** "변경의 원인"을 기준으로 코드의 경계를 명확히 나누어 관리합니다. * **Public Interface Layer:** 가맹점과 약속한 인터페이스를 검증하고 도메인 언어로 번역하는 역할 * **Domain Layer:** 핵심 비즈니스 로직과 결제 정책을 담당하는 중심부 * **External Service Layer:** 서버 API나 Web API 등 외부 의존성과의 통신을 담당하는 계층 * **관심사 격리:** 이러한 계층화를 통해 가맹점별 커스텀 요구사항이 추가되더라도 기존의 핵심 로직에 영향을 주지 않고 특정 블록만 교체하거나 확장할 수 있는 유연성을 확보했습니다. 성공적인 SDK 개발을 위해서는 단순히 편리한 기능을 제공하는 것을 넘어, 타사의 코드 환경에서도 견고하게 동작할 수 있는 방어적인 설계와 문제 발생 시 즉시 원인을 파악할 수 있는 관측성(Observability) 확보가 필수적입니다. 가맹점별 특이 케이스를 코드 전반에 흩뿌리기보다는, 명확한 레이어 구분을 통해 비즈니스 로직과 커스텀 로직을 분리하는 설계 원칙을 권장합니다.

피그마 내부 이야기: 내부 웹 (새 탭에서 열림)

피그마는 웹 기반 디자인 도구로서 실시간 협업의 복잡성을 해결하기 위해 단일 모놀리스에서 정교한 분산 시스템으로 인프라를 확장해 왔습니다. 이들은 클라이언트측의 WebAssembly 성능과 백엔드의 안정적인 데이터 동기화 메커니즘을 결합하여, 전 세계 수백만 사용자가 동시에 지연 없이 작업할 수 있는 환경을 구축했습니다. 결과적으로 피그마의 기술적 성공은 화려한 기술의 도입보다는 실제 서비스 성장에 맞춘 실용적인 아키텍처 진화와 지속적인 최적화에 뿌리를 두고 있습니다. ### 실시간 협업을 위한 Multiplayer 서버 아키텍처 * 피그마의 핵심은 'Multiplayer'라고 불리는 상태 유지형(Stateful) 서버 시스템입니다. * 사용자가 파일을 열면 특정 서버 프로세스에 할당되며, 클라이언트는 WebSocket을 통해 이 서버와 실시간으로 통신합니다. * 서버는 문서의 현재 상태를 메모리에 유지하면서 여러 사용자의 편집 요청을 순서대로 처리하고, 변경 사항을 즉각적으로 모든 참여자에게 전파하여 충돌을 방지합니다. ### 데이터베이스 확장과 Vitess 도입 * 초기에는 단일 PostgreSQL 인스턴스로 시작했으나, 데이터 사용량이 폭증함에 따라 데이터베이스 확장성 한계에 직면했습니다. * 이를 해결하기 위해 데이터를 논리적으로 나누는 수직 분할(Vertical Partitioning)을 거쳐, 최종적으로는 수평 샤딩(Horizontal Sharding)으로 전환했습니다. * 이 과정에서 YouTube에서 개발한 오픈소스 데이터베이스 클러스터링 시스템인 'Vitess'를 도입하여, 애플리케이션 코드의 수정 없이도 수만 개의 샤드를 효율적으로 관리할 수 있는 구조를 만들었습니다. ### 성능 극대화를 위한 WebAssembly와 C++ 엔진 * 피그마의 그래픽 렌더링 엔진은 성능 극대화를 위해 C++로 작성되었으며, 이를 WebAssembly(Wasm)로 컴파일하여 브라우저에서 실행합니다. * 이는 일반적인 JavaScript 환경보다 훨씬 빠른 연산 속도를 제공하며, 대규모 디자인 파일에서도 데스크톱 앱 수준의 부드러운 사용자 경험을 보장합니다. * 클라이언트와 서버가 동일한 동기화 로직을 공유할 수 있도록 설계하여, 복잡한 협업 시나리오에서도 데이터의 정합성을 유지합니다. ### 시스템 신뢰성을 보장하는 시뮬레이션 테스트 * 동시성 문제가 발생하기 쉬운 실시간 환경의 특성을 고려하여, '결정론적 시뮬레이션(Deterministic Simulation)' 테스트를 수행합니다. * 수천 명의 가상 사용자가 무작위로 편집을 수행하거나 네트워크 지연이 발생하는 극한의 상황을 재현하여 시스템의 안정성을 검증합니다. * 이러한 철저한 테스트 자동화 덕분에 복잡한 인프라 변경이나 기능 업데이트 시에도 사용자 데이터 손실 없이 안정적인 서비스를 유지할 수 있습니다. ### 점진적 진화와 관찰 가능성(Observability) * 피그마는 초기부터 완벽한 시스템을 설계하기보다 서비스 규모에 맞춰 인프라를 단계적으로 개선하는 전략을 취했습니다. * 모든 시스템 구성 요소에 상세한 로깅과 대시보드를 구축하여, 장애가 발생하기 전 징후를 파악하고 신속하게 대응할 수 있는 환경을 조성했습니다. * 인프라 부서는 단순히 서버를 운영하는 것을 넘어, 제품 엔지니어가 확장성 고민 없이 기능을 개발할 수 있도록 추상화된 플랫폼을 제공하는 데 집중합니다. 피그마의 사례는 서비스 초기부터 오버엔지니어링을 하기보다, 병목 지점을 정확히 파악하고 적시에 Vitess나 WebAssembly 같은 핵심 기술을 도입하는 것이 얼마나 중요한지 보여줍니다. 실시간 협업 서비스를 설계한다면 상태 유지형 서버의 안정성과 데이터베이스 샤딩 전략을 최우선으로 고려할 것을 추천합니다.

Figma 데이터의 안전한 보호 및 (새 탭에서 열림)

Figma는 사용자가 직접 도구를 확장할 수 있는 플러그인 시스템을 구축하면서, 서드파티 코드가 메인 앱의 성능을 저하시키거나 보안 위협이 되지 않도록 하는 데 집중했습니다. 이를 위해 기존의 웹 샌드박싱 기술인 `<iframe>`이나 Web Worker의 한계를 넘어서는 새로운 구조를 설계했습니다. 최종적으로 Figma는 WebAssembly를 통해 QuickJS라는 경량 자바스크립트 엔진을 브라우저 내에서 실행함으로써, 안전하면서도 고성능을 유지하는 독자적인 플러그인 실행 환경을 구현해냈습니다. **기존 웹 기술 기반 샌드박싱의 한계** * **iframe 샌드박스:** 보안을 위해 `sandbox` 속성을 사용할 수 있지만, 동일한 메인 스레드를 공유하기 때문에 플러그인의 무거운 연산이 Figma 전체 UI를 멈추게 할 위험이 있습니다. 또한, 수백 개의 플러그인을 동시에 실행할 경우 메모리 오버헤드가 급증합니다. * **Web Worker:** 별도의 스레드에서 실행되므로 메인 UI를 방해하지 않지만, DOM에 직접 접근할 수 없고 메인 스레드와의 통신(postMessage)이 비동기적으로 이루어져야 하므로 성능 병목 현상이 발생합니다. * **보안과 성능의 트레이드오프:** 기존 방식들은 보안을 강화하면 성능이 떨어지고, 성능을 올리면 보안이나 구현 복잡도가 높아지는 딜레마가 있었습니다. **QuickJS와 WebAssembly를 활용한 격리 환경** * **Sandboxing inside Sandbox:** Figma는 C 언어로 작성된 경량 자바스크립트 엔진인 QuickJS를 WebAssembly(Wasm)로 컴파일하여 브라우저 위에서 실행했습니다. * **메모리 및 자원 제어:** Wasm 환경은 호스트 시스템(브라우저)과 완전히 격리된 선형 메모리 공간을 사용하므로, 플러그인 코드가 Figma의 내부 데이터나 브라우저 API에 직접 접근하는 것을 원천 차단합니다. * **결정론적 실행:** 플러그인이 사용할 수 있는 CPU 시간과 메모리 할당량을 세밀하게 제어할 수 있어, 악성 코드나 무한 루프에 빠진 플러그인이 전체 앱의 가용성을 해치지 않도록 방어합니다. **효율적인 플러그인 API 설계** * **가상 API 브릿지:** 플러그인이 Figma의 문서 구조(Scene graph)에 접근할 때, 실제 데이터를 복사하는 대신 프록시(Proxy) 객체를 통해 필요한 데이터만 동기적으로 가져오도록 설계하여 통신 비용을 최소화했습니다. * **로직과 UI의 분리:** 플러그인의 비즈니스 로직은 QuickJS-Wasm 환경에서 실행되지만, 사용자 인터페이스(UI)는 별도의 `<iframe>`에서 실행되도록 분리했습니다. 이를 통해 안전한 UI 렌더링과 강력한 로직 격리를 동시에 달성했습니다. **시스템 안정성과 확장성 확보** * **동기적 실행 모델:** 개발자들에게 익숙한 동기 방식의 프로그래밍 모델을 제공하면서도, 내부적으로는 Wasm 기반의 격리 계층을 두어 복잡한 플러그인도 안정적으로 구동되게 했습니다. * **브라우저 독립성:** 특정 브라우저의 보안 버그나 패치에 의존하지 않고, Figma가 직접 제어하는 런타임 엔진을 통해 일관된 보안 수준을 유지합니다. 웹 환경에서 신뢰할 수 없는 외부 코드를 실행해야 한다면, 브라우저가 제공하는 기본 기능을 넘어 WebAssembly를 활용한 자체 런타임 환경 구축을 고려해야 합니다. 이는 구현 난이도가 높지만, 사용자 보안과 애플리케이션의 성능이라는 두 마리 토끼를 잡을 수 있는 가장 확실한 방법입니다. 특히 대규모 협업 툴이나 확장성이 중요한 플랫폼 서비스라면 Figma와 같은 "계층화된 샌드박스" 접근 방식이 훌륭한 레퍼런스가 될 것입니다.