시니어 백엔드 포지션의 기술 면접에서 코딩 테스트는 "탈락시킬 사람을 거르는" 필터에 가깝고, 실제로 합격과 불합격을 가르는 단계는 시스템 설계 라운드다. 이유는 단순하다. 주니어는 주어진 API 스펙을 구현하면 되지만, 시니어는 "요구사항이 명확하지 않은 상태에서 제약 조건을 스스로 도출하고, 여러 선택지 중 트레이드오프를 명시하며 의사결정할 수 있는가"를 증명해야 한다. 면접관은 정답 아키텍처를 찾으러 온 것이 아니라, 당신이 장애 상황에서 조직을 대표해 판단할 수 있는 사람인지 관찰하러 온 것이다.
이 문서는 "URL shortener를 그려 보세요"라는 고전적 질문에 45분 안에 요구사항 명확화부터 장애 대응까지 매끄럽게 talk-through할 수 있도록 구성된 실전 스터디 팩이다. CJ 올리브영 웰니스 플랫폼처럼 트래픽 스파이크가 분명하고, 커머스/회원/추천이 동시에 돌아가는 환경에서 시니어로서 설득력 있게 말할 수 있어야 한다.
핵심 개념 1: 요구사항 명확화는 "문제를 좁히는 행위"다
면접관이 "URL shortener를 설계해 달라"고 하면 바로 박스와 화살표를 그리기 시작하는 후보는 거의 대부분 감점된다. 시니어는 먼저 문제의 경계를 재정의해야 한다. 다음 세 축으로 질문을 던진다.
Functional requirements (기능 요구사항)
핵심 사용자 시나리오는 무엇인가? 단축 URL 생성, 리다이렉트, 통계 조회, 만료 관리, 커스텀 alias?
쓰기(write) vs 읽기(read) 비율 추정은? URL shortener는 보통 1:100 ~ 1:1000의 read-heavy 시스템이다.
사용자 인증이 필요한가? 익명 생성을 허용하는가?
통계(클릭 수, 지역별 분포)는 실시간인가 배치로 충분한가?
Non-functional requirements (비기능 요구사항)
가용성 목표: 99.9% (연 8.76시간 다운) vs 99.99% (연 52분)?
지연시간 목표: 리다이렉트 p99 < 100ms?
데이터 보존 기간: 5년? 무기한?
보안: 단축 URL을 통한 피싱 방지, abuse detection?
일관성 / 실시간성 / 확장성 축
방금 만든 단축 URL을 즉시 리다이렉트할 수 있어야 하는가? (read-your-writes)
통계 카운터는 eventual consistency로 충분한가?
트래픽 성장 예측: 1년 후 10배, 5년 후 100배를 감당해야 하는가?
이 질문을 15개쯤 준비해서 면접 초반 5~7분을 "질문-확인-정리"로 사용하는 것이 프로다. 좁혀진 요구사항은 이후 모든 의사결정의 정당화 근거로 사용된다. 예를 들어 "실시간 통계는 eventual로 가능"이라는 합의를 얻어내면, 나중에 Kafka + 배치 집계 구조를 자연스럽게 정당화할 수 있다.
핵심 개념 2: Capacity estimation — back-of-the-envelope 계산
용량 추정을 못 하는 시니어는 없다. 하지만 면접장에서 당황하지 않고 빠르게 계산하려면 "숫자 블록"을 외워 둬야 한다.
기본 숫자 블록:
1일 = 86,400초 ≈ 10^5초
1년 = 약 3 × 10^7초
UTF-8 영문자 1자 = 1 byte, 한글 1자 = 약 3 bytes
HDD seek = 10ms, SSD seek = 0.1ms, 메모리 read = 100ns, 네트워크 RTT(같은 리전) = 0.5ms
나쁜 예 2: "처음부터 10개 MSA로 쪼개요."
→ 초기 트래픽에 비해 운영 복잡도 폭증. 분산 트랜잭션, 분산 추적, CI/CD, 인증 전파 전부 비용.
개선: 모듈러 모놀리스로 시작, 데이터 오너십 경계를 명확히 유지, 병목이 드러날 때 해당 경계만 분리(strangler fig pattern).
나쁜 예 3: 캐시 TTL을 모든 키에 정확히 1시간으로 설정.
→ 정각마다 대량 만료 → 동시 DB 폭격(thundering herd).
개선: TTL에 ±10% 랜덤 jitter, hot key는 probabilistic early refresh.
후보자 경험 연결 포인트
Slot 엔진 추상화 경험: "게임 슬롯의 다양한 수학 모델을 engine abstraction 뒤에 숨겨, 클라이언트 계약을 깨지 않고 엔진을 추가/교체했다"는 서술은 결합도 분리 / plug-in 아키텍처 / contract-first 경험으로 연결된다. 시스템 설계 라운드에서 "서비스 분리 기준"이나 "stable interface와 내부 진화를 어떻게 양립시켰는가"를 물을 때 강력한 답변이 된다.
RAG 배치 경험: "대량 문서 임베딩 배치를 안정적으로 운영했다"는 서술은 배치 vs 스트림, 재시도, idempotency, backpressure, partial failure 복구 경험이다. Kafka + 집계 잡 이야기를 할 때 자연스럽게 "실제로 이런 구조에서 poison message와 DLQ를 어떻게 처리했다"로 이어갈 수 있다.
면접에서는 "제가 맡았던 X에서 비슷한 트레이드오프를 겪었는데, 그때 Y를 선택한 이유는 Z였습니다"라는 템플릿을 2~3번 꽂으면 즉시 신뢰가 쌓인다.
면접 talk-through 구조 (45분용)
요구사항 명확화 (5~7분): functional, non-functional, 일관성/실시간성/확장성 축. 합의한 내용은 화면 한 귀퉁이에 적어 두고 계속 참조.
용량 추정 (3~5분): QPS, 저장소, 대역폭. 숫자를 끝까지 말한다.
하이레벨 설계 (8~10분): 박스와 화살표. 컴포넌트별 책임 한 줄 설명.
딥다이브 (10~15분): 면접관이 고르는 한 컴포넌트 또는 본인이 가장 자신 있는 곳. DB 스키마, 캐시 전략, 샤딩 키 결정.
병목 & 확장 (5~7분): "트래픽 10배가 되면 무엇이 먼저 부러지는가"를 스스로 말한다.
장애 대응 & 트레이드오프 (3~5분): 캐시 장애, DB primary 장애, 리전 장애. PACELC로 의사결정 요약.
시간 배분을 지키는 연습을 타이머 두고 3회 이상 해본다. 실전에서 가장 흔한 실패는 "하이레벨 설계에서 시간 다 쓰고 딥다이브를 못 하는 것"이다.
시니어가 자주 지적받는 공통 실수와 방어
"Scalable하게 설계했습니다"로 뭉뚱그림 → 방어: 숫자로 말한다. "피크 6만 QPS를 감당하도록 Redis 샤드 6개, replica 2개로 구성"처럼.
트레이드오프 없이 단정 → 방어: 모든 선택에 "대안 A/B를 고려했고, X 제약 때문에 A를 골랐다"를 덧붙인다.
분산 트랜잭션 남용 → 방어: Saga/outbox/idempotency key로 이벤트 기반 일관성을 설명.
장애 시나리오 미언급 → 방어: 항상 "이 컴포넌트가 죽으면 시스템은 어떻게 degrade되는가"를 먼저 말한다.
기술 유행어 나열 → 방어: Kafka, Kubernetes, GraphQL을 이유 없이 넣지 않는다. "이 요구사항 때문에 선택했다"가 없으면 감점 요인.