← 전체 해설 목록  ·  week-04 · 5강

5강 — 서비스 아키텍처 설계

🎯 학습 목표

📖 해설

1. 분석은 끝났는데, 어떻게 보여줄까요?

지금까지 우리는 리뷰를 수집·전처리하고, LLM으로 감성 분석·키워드 추출·리포트까지 만들고, 품질 검증과 편향 점검도 했습니다. 분석 기능 자체는 완성입니다. 그런데 남은 과제가 있습니다. 이 결과물을 다른 사람에게 어떻게 보여줄까요?

마케팅 팀장님이 "요즘 리뷰 반응 어때?" 하고 물을 때, 콜랩 링크를 보내며 "여기서 실행 버튼 누르세요"라고 할 순 없죠. 비개발자에게 콜랩은 외계어입니다. 화면을 캡처해 카톡으로 보낼 수도 있지만, 다음 주에 또 물으면 또 캡처해야 합니다. 엑셀로 정리해 메일을 보내면 분석보다 정리에 시간이 더 듭니다. 세 방법 모두 비효율적입니다 — 서비스가 아니라 수작업이거든요.

오늘은 코드를 한 줄도 짜지 않습니다. 대신 우리가 만든 분석 기능을 웹 서비스로 바꾸는 설계도를 그립니다. 건물을 짓기 전에 설계도를 먼저 그리는 것처럼요.

2. 콜랩 노트북 vs 웹 서비스 — 목적이 다르다

콜랩 노트북 웹 서비스
매번 코드를 실행해야 함 브라우저 열고 주소만 입력
콜랩 계정이 있어야 함 로그인 필요 없음
결과 공유가 번거로움(캡처·파일) 링크 하나로 공유 끝
비개발자는 사용 불가 누구나 버튼 클릭으로 사용
실행할 때마다 시간 소요 항상 최신 결과가 바로 표시

핵심은 목적입니다. 콜랩 노트북은 우리가 분석 로직을 만들고 테스트하는 개발용, 웹 서비스는 다른 사람에게 결과를 보여주는 제공용입니다. 요리사로 비유하면, 레시피를 개발할 때는 주방에서 이것저것 시도하지만, 손님에게 낼 때는 깔끔하게 플레이팅해서 서빙하죠. 주방의 뒤죽박죽을 그대로 보여주지 않습니다. 콜랩에서 코드 짜고 에러 고치는 건 개발 단계, 타 부서에 보여줄 땐 깔끔한 화면으로 결과만 — 그게 서비스입니다.

3. 웹 서비스 = 식당

웹 서비스 구조는 식당에 비유하면 바로 이해됩니다.

식당 웹 서비스 역할
손님 사용자 서비스를 이용하는 사람(팀장님, 동료)
메뉴판 프론트엔드 사용자가 보고 버튼 누르고 결과 확인하는 화면
주문서 API 요청 원하는 걸 주방에 전달하는 양식
주방 백엔드(서버) 실제로 계산·분석·데이터 처리하는 곳
냉장고 데이터베이스 리뷰·분석 결과 등 데이터를 보관하는 곳

여기서 생각해 볼 거리 하나. 식당에서 주방장이 바뀌어 레시피가 좋아졌다면, 메뉴판도 바꿔야 할까요? 바꿀 필요 없습니다. 손님은 똑같은 된장찌개를 주문하니까요. 주방에서 어떻게 만드는지는 손님이 알 필요가 없습니다. 웹 서비스도 똑같습니다. 백엔드(분석 로직)를 개선해도 프론트엔드(화면)는 그대로일 수 있습니다. 이게 역할 분리의 핵심 — 각 부분을 독립적으로 수정할 수 있다는 거죠.

정식 용어로, 웹 서비스는 3계층(3-tier) 구조입니다.

         👤 사용자
            │  클릭·입력
            ▼
   🖥️ 프론트엔드 (화면)        ← 메뉴판
            │  API 호출
            ▼
   ⚙️ 백엔드 (서버)            ← 주방
            │  데이터 조회·저장
            ▼
   🗄️ 데이터베이스 (저장소)    ← 냉장고

세 계층이 독립적이라 좋은 점은 유지보수가 쉽다는 것입니다. "화면은 잘 나오는데 데이터가 이상해" → 백엔드나 DB 문제겠죠. 어디가 문제인지 찾기 쉽고, "넌 화면 만들어, 난 서버 만들게"처럼 팀 협업도 쉬워집니다.

4. 데이터 흐름 — 버튼을 누르면 무슨 일이?

사용자가 화면에서 "분석 결과 보기" 버튼을 누르면, 짧은 순간에 이런 왕복이 일어납니다.

  1. 사용자가 프론트엔드(화면)에서 버튼 클릭
  2. 프론트엔드가 백엔드에 요청을 보냄 ("통계 데이터 주세요") — 이게 API 요청(HTTP 방식)
  3. 백엔드가 요청을 받음
  4. 백엔드가 데이터베이스에서 데이터를 가져옴
  5. 백엔드가 데이터를 가공(계산·정리)
  6. 백엔드가 프론트엔드에 응답을 보냄(JSON 형식)
  7. 프론트엔드가 응답을 받아 화면에 표시(차트·테이블)

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는 유지하는 것과 같은 사고입니다. 그리고 "설계 먼저"라는 메시지는 기획서의 본질 — 만들기 전에 무엇을·왜 만들지 못 박는다 — 와 정확히 일치합니다.

⚠️ 흔한 오해 / 짚고 갈 점

✅ 30초 정리

  1. 콜랩 노트북(개발용)과 웹 서비스(제공용)는 목적이 다릅니다. 공유엔 콜랩 링크 대신 서비스를.
  2. 웹 서비스는 3계층 — 프론트엔드(화면)·백엔드(서버)·데이터베이스(저장소). 식당의 메뉴판·주방·냉장고.
  3. 우리 스택은 Streamlit + FastAPI + SQLite, 전부 Python. 설계 먼저, 코딩 나중입니다.

▶️ 다음 강 연결

이제 머릿속에 전체 아키텍처가 들어왔습니다. 다음 차시(33차시)에서는 본격적인 코딩에 앞서 저작권과 생성형 AI — LLM으로 만든 결과물을 마음대로 써도 되는지, API 키를 코드에 넣으면 안 되는 이유 같은 — 실무에서 꼭 알아야 할 법적·보안 주의사항을 짚고, 그다음부터 이 설계도대로 서비스를 하나씩 구현해 나갑니다.

전체📚 강의 목록