AI를 활용하여 시스템 디자인을 연습하는 방법 (URL 단축기 워크스루)
요약
시스템 디자인 면접을 효과적으로 연습하기 위해 단일 프롬프트 대신 단계별 체이닝(Chain the steps) 방식의 AI 워크플로우를 활용하는 방법을 제안합니다. 요구사항 정의부터 트레이드오프 분석까지 실제 면접 프로세스를 모방한 다단계 구조를 통해 더 깊이 있는 추론을 유도합니다.
핵심 포인트
- 단일 프롬프트는 패턴 매칭에 의존하여 구체적인 설계 근거를 제시하지 못함
- 시스템 디자인은 요구사항, 규모 추정, 아키텍처 비교 등 순차적 프로세스가 핵심임
- AI에게 면접 형식을 반영한 7단계 다단계 워크플로우를 적용하여 학습 효과 극대화
- 이전 단계의 출력을 기반으로 다음 단계를 구축하는 체이닝 방식 권장
저는 수년 동안 지원자로서, 그리고 면접관으로서 시스템 디자인 (System Design) 면접을 진행해 왔습니다. 혼자서 연습할 때 가장 어려운 부분은 지식이 아닙니다. 바로 프로세스입니다. 요구사항 (Requirements) 정의부터 시작하여, 수치를 계산하고, 확정하기 전에 여러 옵션을 평가하며, 마지막에 명시적인 트레이드오프 (Trade-off) 논거를 제시하는 과정 말입니다. 관련 내용을 읽는 것도 도움이 되지만, 실제로 직접 수행해 보는 것은 다릅니다. 몇 달 전, 저는 전체 시스템 디자인 세션을 처음부터 끝까지 안내하는 구조화된 다단계 AI 계획을 구축했습니다. 저는 이를 사용하여 다양한 시스템을 대상으로 연습해 왔습니다. 이 포스트는 URL 단축기 (URL shortener)를 예시로 사용하여, 이 계획이 정확히 어떤 결과물을 만들어내는지 보여줍니다.
단일 프롬프트 시스템 디자인의 문제점
AI로 시스템 디자인을 연습할 때 흔히 취하는 방식은 다음과 같습니다: "당신은 시니어 엔지니어입니다. URL 단축기를 설계하세요. 요구사항, 아키텍처 (Architecture), 데이터베이스 스키마 (Database schema), 캐싱 (Caching), 확장성 (Scalability)을 다루세요." 그러면 꽤 철저해 보이는 결과가 돌아옵니다. 캐싱을 위한 Redis, 저장을 위한 PostgreSQL, 로드 밸런서 (Load balancers), CDN 등등. 답변은 모든 항목을 충족합니다. 하지만 이를 더 깊게 파고들어 보십시오. 왜 Memcached가 아니라 구체적으로 Redis인가요? 어떤 QPS (Queries Per Second) 수치가 그 결정을 이끌어냈나요? 왜 301이 아니라 302인가요? 왜 그 파티셔닝 키 (Partitioning key)를 사용했나요? AI는 이에 답할 수 없습니다. 왜냐하면 이러한 선택을 무언가로부터 도출한 것이 아니라, 학습한 수천 개의 URL 단축기 관련 기사들로부터 패턴 매칭 (Pattern-matching)을 했기 때문입니다. 출력 결과가 맞게 들리는 이유는 학습 데이터가 맞게 들리기 때문입니다.
또 다른 문제: 단일 프롬프트는 전체 설계 프로세스를 단 한 번의 시도로 압축해 버립니다. 실제 시스템 디자인은 순차적입니다. 수치를 계산하기 전에 아키텍처를 선택할 수 없습니다. 대안들을 평가하기 전에 트레이드오프 논거를 만들 수 없습니다. 단계를 건너뛴다고 해서 결과가 틀린 것은 아니지만, 추론 과정이 보이지 않게 됩니다.
다른 접근 방식: 단계별 체이닝 (Chain the steps)
시스템 디자인 면접이 잘 알려진 형식을 갖추고 있는 데에는 그만한 이유가 있습니다.
당신은 다음과 같은 특정 단계들을 순서대로 수행해야 합니다: 요구사항 명확화 (clarify requirements), 규모 추정 (estimate scale), 아키텍처 옵션 제안 및 비교 (propose and compare architecture options), 상위 수준 설계 (draw the high-level design), 핵심 구성 요소 심층 분석 (deep-dive into the critical components), 그리고 트레이드오프 (trade-offs)로 마무리하기. 단계를 건너뛰거나 순서를 어기는 것은 당신에게 구조화된 접근 방식 (structured approach)이 없다는 신호가 됩니다. 여기서 얻을 수 있는 통찰은 이 형식이 다단계 AI 워크플로우 (multi-step AI workflow)와 직접적으로 매핑된다는 점입니다. 하나의 거대한 프롬프트 (prompt)를 사용하는 대신, AI에게 동일한 면접 구조를 한 번에 한 단계씩 따르도록 지시하며, 각 단계는 이전 단계의 출력물 (output)을 기반으로 구축되도록 합니다. 저는 공식적인 시스템 디자인 면접 형식을 반영하여 워크플로우를 다음과 같은 7개의 순차적 단계로 구성했습니다:
| 단계 | 면접 단계 | 수행 내용 |
|---|---|---|
| 1 | 요구사항 (Requirements) | 요구사항을 명확히 하고 완성하며, 누락된 비기능 요구사항 (NFR) 기본값을 채우고, 가정을 명시함 |
| 2 | 백오브엔벨로프 (Back-of-envelope) | 산술 연산을 통해 트래픽, 저장소, 대역폭 및 캐시 추정치를 도출함 |
| 3 | 아키텍처 옵션 (Architecture options) | 장단점을 포함한 2~3가지 옵션을 제안하고, 하나를 추천하며, 비교 다이어그램을 생성함 |
| 4 | 상위 수준 설계 (High-level design) | 구성 요소 개요, 데이터 흐름, 전체 아키텍처 다이어그램 작성 |
| 5 | 심층 분석 (Deep-dive) | 데이터 모델, API 설계, 확장성 전략 (scalability strategies), 장애 모드 (failure modes) 테이블 작성 |
| 6 | 트레이드오프 (Trade-offs) | 결정 테이블, 알려진 한계점, 향후 개선 사항 작성 |
| 7 | 최종 문서 (Final doc) | 모든 내용을 하나의 일관된 문서로 조립함 |
각 단계의 프롬프트는 {{step_id}} 플레이스홀더 (placeholder)를 사용하여 이전의 출력물을 참조합니다. 장애 모드 테이블이 작성될 때쯤이면, AI는 정확한 QPS 수치, 주요 병목 현상 (bottleneck), 그리고 어떤 아키텍처가 왜 선택되었는지를 정확히 알고 있습니다. 어떤 것도 고립된 상태에서 임의로 만들어지지 않습니다. 저는 YAML을 통해 다단계 AI 세션을 정의할 수 있는 Askimo Plans를 사용하여 이를 구축했습니다. 다음은 이 플랜이 실행되는 짧은 데모입니다: [IMG:1] 하지만 중요한 것은 구조 그 자체입니다. 단계 간에 컨텍스트 (context)를 전달할 수 있는 어떤 도구에서도 동일한 체인 (chain)을 구현할 수 있습니다.
제공된 URL 단축기 (URL shortener)를 통해 살펴보겠습니다. 저는 다음과 같은 입력값들을 제공했습니다:
시스템: URL 단축기 (URL Shortener)
기능적 요구사항 (Functional requirements): URL 단축, 원본으로 리다이렉트 (redirect), 커스텀 별칭 (custom aliases), 클릭 분석 (click analytics)
비기능적 요구사항 (Non-functional): 99.99% 가용성 (availability), 리다이렉트 지연 시간 (latency) < 10ms p99
규모 힌트 (Scale hints): 5억 명의 사용자, 일일 활성 사용자 수 (DAU) 5,000만 명. 일일 신규 URL 2억 개 (평균 초당 쓰기 횟수 2,300회)
요구사항 (requirements) 단계에서는 아무것도 설계하지 않습니다. 사용자가 제공한 내용을 정확하게 재진술하고, 누락된 비기능적 기본값들을 채워 넣으며, 명시적인 가정을 표시합니다. 이번 실행에서 주목할 만한 점 하나는, 제 입력값에는 단순히 "리다이렉트"라고만 적혀 있었다는 것입니다. AI는 301 리다이렉트가 영구적(permanent)이라는 점을 지적했습니다. 브라우저가 이를 캐싱(cache)하기 때문에 사용자는 서비스에 단 한 번만 접속하게 되고, 결과적으로 분석 (analytics) 기능이 작동하지 않게 됩니다. AI는 302가 올바른 선택임을 제시했습니다. 작은 디테일이지만 실제 아키텍처 (architectural) 측면에서 중대한 결과이며, 이를 잡아내기에 가장 적절한 단계입니다.
대략적인 계산 (back-of-envelope) 단계는 실무에서 대부분의 사람들이 건너뛰지만, 인터뷰에서는 이 때문에 무너지는 단계입니다. 이 시스템의 경우: 피크 시 리다이렉트 QPS 35,000, URL 레코드용 915 GB, 5년간의 분석 데이터용 365 TB, 인기 URL을 위한 183 GB 캐시 (cache)가 필요합니다. 이 365 TB라는 숫자는 분석 데이터를 URL과 동일한 데이터베이스에 저장하는 것을 즉시 배제합니다. 1000:1의 읽기/쓰기 비율 (read/write ratio)은 이 시스템이 읽기 집약적 (read-heavy)이며 거의 모든 것이 캐시 적중률 (cache hit rate)에 달려 있음을 나타냅니다. 이렇게 도출된 수치들은 이후의 모든 아키텍처 결정의 근거가 됩니다.
아키텍처 옵션 (architecture options) 단계는 해당 수치들을 바탕으로 장단점과 Mermaid 비교 다이어그램을 포함한 2~3개의 서로 다른 설계를 제안합니다. 이 시스템의 경우, 비동기 분석 (async analytics)을 결합한 읽기/쓰기 분리 (read/write split) 구조로 결론이 났습니다: Redis와 읽기 복제본 (read replicas)을 기반으로 하는 상태 비저장 (stateless) 리다이렉트 서비스, 별도의 쓰기 서비스, 그리고 Kafka를 거쳐 ClickHouse로 들어가는 분석 데이터 구조입니다. 이 권장 사항은 아키텍처적으로 유행하는 방식이 아니라, 수치에 의해 정당화됩니다.
상위 수준 설계 (high-level design), 심층 분석 (deep-dive), 그리고 트레이드오프 (trade-offs) 단계는 각각 이전 단계의 결과물을 바탕으로 구축됩니다. 아키텍처 다이어그램의 모든 규모 산정 (sizing) 결정은 추정치로 거슬러 올라갑니다. 장애 모드 (failure modes) 테이블은 두 단계 전에서 식별된 병목 현상 (bottlenecks)을 참조합니다.
트레이드오프 (trade-off) 테이블 — 대부분의 지원자가 건너뛰는 단계 — 의 모든 행은 이전 결정으로 추적 가능합니다: 요구사항에서 비롯된 302 vs 301, 183 GB 캐시 추정치에서 비롯된 Memcached 대신 Redis, < 10ms p99 리다이렉트 SLA에서 비롯된 ClickHouse 직접 쓰기 대신 Kafka를 선택한 것 등이 그 예입니다. 디자인은 시작점이지 막다른 길이 아닙니다. 계획이 완료되면, Askimo는 전체 실행 과정의 모든 컨텍스트 (context)를 메모리에 유지합니다. 여러분은 후속 질문을 통해 대화를 계속 이어갈 수 있으며, AI는 이미 자신이 생성한 모든 내용을 알고 있습니다. 예를 들어, 위의 상위 수준 디자인 (high-level design)은 의도적으로 클라우드 불가지론적 (cloud-agnostic)으로 설계되었습니다. 만약 이를 AWS에 배포하고 싶다면, "이 아키텍처를 AWS 서비스로 매핑해줘"라고 요청할 수 있습니다. AI가 전체 컨텍스트 — 35K 피크 QPS, 183 GB Redis 클러스터, Kafka 파이프라인, ClickHouse 분석 저장소 — 를 가지고 있기 때문에, 응답은 일반적이지 않습니다. AI는 각 특정 구성 요소를 변환합니다: Redis를 위한 ElastiCache, Kafka를 위한 MSK, 리다이렉트 서비스를 위한 ALB + ECS Fargate, PostgreSQL을 위한 읽기 복제본이 있는 RDS Aurora를 제안하며, 365 TB의 분석 볼륨을 고려할 때 EC2 상의 ClickHouse가 나을지 아니면 Redshift와 같은 대안이 더 합리적일지 제안합니다. 다른 후속 질문들도 같은 원리입니다: "이것을 GCP에서 실행하려면 어떻게 해야 하나요?"라고 물으면 Cloud Memorystore, Pub/Sub, Cloud Run, Cloud SQL을 얻게 됩니다. "리다이렉트 서비스에 대한 Kubernetes 배포는 어떤 모습인가요?"라고 물으면 HPA 설정, 리소스 제한 (resource limits), 지연 시간 SLA에 맞춰 조정된 활성 프로브 (liveness probes)를 얻게 됩니다. "35K QPS 기준 이 디자인의 월간 AWS 비용을 추정해줘"라고 하면 서비스별 대략적인 비용 내역을 얻게 됩니다. 계획이 구축한 컨텍스트가 바로 이러한 답변들을 유용하게 만드는 핵심입니다. 이전의 체인 (chain)이 없다면 일반적인 클라우드 매핑 결과만 얻게 됩니다. 하지만 체인이 있다면, 여러분이 실제로 설계한 시스템에 특화된 결과물을 얻을 수 있습니다.
체인된 컨텍스트 (chained context)가 중요한 이유
위의 트레이드오프 테이블은 임의로 만들어진 것이 아닙니다. 모든 행은 이전 단계에서 내려진 결정으로 거슬러 올라갑니다: 302 vs 301은 AI가 클릭 분석에는 302가 필요하다고 표시했던 요구사항 단계에서 비롯되었습니다.
301 리다이렉트는 브라우저가 해당 리다이렉트를 캐싱하게 만들어 서비스에 요청을 보내는 것을 중단시키므로, 분석 데이터의 흐름이 끊기게 됩니다. RDBMS 대신 NoSQL을 선택한 것은 대략적인 계산 (back-of-envelope) 단계에서 비롯되었습니다. 50TB의 URL 매핑 데이터와 500K의 피크 QPS (초당 쿼리 수)는 수동으로 샤딩된 PostgreSQL 클러스터를 배제합니다. NoSQL 선택은 기본 가정이 아니라 이러한 수치에서 도출된 직접적인 결과입니다. 읽기 경로에서 API Gateway 대신 ALB를 사용하는 것 또한 대략적인 계산의 결과입니다. 하루 100억 건의 리다이렉트가 발생할 경우, API Gateway의 요청당 과금 방식은 비용 면에서 감당할 수 없게 됩니다. 아키텍처를 그리기 전부터 이 추정치가 비용 문제를 가시화했습니다. Kafka를 통한 비동기 분석 (Async analytics)은 요구사항에 명시된 10ms 미만의 p99 리다이렉트 SLA (서비스 수준 협약)를 따릅니다. 리다이렉트 핫 패스 (hot path)에서 초당 115K 건의 클릭 이벤트를 동기적으로 기록하는 것은 지연 시간 예산 (latency budget)을 초과하게 됩니다. Kafka는 쓰기 작업을 분리하여 리다이렉트 서비스가 즉시 응답할 수 있게 합니다. ID 생성을 위한 DynamoDB 원자적 카운터 (Atomic Counters)는 이전 단계에서 선택된 NoSQL 전용 아키텍처와 결합하여, 요구사항에 명시된 충돌 방지 보장으로부터 도출되었습니다. 이로 인해 ZooKeeper 클러스터가 필요하지 않습니다. 단일 프롬프트로는 이를 생성할 수 없는데, 참조할 사전 맥락이 없기 때문입니다. AI는 그저 URL 단축기에 적절해 보이는 것을 아무거나 선택할 뿐입니다. 다단계 접근 방식은 결론을 추측하는 것이 아니라 도출하도록 강제합니다. (궁금한 분들을 위한) 계획 구조: 이 세션의 배후에는 7단계로 구성된 YAML 파일이 있습니다. 각 단계는 하나의 명확한 목표를 가지며, {{step_id}} 참조를 통해 이전 모든 단계의 출력값을 맥락으로 전달받습니다.
| 단계 | 목표 | 주요 입력값 | 요구사항 |
|---|---|---|---|
| Clarify, complete, and de-ambiguate the inputs | 입력값을 명확히 하고, 완성하며, 모호함을 제거합니다 | 기능적/비기능적(NFR)/규모 힌트 | {{requirements}} |
| back-of-envelope | 산술 연산을 통해 트래픽, 저장소, 대역폭 및 캐시 추정치를 도출합니다 | {{requirements}} | |
| architecture-options | 장단점과 Mermaid 비교 다이어그램을 포함한 2~3개의 뚜렷한 옵션을 제안합니다 | {{requirements}}, {{back-of-envelope}} | |
| high-level | 컴포넌트 개요, 데이터 흐름, 전체 아키텍처 다이어그램을 작성합니다 | {{requirements}}, {{back-of-envelope}}, {{architecture-options}} | |
| deep-dive | 데이터 모델, API 설계, 장애 모드(failure modes) 테이블, 시퀀스 다이어그램을 작성합니다 | {{high-level}} | |
| tradeoffs | 결정 테이블, 알려진 한계점, 향후 개선 사항을 작성합니다 | {{requirements}}, {{high-level}}, {{deep-dive}} | |
| final | 모든 출력물을 하나의 공유 가능한 문서로 조립합니다 | 이전의 모든 단계 |
{{step_id}} 참조가 체인을 작동하게 만드는 핵심입니다. back-of-envelope 단계는 사용자의 입력을 다시 읽는 것이 아니라, 1단계에서 명확해진 요구사항을 읽습니다. architecture-options 단계는 추측하지 않습니다. 2단계의 수치와 1단계의 요구사항을 확인합니다. 각 단계는 한 가지 일만 수행합니다.
전체 YAML 파일은 GitHub에 있습니다. 이를 복사하여 어떤 Askimo 인스턴스에든 로드하거나, 자신만의 계획 변형을 위한 템플릿으로 사용할 수 있습니다.
다른 시스템에 적용하기
저는 현재까지 몇 가지 다른 시스템에 이를 적용해 보았습니다:
- 실시간 채팅 (Real-time chat) - architecture-options 단계는 WebSocket vs SSE vs long-polling의 트레이드오프(trade-offs)에 집중하며, deep-dive 단계에서는 메시지 순서 보장 및 전달 보장이 주를 이룹니다.
- 승차 공유 플랫폼 (Ride-sharing platform) - 매칭 지연 시간(matching latency)이 지배적인 제약 조건이 됩니다. 지리 공간 인덱싱(geospatial indexing)을 고려할 때 back-of-envelope 단계가 흥미로워집니다.
- 비디오 스트리밍 (Video streaming) - 저장소 및 CDN 비용이 모든 것을 압도합니다. 사전 인코딩(pre-encoding) 대 적응형 비트레이트 스트리밍(adaptive bitrate streaming)에 관한 트레이드오프에서 깊이 있는 분석이 이루어집니다.
계획 구조는 동일하게 유지됩니다. 결론은 수치가 무엇을 보여주느냐에 따라 달라집니다.
직접 시도해 보기
있는 그대로 실행하고 싶다면 Askimo에 이 계획이 내장되어 있습니다.
시스템 이름, 요구사항, 규모 힌트(scale hints)를 입력한 다음, 사용 중인 어떤 AI 제공업체(OpenAI, Claude, Gemini 또는 Ollama를 통한 로컬 모델)와 함께 세션을 진행하면 됩니다. 또한 YAML을 수정하여 단계를 추가할 수도 있습니다. 예를 들어, 대략적인 계산(back-of-envelope) 이후의 비용 추정 단계, 보안 검토 단계, 마이그레이션 계획 단계 등을 추가할 수 있습니다. 플랜 에디터(plan editor)에는 직접 작성하고 싶지 않은 경우를 위해 일반적인 영어 설명으로부터 YAML을 작성해 주는 AI 생성기가 포함되어 있습니다. 시스템 디자인 플랜의 전체 소스 코드는 GitHub에서 확인할 수 있습니다. 기여(Contributions)를 환영합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기