개발 › 백엔드
개발 › 백엔드 카테고리의 글
- 이벤트가 브라우저까지 — 폴링을 SSE로 바꾸다
21편에서 폴링으로 실시간을 흉내 냈습니다. 2초마다 당기는 방식은 지연도 있고 낭비도 있죠. 이번엔 진짜 push로 바꿉니다 — 사가의 이벤트를 브라우저까지 밀어냅니다. NATS→readmodel 프로젝터→SSE 허브→BFF 프록시→브라우저 EventSource. 그리고 그 과정에서 관찰성 미들웨어가 Flusher를 안 물려줘 스트리밍이 죽던 버그를, SSE 샌티 체크가 잡아냈습니다. 이벤트 기반 쇼핑몰 고도화 시리즈 23편입니다.
- 역할이 필요해질 때 — 관리자 페이지와 RBAC
지금까지 모든 사용자는 동등했습니다. 그런데 관리자 페이지를 만들려니 "누가 관리자인가"를 정해야 했습니다 — 역할(role)이 처음 필요해진 순간입니다. JWT에 role을 심어 인증(누구냐)에 인가(무엇을 할 수 있냐)를 더하고, 게이트를 서버(SSR)와 BFF 두 겹으로 두고, 읽기 모델의 집계를 통계 대시보드로, 카탈로그 write를 상품 관리로 끌어왔습니다. 이벤트 기반 쇼핑몰 고도화 시리즈 22편입니다.
- 프런트가 백엔드를 비춘다 — 실시간·검색·재고·세션
핵심 여정(상품→결제→주문)은 있었으니, 이제 백엔드의 강점을 화면에서 살릴 네 가지를 붙였습니다. 실시간 주문 상태로 사가가 움직이는 걸 새로고침 없이 보여주고, 이벤트 전용이던 재고 서비스에 조회 엔드포인트를 열어 품절을 표시하고, URL 쿼리로 검색·정렬을 SSR 하고, 서버 컴포넌트가 세션을 읽어 헤더에 로그아웃·장바구니 배지를 그립니다. 각 기능이 백엔드 개념 하나를 화면으로 끌어냈습니다. 이벤트 기반 쇼핑몰 고도화 시리즈 21편입니다.
- 테스트는 하나의 렌즈가 아니다 — 접근성·시각 회귀·부하
19편에서 기능 테스트로 "동작하는가"는 봤습니다. 그런데 "누구나 쓸 수 있나(접근성), 모양이 안 깨졌나(시각), 부하에 버티나(성능)"는 전혀 다른 렌즈였습니다. 세 가지를 더 붙였습니다 — axe 로 접근성을 스캔하다 라벨 없는 입력을 잡았고, Playwright 스냅샷으로 시각 회귀를 세우다 무작위 상품 순서 때문에 깨져 정렬로 고쳤고, autocannon 으로 부하를 재 p99 24ms 를 확인했습니다. 각 렌즈의 도구와 함정을 정리합니다. 이벤트 기반 쇼핑몰 고도화 시리즈 20편입니다.
- 테스트가 아키텍처를 드러낸다 — Next.js를 모든 층위에서 테스트하기
프런트를 붙였으니(17·18편) 이제 이걸 어떻게 믿을까요. "모든 종류의 테스트를 다 해보자" 마음먹고 시작했는데, 곧 진짜 교훈을 만났습니다 — 테스트가 쉬우려면 구조가 좋아야 한다. 라우트 핸들러가 fetch 를 직접 부르던 코드를, 순수 로직·API 어댑터·세션·얇은 핸들러로 계층을 나눴더니 테스트가 술술 붙었습니다. 유닛부터 컴포넌트(RTL), 라우트 통합, 그리고 Playwright E2E 까지 피라미드를 세운 이야기입니다. 이벤트 기반 쇼핑몰 고도화 시리즈 19편입니다.
- 백엔드에 프런트를 붙이니 보이는 것들 — BFF로 CORS를 지우다
지금까지 이 쇼핑몰은 API 뿐이었습니다. curl 로만 두드렸죠. 그런데 진짜 브라우저 프런트엔드(Next.js)를 붙이자마자 첫 벽이 나타났습니다 — CORS. 브라우저는 catalog·customer·cart·ordering 을 제각각 부를 수 없습니다. 흔한 답은 모든 서비스에 CORS 헤더를 바르고 게이트웨이를 세우는 것이지만, Next.js SSR 과 docker-compose 를 만나면 더 깔끔한 길이 있습니다 — BFF. 서버 컴포넌트는 컨테이너 안에서 내부 DNS 로 부르고, 변경은 Next Route Handler 로 통과시켜, CORS 를 코드 한 줄 없이 지웁니다. 이벤트 기반 쇼핑몰 고도화 시리즈 17편입니다.
- 메트릭과 SLO — 무엇을 재고, 어디까지 괜찮은가
8편에서 분산추적으로 "이 요청이 어디서 느렸나"를 봤습니다. 그런데 추적은 개별 사건이라, "지금 시스템 전체가 괜찮은가?"는 한눈에 안 보였습니다. 그 답이 메트릭입니다. 16편에서는 RED(요청률·에러·지연)와 비즈니스·신뢰성 지표를 Prometheus 로 노출하고 Grafana 대시보드로 세운 뒤, SLO·에러 예산·번 레이트로 "어디까지가 괜찮은가"를 숫자로 못박습니다. 이벤트 기반 쇼핑몰 고도화 시리즈 16편입니다.
- 이벤트 스키마 진화 — 옛 이벤트를 어떻게 읽을까
order.placed 이벤트에 필드 하나를 더하려다 문득 멈췄습니다. JetStream 스트림에는 예전 모양의 order.placed 가 이미 잔뜩 쌓여 있고, 읽기 모델은 시작할 때 그 과거를 전부 재생합니다. 이벤트는 DB 처럼 ALTER 로 고쳐 쓸 수 없는 불변의 기록인데, 모양이 바뀌면 옛 이벤트는 어떻게 읽어야 할까요? 15편에서는 두 가지로 답합니다 — 더하기 변경은 관용적 리더로 그냥 소화하고, 깨는 변경은 버전을 올려 업캐스팅으로 옛 이벤트를 최신 모양으로 끌어올립니다. 이벤트 기반 쇼핑몰 고도화 시리즈 15편입니다.
- 죽은 편지함 — 실패한 이벤트는 어디로 가나
이벤트 소비자가 처리에 실패하면 어떻게 될까요? 지금까지 이 쇼핑몰은 그냥 Nak — 무한 재전송이었습니다. 그런데 영원히 실패하는 독성 메시지 하나가 들어오면, 소비자는 그걸 붙들고 CPU만 태우며 뒤를 막습니다. 14편에서는 두 축으로 이 문제를 풉니다 — 일시적 장애는 지수 백오프로 재시도해서 흡수하고, 끝내 실패하는 메시지는 죽은 편지함(DLQ)으로 보내 격리합니다. 잃지도, 막히지도 않게. 이벤트 기반 쇼핑몰 고도화 시리즈 14편입니다.
- 인증과 인가 — 로그인·JWT·본인 것만
지금까지 이 쇼핑몰은 누구나 남의 이름으로 주문하고 남의 주문을 들여다볼 수 있었습니다. customer_id 를 클라이언트가 그냥 적어 보냈으니까요. 13편에서는 이 구멍을 막습니다 — 비밀번호는 bcrypt 로, 로그인은 표준 라이브러리만으로 만든 HS256 JWT 로, 그리고 신원은 오직 토큰에서만. 주문·장바구니를 미들웨어로 감싸 "본인 것만" 만지게 하고, 장바구니→주문 호출에는 토큰을 그대로 이어 흘려 신원을 전파합니다. 이벤트 기반 쇼핑몰 고도화 시리즈 13편입니다.
- 모놀리식을 쪼개며 배운 것들 — MSA 전환 회고
모놀리식을 마이크로서비스로 분리하며 실제로 부딪힌 문제들을 정리합니다. 서비스 경계를 잘못 그었던 대가, 공유 DB를 나누는 일의 어려움, saga로 분산 트랜잭션을 다룬 방식, 장애 전파와 관찰성, 그리고 다시 한다면 무엇을 다르게 할지까지 — 개요가 아니라 경험으로 적었습니다.
- 서버리스, Lambda는 언제 답인가 — cold start·비용·동시성으로 따져보기
서버리스는 만능이 아니라 트레이드오프입니다. Lambda가 빛나는 워크로드와 오히려 독이 되는 워크로드를, cold start·비용 모델·동시성·실행시간 관점에서 따져보고 의사결정 기준을 정리합니다.