5강 — 서비스 아키텍처 설계
🎯 학습 목표
- 콜랩 노트북과 웹 서비스가 목적이 다르다는 것을 설명할 수 있다
- 웹 서비스의 3계층 구조(프론트엔드·백엔드·데이터베이스)를 이해한다
- 버튼 클릭 한 번에 데이터가 어떻게 흐르는지(API 요청·응답) 따라갈 수 있다
- 우리 기술 스택 Streamlit + FastAPI + SQLite를 왜 골랐는지 안다
📖 해설
1. 분석은 끝났는데, 어떻게 보여줄까요?
지금까지 우리는 리뷰를 수집·전처리하고, LLM으로 감성 분석·키워드 추출·리포트까지 만들고, 품질 검증과 편향 점검도 했습니다. 분석 기능 자체는 완성입니다. 그런데 남은 과제가 있습니다. 이 결과물을 다른 사람에게 어떻게 보여줄까요?
마케팅 팀장님이 "요즘 리뷰 반응 어때?" 하고 물을 때, 콜랩 링크를 보내며 "여기서 실행 버튼 누르세요"라고 할 순 없죠. 비개발자에게 콜랩은 외계어입니다. 화면을 캡처해 카톡으로 보낼 수도 있지만, 다음 주에 또 물으면 또 캡처해야 합니다. 엑셀로 정리해 메일을 보내면 분석보다 정리에 시간이 더 듭니다. 세 방법 모두 비효율적입니다 — 서비스가 아니라 수작업이거든요.
오늘은 코드를 한 줄도 짜지 않습니다. 대신 우리가 만든 분석 기능을 웹 서비스로 바꾸는 설계도를 그립니다. 건물을 짓기 전에 설계도를 먼저 그리는 것처럼요.
2. 콜랩 노트북 vs 웹 서비스 — 목적이 다르다
| 콜랩 노트북 | 웹 서비스 |
|---|---|
| 매번 코드를 실행해야 함 | 브라우저 열고 주소만 입력 |
| 콜랩 계정이 있어야 함 | 로그인 필요 없음 |
| 결과 공유가 번거로움(캡처·파일) | 링크 하나로 공유 끝 |
| 비개발자는 사용 불가 | 누구나 버튼 클릭으로 사용 |
| 실행할 때마다 시간 소요 | 항상 최신 결과가 바로 표시 |
핵심은 목적입니다. 콜랩 노트북은 우리가 분석 로직을 만들고 테스트하는 개발용, 웹 서비스는 다른 사람에게 결과를 보여주는 제공용입니다. 요리사로 비유하면, 레시피를 개발할 때는 주방에서 이것저것 시도하지만, 손님에게 낼 때는 깔끔하게 플레이팅해서 서빙하죠. 주방의 뒤죽박죽을 그대로 보여주지 않습니다. 콜랩에서 코드 짜고 에러 고치는 건 개발 단계, 타 부서에 보여줄 땐 깔끔한 화면으로 결과만 — 그게 서비스입니다.
3. 웹 서비스 = 식당
웹 서비스 구조는 식당에 비유하면 바로 이해됩니다.
| 식당 | 웹 서비스 | 역할 |
|---|---|---|
| 손님 | 사용자 | 서비스를 이용하는 사람(팀장님, 동료) |
| 메뉴판 | 프론트엔드 | 사용자가 보고 버튼 누르고 결과 확인하는 화면 |
| 주문서 | API 요청 | 원하는 걸 주방에 전달하는 양식 |
| 주방 | 백엔드(서버) | 실제로 계산·분석·데이터 처리하는 곳 |
| 냉장고 | 데이터베이스 | 리뷰·분석 결과 등 데이터를 보관하는 곳 |
여기서 생각해 볼 거리 하나. 식당에서 주방장이 바뀌어 레시피가 좋아졌다면, 메뉴판도 바꿔야 할까요? 바꿀 필요 없습니다. 손님은 똑같은 된장찌개를 주문하니까요. 주방에서 어떻게 만드는지는 손님이 알 필요가 없습니다. 웹 서비스도 똑같습니다. 백엔드(분석 로직)를 개선해도 프론트엔드(화면)는 그대로일 수 있습니다. 이게 역할 분리의 핵심 — 각 부분을 독립적으로 수정할 수 있다는 거죠.
정식 용어로, 웹 서비스는 3계층(3-tier) 구조입니다.
👤 사용자
│ 클릭·입력
▼
🖥️ 프론트엔드 (화면) ← 메뉴판
│ API 호출
▼
⚙️ 백엔드 (서버) ← 주방
│ 데이터 조회·저장
▼
🗄️ 데이터베이스 (저장소) ← 냉장고
세 계층이 독립적이라 좋은 점은 유지보수가 쉽다는 것입니다. "화면은 잘 나오는데 데이터가 이상해" → 백엔드나 DB 문제겠죠. 어디가 문제인지 찾기 쉽고, "넌 화면 만들어, 난 서버 만들게"처럼 팀 협업도 쉬워집니다.
4. 데이터 흐름 — 버튼을 누르면 무슨 일이?
사용자가 화면에서 "분석 결과 보기" 버튼을 누르면, 짧은 순간에 이런 왕복이 일어납니다.
- 사용자가 프론트엔드(화면)에서 버튼 클릭
- 프론트엔드가 백엔드에 요청을 보냄 ("통계 데이터 주세요") — 이게 API 요청(HTTP 방식)
- 백엔드가 요청을 받음
- 백엔드가 데이터베이스에서 데이터를 가져옴
- 백엔드가 데이터를 가공(계산·정리)
- 백엔드가 프론트엔드에 응답을 보냄(JSON 형식)
- 프론트엔드가 응답을 받아 화면에 표시(차트·테이블)
API란 쉽게 말해 주문서 양식입니다. 식당 주문서에 메뉴·수량·테이블 번호를 정해진 형식대로 써야 주방이 알아듣듯, API도 "어떤 주소로 어떻게 요청하면 무엇을 받는지" 규칙이 정해져 있습니다. 이 규칙만 알면 웹·모바일·다른 서버 어디서든 같은 방식으로 쓸 수 있어, 한 번 만들면 여러 곳에서 재사용됩니다. 우리는 그동안 OpenRouter라는 남이 만든 API를 써 왔는데, 이제 우리가 직접 API를 만드는 단계로 갑니다. 만들 API는 네 개입니다.
| 메서드 | 엔드포인트 | 하는 일 |
|---|---|---|
| GET | /api/stats |
통계 조회(총 리뷰 수, 긍·부정 비율) |
| GET | /api/reviews |
리뷰 목록 조회(최근·필터링) |
| GET | /api/trends |
트렌드 조회(월별·주별 변화) |
| POST | /api/analyze |
새 리뷰 분석 요청(LLM 호출) |
GET은 데이터를 가져오는 것, POST는 뭔가 작업을 시키는 것입니다.
5. 기술 스택 선정 — 전부 Python
이제 화면·서버·DB를 각각 무엇으로 만들지 정합니다. 우리의 기준은 분명합니다. 데이터 분석가로서 결과를 빨리 보여주는 것이지, 웹 개발자가 되는 게 아닙니다.
화면: React vs Streamlit
| React (전통적) | Streamlit (우리 선택) |
|---|---|
| HTML·CSS·JavaScript 필요 | Python만 알면 됨 |
| npm·빌드 시스템 이해 필요 | pip install streamlit 끝 |
| 컴포넌트·상태 관리 개념 | st.title(), st.bar_chart() 호출 |
| 학습에 몇 주~몇 달 | 30분이면 첫 화면 완성 |
React가 더 예쁘지만 새 언어 세계를 배워야 합니다. 우리 목적엔 Streamlit이 맞습니다. (강의 후반부엔 React로 직접 구현하는 시연도 따로 보여줄 예정이니 기대해도 좋습니다.)
서버: Flask vs FastAPI
| Flask (2010년) | FastAPI (2018년, 우리 선택) |
|---|---|
| 오래되고 자료 풍부하나 다소 구식 | 콜랩 코드를 거의 그대로 사용 |
| 타입 힌트 없음 | 타입 힌트로 에러 미리 방지 |
| API 문서 수동 작성 | API 문서 자동 생성(/docs) |
이름처럼 FastAPI는 성능도 뛰어나(파이썬의 약점인 속도를 다른 언어 백엔드에 뒤지지 않게) 실무에서도 많이 씁니다.
데이터베이스: PostgreSQL vs SQLite
| PostgreSQL (대규모) | SQLite (우리 선택) |
|---|---|
| 별도 설치·서버 관리 필요 | 설치 불필요(Python 내장) |
| 대규모 트래픽용 | 파일 1개(reviews.db)로 끝 |
| 인스타그램·우버 등 운영 환경 | 소규모·학습에 딱 |
나중에 데이터가 수백만 건이 되면 PostgreSQL로 전환을 고려하지만(오라클·MySQL·MSSQL도 이런 대형 DB 부류입니다), 지금은 SQLite로 충분합니다. 최종 스택은 Streamlit + FastAPI + SQLite — 가장 중요한 건 전부 Python이라 새 언어를 배울 필요가 없다는 점입니다.
6. 맛보기 — 정말 Python만으로 되나?
설계가 끝났으니 각 도구를 아주 짧게 맛만 봅시다. (실행은 콜랩이 아니라 로컬 환경에서 하는 게 깔끔합니다.)
먼저 Streamlit — 단 몇 줄로 대시보드 화면이 됩니다. 아래 코드는 app.py 파일을 만들고, 터미널에서 streamlit run app.py로 실행하면 브라우저가 열립니다.
# Streamlit 대시보드 예시 (app.py로 저장됨)
streamlit_code = '''
import streamlit as st
import pandas as pd
st.title("🎮 게임 리뷰 분석 대시보드") # 페이지 제목
sentiment = st.sidebar.selectbox("감성 선택", ["전체", "긍정", "부정", "중립"]) # 사이드바 필터
data = {
"리뷰": ["재밌어요!", "별로예요", "그냥 그래요", "최고의 게임", "버그가 많음"],
"감성": ["긍정", "부정", "중립", "긍정", "부정"],
"신뢰도": [0.95, 0.88, 0.72, 0.91, 0.85],
}
df = pd.DataFrame(data)
st.subheader("📊 감성 분포")
st.bar_chart(df["감성"].value_counts()) # 막대 차트 한 줄
st.subheader("📋 리뷰 목록")
st.dataframe(df) # 데이터 테이블 한 줄
'''
with open('app.py', 'w', encoding='utf-8') as f:
f.write(streamlit_code)
print("app.py 생성 완료 → 터미널에서 'streamlit run app.py' (기본 포트 8501)")
다음 FastAPI — 함수에 @app.get(...) 한 줄(데커레이터)을 붙이면 API가 됩니다. main.py로 저장하고 uvicorn main:app --reload로 실행하면, /docs에서 API 문서가 자동 생성됩니다.
# FastAPI 서버 예시 (main.py로 저장됨)
api_code = '''
from fastapi import FastAPI
app = FastAPI(title="Steam 리뷰 분석 API", version="1.0.0")
@app.get("/")
def read_root():
return {"message": "Steam 리뷰 분석 API에 오신 것을 환영합니다!"}
@app.get("/api/stats") # GET /api/stats → 통계 조회
def get_stats():
return {"total_reviews": 5000, "positive": 3250,
"negative": 1250, "neutral": 500, "positive_rate": 0.65}
@app.get("/api/reviews") # GET /api/reviews → 리뷰 목록
def get_reviews(sentiment: str = None, limit: int = 10):
sample = [
{"id": 1, "text": "재밌어요!", "sentiment": "POSITIVE"},
{"id": 2, "text": "별로예요", "sentiment": "NEGATIVE"},
]
return {"reviews": sample[:limit]}
'''
with open('main.py', 'w', encoding='utf-8') as f:
f.write(api_code)
print("main.py 생성 완료 → 터미널에서 'uvicorn main:app --reload' (기본 포트 8000, 문서 /docs)")
마지막 SQLite — 파일 하나로 동작하는 DB입니다. 아래 코드는 바로 실행돼 reviews.db 파일을 만들고 데이터를 넣고 조회합니다. 테이블은 곧 엑셀 시트 — 열(column)은 엑셀의 열, 행(row)은 각 리뷰 데이터라고 생각하면 됩니다.
import sqlite3
conn = sqlite3.connect('reviews.db') # 파일이 없으면 자동 생성
cursor = conn.cursor()
# 테이블 생성 (한 번만)
cursor.execute('''
CREATE TABLE IF NOT EXISTS reviews (
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL,
sentiment TEXT,
confidence REAL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
# 데이터 삽입
sample_data = [
("정말 재밌는 게임이에요!", "POSITIVE", 0.95),
("버그가 너무 많아요", "NEGATIVE", 0.88),
("그냥 그래요", "NEUTRAL", 0.72),
]
cursor.executemany(
"INSERT INTO reviews (text, sentiment, confidence) VALUES (?, ?, ?)", sample_data)
conn.commit()
# 감성별 통계 조회 (SQL로 집계)
cursor.execute("SELECT sentiment, COUNT(*) FROM reviews GROUP BY sentiment")
print("감성별 통계:")
for sentiment, count in cursor.fetchall():
print(f" {sentiment}: {count}개")
conn.close()
세 도구 모두 보다시피 Python 문법 그대로입니다. 새 언어 없이, 지금까지의 실력으로 서비스를 만들 수 있다는 게 이 스택의 힘입니다.
7. 전체 그림 — 설계 먼저, 코딩 나중
전체를 한 장으로 정리하면 이렇습니다. 사용자가 브라우저로 Streamlit(포트 8501) 화면에 접속해 버튼을 누르면, Streamlit이 FastAPI(포트 8000)에 요청을 보냅니다. FastAPI는 SQLite(reviews.db)에서 데이터를 가져오고, 이미 분석된 결과가 있으면 바로 응답합니다. 새 리뷰를 분석해야 하면 FastAPI가 외부 OpenRouter(LLM) API를 호출해 감성 분석 결과를 받아 SQLite에 저장한 뒤 Streamlit에 응답하고, Streamlit이 차트·테이블로 화면에 표시합니다.
사용자 → Streamlit(:8501) → FastAPI(:8000) → SQLite(reviews.db)
│
└→ OpenRouter LLM API (새 리뷰 분석 시)
오늘 우리는 코드를 (맛보기 외엔) 짜지 않았습니다. 대신 전체 구조를 이해했죠. 건물을 설계도 없이 벽돌부터 쌓으면 나중에 "여기 창문 못 내네" 하며 허물게 됩니다. 서비스도 구조를 모르고 코드부터 짜면 다시 짜야 합니다. 설계가 제대로 되면 코딩은 자연히 따라옵니다. 그러니 무엇을 만들고 싶은지 구상하는 데 많은 노력을 기울이세요.
🔑 핵심 용어
| 용어 | 쉬운 설명 |
|---|---|
| 3계층(3-tier) 구조 | 프론트엔드·백엔드·데이터베이스로 나눈 웹 서비스 구조 |
| 프론트엔드 | 사용자가 보는 화면(메뉴판). 우리는 Streamlit |
| 백엔드(서버) | 실제 처리하는 곳(주방). 우리는 FastAPI |
| 데이터베이스 | 데이터 저장소(냉장고). 우리는 SQLite |
| API | "어떤 주소로 요청하면 뭘 받는지"의 규칙(주문서 양식) |
| 역할 분리 | 각 계층을 독립적으로 수정 → 유지보수·협업이 쉬움 |
| GET / POST | 데이터를 가져오기 / 작업을 시키기 |
🎮 게임 기획자 시점
이 강의 핵심 — "콜랩은 개발용, 서비스는 제공용" — 은 기획자에게 곧 분석을 조직의 의사결정 도구로 전환하는 문제입니다. 아무리 좋은 리뷰 분석도 분석가 한 명의 노트북에 갇혀 있으면 가치가 제한되죠. 팀장·마케팅·CS가 링크 하나로 최신 감성 트렌드를 보는 순간, 분석은 일회성 보고서에서 상시 운영 지표로 바뀝니다. 역할 분리(3계층) 개념도 기획에 그대로 옮겨집니다 — 분석 로직(백엔드)을 개선해도 사람들이 보는 대시보드(프론트엔드)는 그대로 두는 건, 라이브 게임에서 내부 밸런싱 로직을 바꿔도 유저가 보는 UI는 유지하는 것과 같은 사고입니다. 그리고 "설계 먼저"라는 메시지는 기획서의 본질 — 만들기 전에 무엇을·왜 만들지 못 박는다 — 와 정확히 일치합니다.
⚠️ 흔한 오해 / 짚고 갈 점
- 콜랩 링크를 공유하는 건 "서비스 제공"이 아닙니다. 비개발자는 실행조차 못 합니다.
- 3계층은 복잡하게 만들려는 게 아니라 역할을 나눠 유지보수를 쉽게 하려는 것입니다.
- Streamlit/FastAPI/SQLite는 "초보용 임시방편"이 아닙니다. FastAPI·SQLite는 실무에서도 널리 쓰입니다. 규모가 커지면 그때 갈아타면 됩니다.
- 설계 없이 코드부터 짜면 나중에 다시 짭니다. 오늘 코드가 거의 없는 건 일부러 그런 것 — 구조 이해가 먼저입니다.
✅ 30초 정리
- 콜랩 노트북(개발용)과 웹 서비스(제공용)는 목적이 다릅니다. 공유엔 콜랩 링크 대신 서비스를.
- 웹 서비스는 3계층 — 프론트엔드(화면)·백엔드(서버)·데이터베이스(저장소). 식당의 메뉴판·주방·냉장고.
- 우리 스택은 Streamlit + FastAPI + SQLite, 전부 Python. 설계 먼저, 코딩 나중입니다.
▶️ 다음 강 연결
이제 머릿속에 전체 아키텍처가 들어왔습니다. 다음 차시(33차시)에서는 본격적인 코딩에 앞서 저작권과 생성형 AI — LLM으로 만든 결과물을 마음대로 써도 되는지, API 키를 코드에 넣으면 안 되는 이유 같은 — 실무에서 꼭 알아야 할 법적·보안 주의사항을 짚고, 그다음부터 이 설계도대로 서비스를 하나씩 구현해 나갑니다.