Frontend

프론트엔드 시스템 디자인 (RADIO 접근법)

haeunkim.on 2026. 7. 15. 18:17

프론트엔드를 개발하며 대규모 트래픽에서 안정적으로 동작하게 설계하는 방법 같은 질문 앞에서는 어디서부터 생각을 시작해야 할지 명확한 정리가 필요하다고 느껴왔다. 말로 설명하려면 머릿속에 완벽한 다이어그램이 그려져야하는 사람이라 한번 각잡고 정리해봐야겠다 싶었다. 그치만 백엔드 시스템 디자인 자료는 많은데, 프론트엔드 관점의 시스템 디자인을 체계적으로 다루는 자료는 의외로 찾기 어려웠다. 여기저기 뒤지다가 인프런에서 [미국 빅테크 프론트엔드 시스템 디자인 실전: 단순 구현자로 남지 않기 위한 프론트엔드 개발자를 위해] (링크: https://inf.run/8ezQ9 ) 라는 강의를 발견했다. 한번 들어볼까 싶었다가.. 

 

이 후기를 보고 홀린듯 구매해버렸다.

 

이 글은 그 강의의 앞부분, AI 시대 프론트엔드 엔지니어의 역할과 RADIO 접근법 파트를 들으며 정리한 내용이다. 강의 내용에 추가로 내가 공부하며 얻은 인사이트를 추가했다.
크게 세 부분으로 나눴다.

  1. 프론트엔드 시스템 디자인의 중요성
  2. AI 시대의 프론트엔드: Thin Client vs Thick Client
  3. 문제 접근법 RADIO (Requirements, Architecture, Data Model, Interface, Optimization & Observability)

1. 프론트엔드 시스템 디자인의 중요성

프론트엔드를 "화면을 예쁘게 만드는 영역", "React 컴포넌트를 잘 구성하는 영역", "API를 받아서 렌더링하는 영역"으로만 보면 놓치는 게 많다. 프론트엔드 시스템 디자인은 사용자가 보는 화면을 기준으로 성능, 상태, 데이터 흐름, 렌더링, 캐싱, 장애 복구, 그리고 조직 확장성까지 설계하는 일이라고 표현한다.

Amazon 상품 페이지 예시

검색 바, 상품 이미지, 가격, 재고, Add to Cart 버튼이 있는 상품 페이지를 만든다고 해보자. 나부터도 직관적으로는 "상품 정보를 API로 받아와서 화면에 보여주면 되지 않나?"라고 생각하게 되는데, 실제로는 이런 질문들을 더 깊게 던져야 한다.

  1. 상품 가격이 바뀌면 화면은 언제 업데이트되어야 할까?
  2. Add to Cart를 눌렀을 때 서버가 재고 부족을 반환하면?
  3. 사용자가 수량 + 버튼을 빠르게 5번 누르면 서버 요청도 5번 보내야 할까?
  4. 상품 이미지가 늦게 로드되어 레이아웃이 밀리면?
  5. 모바일 저사양 기기에서 JS가 오래 실행되어 버튼이 안 눌리면?
  6. 새 릴리즈 이후 사파리 브라우저에서만 체크아웃 버튼이 먹통이면 어떻게 찾을까?

프론트엔드의 책임은 계속 커져 왔다

예전의 프론트엔드는 HTML, CSS, JavaScript 정도로 상대적으로 단순했다. 서버가 만든 페이지를 브라우저가 보여주는 구조였다.

지금은 다루는 범위가 훨씬 넓어졌다.

  • 클라이언트 상태 / 서버 상태 캐시
  • 실시간 이벤트
  • 라우팅, 렌더링 전략 (CSR/SSR/스트리밍 등)
  • 인증 / 권한
  • 이미지, 미디어 최적화
  • 성능 지표 수집

강의에서는 프론트엔드를 "API 결과를 보여주는 것"이 아니라 사용자의 기기, 브라우저, 네트워크, 서버 상태, UI 상태를 실시간으로 조율하는 실행 환경이라고 정의한다. 

Threads 피드가 "단순한 게시물 리스트"가 아닌 이유

Meta의 Threads 피드를 생각해 보자. 겉보기에는 게시글 API를 가져와 리스트로 보여주면 될 것 같지만, 실제로 풀어야 하는 문제 목록은 이렇다.

  • 서버 상태 캐시
  • 커서 기반 페이지네이션 (cursor pagination)
  • 실시간 pending buffer: 새 글이 실시간으로 도착해도 읽던 화면을 밀어내지 않도록 버퍼에 쌓아두는 처리
  • Optimistic like: 서버 응답 전에 좋아요 UI를 먼저 반영
  • 스크롤 안정성
  • Virtualization: 보이는 영역만 렌더링
  • RUM (Real User Monitoring): 실사용자 환경에서의 성능 관측

같은 맥락에서 Amazon 장바구니도 "cart 배열 렌더링"이 아니고, Netflix도 "video 태그 하나"가 아니다. 이런 시스템 디자인이 빠지면 결과물은 허울뿐인 사이드 프로젝트에서 끝나기 쉽다.


2. AI 시대의 프론트엔드: Thin Client vs Thick Client

"프론트엔드는 이제 AI가 다 만들 수 있다"는 말은 어느 정도는 맞는 말이다. AI는 아래와 같은 작업을 잘한다. 

  • Next.js 프로젝트 생성
  • CRUD 화면 생성
  • CSS / Tailwind 기반 UI 작성
  • 간단한 API 연결

그런데 여기서 "프론트엔드가 정말 이것뿐인가?"를 물어야 한다. 강의에서는 현재의 프론트엔드를 두 종류로 나누는데, 서버 데이터를 받아서 보여주는 프론트엔드(Thin Client) 와, 클라이언트 안에서 복잡한 제품 경험을 직접 운영하는 프론트엔드(Thick Client) 이다. 

Thin Client

클라이언트의 책임이 비교적 가벼운 앱이다. 대부분의 로직은 서버에 있고, 프론트엔드는 결과를 받아서 보여준다.

Server: 비즈니스 로직, Validation, Authorization, Data Processing
Client: Fetch Data → Render UI → Result 표시

 

기본 흐름도 단순하다. 사용자 입력 → 서버 요청 → 서버 처리 → 응답 표시.

UI를 함수로 표현하면 UI = render(serverState) 정도가 된다. (서버 상태가 오면 화면을 그리는 것)

예시: 블로그, 마케팅 페이지, 단순 관리자 CRUD.

Thick Client

클라이언트 안에 상당한 로직과 상태가 존재하는 앱이다. 서버 데이터를 보여주는 것을 넘어 클라이언트가 제품 경험을 직접 운영한다.

클라이언트가 관리하는 것들:

  • Local State
  • Server Cache
  • Optimistic Update
  • Command History (undo/redo의 기반)
  • Offline Queue
  • Realtime Events

예시: Figma, Notion, Canva, Google Docs, Spotify, ChatGPT류 앱.

Thick Client에서 UI는 서버 상태 하나의 결과물이 아니다. 서버 응답 하나만으로는 현재 UI를 결정할 수 없고, 로컬 편집 상태 + 아직 서버에 저장되지 않은 변경사항 + 웹소켓 이벤트 + 캐시 + 네트워크 상태 + 사용자의 의도까지 함께 고려해서 결정된다.

Thin vs Thick 비교

구분 Thin Client Thick Client
역할 서버 데이터 표시 클라이언트에서 복잡한 제품 경험 운영
주요 상태 서버 응답 데이터 로컬 상태 + 서버 캐시 + 펜딩 뮤테이션 + 실시간 이벤트
예시 블로그, CRUD 관리자 Figma, Google Docs, Spotify
네트워크 의존도 높음 낮추도록 설계하는 경우가 많음
오프라인 지원 거의 없음 필요할 수 있음
협업 기능 단순 실시간 동시 편집 가능
실패 처리 / 성능 병목 / 엔지니어링 난이도 낮음 높음

왜 Thick Client가 AI 시대의 차별점인가

AI는 패턴이 많은 작업에 강하다. CRUD, Form, Table, Card List, CSS Layout, API Route는 학습 데이터가 많고 정답 패턴도 비교적 명확하다. 그래서 AI가 빠르게 만들어내는 것은 대부분 Thin Client에 해당한다.

반면 Thick Client의 어려움은 상호작용의 조합에 있다. <= 너무 와닿는 표현

  • 복잡한 상태 관리
  • 비동기 레이스 컨디션
  • Optimistic update + rollback
  • Offline queue
  • 실시간 이벤트, 충돌 해결
  • undo/redo
  • 접근성

AI는 개별 패턴은 잘 생성한다. 하지만 이런 질문 앞에서는 안정적으로 답하거나 구현하기 어렵다.

사용자가 오프라인 상태에서 문서를 수정했고, 그 사이 다른 기기에서 같은 문서가 수정됐다. 다시 온라인이 되었을 때 어떤 변경을 어떻게 합칠 것인가?

사용자가 좋아요를 누르고 바로 취소했는데, 서버 응답은 반대 순서로 도착했다. 최종 UI는 무엇인가?

 

이런 문제는 단순 구현이 아니라 시스템 설계의 영역이다. 그래서 Thick Client가 AI 시대에도 프론트엔드 엔지니어의 고부가가치 영역으로 남는다는 것이 강의의 주장이고, 나도 여기에 동의하게 됐다.

더 읽어보기: 실제 Thick Client가 어떻게 만들어지는지 궁금하다면 How Figma's multiplayer technology works를 추천한다. 강의에서 나온 "오프라인 편집 후 온라인 복귀 시 충돌 해결" 문제를 Figma가 OT 대신 CRDT 아이디어로 어떻게 풀었는지 나온다. 이 방향을 더 깊게 파고 싶다면 local-first라는 개념을 처음 제시한 Ink & Switch의 에세이 Local-first software도 좋다.


3. RADIO: 프론트엔드 시스템 디자인 문제 접근법

RADIO는 프론트엔드 시스템 디자인 문제를 푸는 프레임워크다. 원래 GreatFrontEnd의 Front End System Design Playbook에서 제안된 접근법으로, Front End Interview Handbook에서도 같은 프레임워크로 인터뷰 대비 가이드를 제공한다.

  • R - Requirements (요구사항)
  • A - Architecture (아키텍처)
  • D - Data Model (데이터 모델)
  • I - Interface (인터페이스)
  • O - Optimization & Observability (최적화와 관측성)

이 프레임워크가 왜 필요할까. 나를 포함해서 많은 주니어 엔지니어들이 보통 "어떤 기술을 써야 하지?"부터 시작한다. React Query를 쓸지, Redux를 쓸지, 웹소켓을 쓸지, SSR을 쓸지. RADIO는 순서를 뒤집는다.

  1. 사용자가 어떤 결과물을 기대하는지
  2. 그 결과물의 품질 기준은 무엇인지
  3. 품질을 보장하려면 어떤 구조가 필요한지

이 질문들에 답하다 보면 기술 선택은 자연스럽게 따라 나온다.


R - Requirements: 무엇을 만들 것인가 X 무엇을 보장할 것인가 O !! 

검색 자동완성을 만든다고 해보자. 보통은 이렇게 설계를 시작하게 된다.

검색어 입력 → API 호출 → 결과 표시

 

그런데 이건 기능 설계에 가깝다. Requirements 단계에서는 질문을 더 던져야 한다.

  • 입력 후 몇 ms 안에 결과가 보여야 할까?
  • 모든 키 입력마다 API를 호출할 것인가? (debounce/throttle)
  • 이전 요청이 늦게 도착하면 최신 결과를 덮어쓰지 않을까? (레이스 컨디션. 요청 취소나 순서 보장이 필요하다)
  • 네트워크가 느리면 fallback 처리는 어떻게 할까?
  • 모바일 키보드, 접근성은?
  • 검색 결과 클릭률, no-result rate를 관측(모니터링)해야 할까?

둘을 나란히 놓고 보면 차이가 분명해진다.

  • 기능: 검색 결과를 보여준다.
  • 요구사항: 사용자가 입력하는 동안 빠르고 안정적으로, 최신 검색어에 맞는 결과만 보여주고, 오류나 지연 상황에서도 UX가 깨지지 않게 하는 것.

즉 Requirements는 기능 목록이 아니라 품질 기준이라고 이해하면 될 것 같다.

"빠르게"는 숫자로 증명해야 한다

"빠르게"는 사람마다 다르게 해석된다. 그래서 수치가 필요하다. 프론트엔드 시스템 디자인에서 쓰는 대표 지표가 Core Web Vitals다.

지표 측정 대상 권장 기준 (P75)

LCP (Largest Contentful Paint) 로딩 2.5초 이하
INP (Interaction to Next Paint) 인터랙션 반응성 200ms 이하
CLS (Cumulative Layout Shift) 시각적 안정성 0.1 이하

 

LCP는 페이지에서 가장 큰 주요 콘텐츠가 화면에 렌더링되기까지 걸린 시간이다. 사용자가 "아, 이제 메인 콘텐츠가 보이네"라고 느끼는 시점이라고 보면 된다. 쇼핑몰 상품 페이지라면 상품 대표 이미지, 히어로 이미지, 상품 제목, 메인 배너, 비디오 포스터 이미지 등이 LCP 요소가 된다.

INP는 사용자가 페이지와 상호작용한 뒤, 브라우저가 다음 화면 업데이트를 보여주기까지 걸린 시간이다. 쉽게 말해 반응 속도다. 장바구니 버튼 클릭, 좋아요 클릭, 검색어 입력 같은 상호작용 이후 다음 페인트까지의 시간을 잰다.

CLS는 사용자가 예상하지 못한 레이아웃 이동이 얼마나 발생했는지 나타내는 점수다. 로딩 중에 화면이 갑자기 아래로 밀리거나, 버튼이 움직이거나, 읽던 글이 튀는 현상. LCP나 INP처럼 시간이 아니라 점수라는 점이 특징이다. 예를 들어 상품 목록에서 이미지 크기를 미리 잡지 않으면, 이미지가 늦게 로드되면서 제목과 버튼이 아래로 밀린다. 사용자 입장에서는 "버튼 누르려고 했는데 갑자기 밀렸네"가 된다. 그래서 CLS가 나쁘면 사용자는 화면 자체를 신뢰하지 못하게 된다.

 

기능 유형에 따라 사용자 행동과 연결된 지표를 추가로 정의할 수도 있다.

  • 리스트/피드: Time to First Item
  • 검색: Input to Result Time
  • 장바구니: Add to Cart Feedback Time

평균의 함정과 P75

좋은 사용자 경험은 보통 P75 기준으로 본다. 전체 사용자 경험을 빠른 순서대로 줄 세웠을 때, 75%의 사용자가 기준 안에 들어와야 좋은 상태라는 뜻이다.

왜 평균이 아니라 P75일까. 사용자가 100명 있다고 가정해 보자.

  • 90명: LCP = 1초
  • 10명: LCP = 10초

평균을 계산하면:

(90 × 1 + 10 × 10) / 100 = 1.9초

 

평균 1.9초. 수치만 보면 괜찮아 보인다. 하지만 10명은 실제로 10초를 기다렸다. 많은 사용자는 빠르지만 일부 사용자가 매우 느린 경우, 평균만 보면 문제가 작게 보인다. 평균은 느린 사용자의 경험을 숨기는 셈이다.

P75 인덱스는 ceil(0.75 × n)으로 구한다. n = 100이면 75번째 사용자의 경험이 P75 값이 된다. 위 예시에서 P75는 1초로 나오지만, P90이나 P99를 보면 꼬리쪽 사용자의 고통이 드러난다. 어떤 percentile을 볼지 정하는 것 자체가 요구사항 정의의 일부라는 점이 흥미로웠다. 실제로 web.dev의 필드 측정 가이드에서도 평균 대신 percentile을 쓰라고 하면서, 느린 네트워크/기기 사용자의 경험을 이해하려면 P90, P95까지 볼 것을 권장한다.

더 읽어보기: 각 지표의 정의와 최적화 방법은 web.dev의 Web Vitals 문서가 원 출처다. 왜 하필 2.5초, 200ms, 0.1이고 왜 하필 75번째 percentile인지가 궁금하다면 How the Core Web Vitals metrics thresholds were defined를 읽어보자. 인간 지각 연구와 CrUX 실측 데이터를 바탕으로 "달성 가능하면서도 의미 있는" 기준을 고른 과정이 나온다.


A - Architecture: 폴더 구조가 아니라 책임 분리와 데이터 흐름

아키텍처라고 하면 보통 이런 걸 떠올리기 쉽다.

components/
hooks/
utils/
pages/

 

하지만 프론트엔드 시스템 디자인에서 아키텍처는 폴더 구조가 아니라 책임 분리와 데이터 흐름의 설계를 말한다.

Amazon 장바구니를 하나의 state로 만들어 보자.

const [cart, setCart] = useState([]);

 

처음에는 쉽지만 시간이 지나면 여러 상태들이 하나둘 생겨난다.

  • 서버 cart (서버에 저장된 진짜 장바구니)
  • cart count
  • quantity pending state (수량 변경 요청 중)
  • price changed state (담은 후 가격 변동)
  • out of stock state (품절)

이쯤 되면 문제가 생긴다. 무엇이 진짜 cart인가? 서버 실패 시 어디로 rollback해야 하나? 가격이 바뀌면 어떤 state를 업데이트해야 하나?

좋은 아키텍처는 상태를 성격에 따라 나눈다.

상태  유형 예시
Server State 서버가 Source of Truth인 데이터 장바구니 내용, 상품 가격
Local State 현재 화면에서만 필요한 UI 상태 호버, 모달 열림 여부
URL State 공유/복구 가능한 상태 검색어, 필터, 페이지
Optimistic State 서버 응답 전 임시 상태 좋아요 즉시 반영
Derived State 원본 상태에서 계산되는 값 cart count, 총액

 

이렇게까지 나누는 이유는, 모든 상태가 같은 생명 주기를 갖지 않기 때문이다. 장바구니는 서버와 동기화되어야 하지만, 호버 상태는 화면에서만 필요하다. 상태를 나누지 않으면 rollback, refetch, cache, cross-device 동기화에서 문제가 꼬이기 시작한다.

결국 핵심 질문은 "어디에 저장할까"가 아니라 "이 상태의 Source of Truth는 어디인가"로 바뀌어야 한다.

더 읽어보기: Server State와 Client State를 분리해야 하는 이유를 가장 잘 설명한 글로 TanStack Query 메인테이너 TkDodo의 React Query as a State Manager를 추천한다. "서버 데이터는 우리 앱이 소유(own)한 게 아니라 빌려와서 스냅샷을 보여주는 것"이라는 관점이 이 섹션의 Server State 개념과 정확히 연결된다. 같은 저자의 Practical React Query도!


D - Data Model: 화면이 안정적으로 동작하기 위한 모델

프론트엔드의 데이터 모델은 백엔드 DB 스키마가 아니다. 화면이 안정적으로 동작하기 위한 모델이다.

나쁜 모델: 상품 카드

type Product = {
  id: string;
  title: string;
  price: number;
  imageUrl: string;
};

 

작은 앱이라면 이걸로 충분할 수 있다. 하지만 실제 커머스에서는 훨씬 더 많은 정보를 포함해야한다. 

  • 색상 / 사이즈 옵션
  • 판매자별로 다른 offer
  • 할인 전 가격과 현재 가격
  • 재고 상태
  • 배송 가능성

price 하나에 다 욱여넣으면 나중에 UI 복잡도, 상태 버그, 체크아웃 오류, 장애 대응 비용으로 돌아온다.

좋은 모델: 개념 분리

모델 의미
Product 상품 개념
SKU 구매 가능한 옵션 단위 (색상/사이즈 조합)
Offer 판매자, 가격, 배송, 재고 조건
CartItem 사용자가 담은 SKU + Offer + 수량

데이터 모델이 성능을 결정한다: 소셜 피드 예시

type Post = {
  id: string;
  text: string;
  likedUsers: User[];  // 좋아요 누른 유저 전체 리스트
};

 

그런데 피드에서 실제로 필요한 것은 모든 likedUsers가 아니다. 필요한 건 두 가지뿐이다.

  • likeCount: 전체 좋아요 수
  • viewerState.liked: 현재 사용자가 좋아요를 눌렀는지 여부

복잡도로 비교해 보면:

  • likedUsers 배열 전송: O(L) (L = 좋아요 누른 사용자 수)
  • viewerState.liked 전송: O(1)

좋아요 10만 개짜리 게시글 20개를 피드에 보여준다고 가정해 보자.

likedUsers 방식:   20 × 100,000 = 2,000,000개의 user ID
viewerState 방식:  20개의 boolean

 

200만 개 vs 20개. 데이터 모델을 어떻게 잡느냐가 사용자 경험과 성능에 이 정도의 차이를 만들 수 있다는 게 중요한 점이다. 


I - Interface: API 명세만이 인터페이스가 아니다

프론트엔드 시스템 디자인에서 인터페이스는 4가지로 본다.

  1. 컴포넌트 인터페이스 (Props, Hook return type)
  2. 서버 API 인터페이스
  3. 이벤트 인터페이스 (Event contract)
  4. 관측/Telemetry 인터페이스

비디오 플레이어를 예로 들면, 단순하게는 이렇게 생각할 수 있다.

<VideoPlayer src={url} />

 

하지만 Netflix나 YouTube 수준의 플레이어에는 다른 수준의 인터페이스가 필요하다.

interface PlayerEngine {
  load(src: string): Promise<void>;
  play(): void;
  seekTo(time: number): void;
  setQuality(level: Quality): void;
  destroy(): void;
  subscribe(listener: Listener): Unsubscribe;
}

 

왜 이렇게 나눌까. 각자 맡은 역할이 다르기 때문이다.

  • UI: 버튼, 오버레이
  • 엔진: Manifest, Segment, Buffer, ABR (적응형 비트레이트)
  • Telemetry: Startup time, Rebuffer, Error

좋은 인터페이스는 팀과 시스템을 분리할 줄 안다. 기준은 세 가지. 협업이 가능한가, 테스트가 가능한가, 장애를 격리할 수 있는가.

"API 명세만 잘 잡으면 인터페이스는 끝 아닌가?"라는 생각이 들 수도 있는데, 프론트엔드에서는 컴포넌트 Props, Hook return type, Event contract, Telemetry schema까지 모두 인터페이스에 포함된다.

"Telemetry 스키마도 진짜 인터페이스인가?"라는 질문에 대한 강의의 답이 좋았다. Telemetry는 운영팀과 제품팀이 실제 사용자 경험을 이해하기 위해 맺은 계약이라는 것. "당장 필요하지 않은데 설계 단계에서 넣어야 하나?"에 대해서는, 나중에 문제가 터졌을 때 모니터링할 수 없는 시스템은 고칠 수 없기 때문이라고 답한다. 그래서 Telemetry까지 설계 단계에서 함께 넣는다.


O - Optimization & Observability: 최적화는 설계의 일부다

"기능 다 만들고 나중에 빠르게 만들면 된다"는 생각을 하기 쉬운데, 대규모 프론트엔드에서는 그때는 이미 늦는 경우가 많다고 한다.

  • 렌더링 구조가 잘못되면 나중에 최적화가 어렵다.
  • state 모델이 잘못되면 refetch나 rollback이 꼬인다.
  • 이미지 크기 정보가 없으면 CLS를 나중에 잡기 어렵다.
  • 관측 이벤트가 없으면 장애 원인을 찾기 어렵다.

메인 스레드와 롱태스크

브라우저의 메인 스레드는 대부분의 JavaScript 실행과 렌더링 관련 작업을 처리하고, 한 번에 하나의 태스크만 처리한다. web.dev에서는 50ms를 넘는 태스크를 long task로 정의하는데, 메인 스레드가 오래 막히면 사용자는 인터페이스가 응답하지 않는 것처럼 느끼게 된다. 앞에서 본 INP 지표가 나빠지는 직접적인 원인이기도 하다. 롱태스크를 쪼개고 메인 스레드에 양보(yield)하는 구체적인 기법은 web.dev의 Optimize long tasks에 잘 정리되어 있다.

그래서 프론트엔드 성능은 "JavaScript 수정, 렌더링 줄이기"에 그치지 않는다. 성능의 범위를 넓게 잡으면 이렇다.

  • 네트워크
  • JavaScript 실행
  • 이미지 / 비디오 로딩
  • 캐시
  • 상태 업데이트 범위
  • 브라우저 최적화
  • 렌더링
  • 관측 (Observability)

Virtualization 계산 예시

긴 리스트를 렌더링하는 흔한 코드이다.

{items.map((item) => (
  <Card item={item} />
))}

상품이 10개면 괜찮지만 10,000개라면 

items = 10,000
카드당 DOM 노드 = 30

생성되는 DOM 노드 = 10,000 × 30 = 300,000개

30만 개의 DOM 노드는 위험한 수준이다. Virtualization(가상화)을 적용하면 화면에 보이는 것만 렌더링한다.

visibleItems = 10      (화면에 보이는 아이템)
overscan    = 5        (스크롤 대비 위/아래 여유분)
nodes per card = 30

렌더링 노드 = (10 + 2 × 5) × 30 = 600개

300,000개 → 600개. 500배 차이가 난다. 이런 브라우저 실행 모델과 최적화 조건까지 고려하는 것이 프론트엔드 시스템 디자인의 범위라는 걸 알 수 있었다.


정리

  • 프론트엔드는 사용자가 직접 만지는 분산 시스템의 최전선이다. API 결과를 보여주는 것이 아니라 기기, 브라우저, 네트워크, 서버 상태, UI 상태를 실시간으로 조율하는 실행 환경이라고 보는 관점이 필요하다.
  • AI가 빠르게 만드는 것은 대부분 Thin Client다. 상태, 비동기 정확성, 협업, 동기화, 복구 로직이 얽힌 Thick Client가 AI 시대 프론트엔드 엔지니어의 고부가가치 영역으로 남는다.
  • RADIO는 기술 선택("React Query? Redux? 웹소켓?")이 아니라 품질 보장에서 출발하는 접근법이다.
    • R: 기능 목록이 아니라 품질 기준. "빠르게"는 LCP/INP/CLS 같은 수치로, P75 기준으로 증명한다. 평균은 느린 사용자를 숨긴다.
    • A: 폴더 구조가 아니라 책임 분리와 데이터 흐름. 상태마다 생명 주기가 다르므로 Server / Local / URL / Optimistic / Derived로 나누고, Source of Truth를 정한다.
    • D: 화면이 안정적으로 동작하기 위한 모델. likedUsers O(L) vs viewerState O(1)처럼 모델 설계가 곧 성능이 된다.
    • I: 컴포넌트, API, 이벤트, Telemetry까지 전부 인터페이스다. 좋은 인터페이스의 기준은 협업, 테스트, 장애 격리.
    • O: 최적화는 나중이 아니라 설계의 일부다. 50ms 롱태스크, 30만 노드 → 600 노드 virtualization처럼 브라우저 실행 모델까지 설계 범위에 들어간다.

 

*이 글에는 인프런 파트너스 활동의 일환으로 수수료를 제공받을 수 있는 링크가 포함되어 있습니다. 강의는 제 돈으로 직접 구매해서 수강했고, 내용 정리와 평가는 전부 제 판단입니다.