데이터 설계 — 도메인 모델을 저장 가능한 형태로 변환하기
데이터 설계는 how-to-design-a-program-from-scratch|설계 프로세스에서 도메인 모델링 이후에 오는 단계로, 개념적 관계를 실제 저장 형태로 변환하는 과정이다. 도메인 모델이 "무엇이 존재하는가"라면, 데이터 설계는 "그걸 어떻게 담을 것인가"다.
도메인 모델과 데이터 설계의 차이
도메인 모델에서 "Course는 여러 Lecture를 가진다"는 개념적 관계일 뿐, 저장 방식은 결정되지 않았다. 같은 관계라도 저장 방식에 따라 완전히 다른 형태가 된다:
JSON: Lecture가 Course 안에 중첩(nesting)
{
"courses": [{
"name": "알고리즘",
"lectures": [{"day": "mon", ...}, {"day": "wed", ...}]
}]
}
SQL: Course와 Lecture가 분리, 외래키로 참조(reference)
courses: id | name | professor
lectures: id | course_id | day | start_time | end_time
이 선택이 데이터 설계다.
데이터 설계에서 결정하는 세 가지
1) 저장소 선택 — "어디에 저장하나"
how-to-choose-tech-stack|기술 스택 선택에서 이미 결정됐을 수 있다:
- Local-First → SQLite or JSON 파일
- Server-Centric → PostgreSQL, MySQL
- 간단한 설정값 → JSON/TOML 파일
2) 스키마 설계 — "어떤 형태로 저장하나"
도메인 모델의 각 개념을 저장소에 맞는 형태로 변환한다:
도메인 모델 테이블 설계
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Semester → semesters 테이블
Course → courses 테이블
Lecture → lectures 테이블
"Course가 Lecture를 가진다" → lectures.course_id (외래키)
"Semester가 Course를 가진다" → courses.semester_id (외래키)
여기서 판단이 필요한 부분도 생긴다. 예를 들어 Course.color는 courses 테이블에 넣을지, 별도 user_settings 테이블로 분리할지. 개인용 v1에서는 courses에 직접 넣는 것으로 충분하다.
3) 접근 패턴 — "데이터를 어떻게 읽고 쓰나"
자주 하는 조회가 뭐냐에 따라 최적화가 달라진다:
- "주간 시간표 보기"가 빈번 → 요일별 Lecture 조회가 빨라야 함
- "충돌 검사"가 빈번 → 같은 요일+시간대 조회가 빨라야 함
소규모 개인 앱에서는 깊이 고민할 필요 없지만, 이런 고려가 존재한다는 것을 알아두면 규모가 커질 때 도움이 된다.
전체 흐름
최종 산출물 예시
CREATE TABLE semesters (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
start_date TEXT NOT NULL,
end_date TEXT NOT NULL
);
CREATE TABLE courses (
id TEXT PRIMARY KEY,
semester_id TEXT NOT NULL REFERENCES semesters(id),
name TEXT NOT NULL,
professor TEXT,
credits INTEGER,
color TEXT
);
CREATE TABLE lectures (
id TEXT PRIMARY KEY,
course_id TEXT NOT NULL REFERENCES courses(id),
day TEXT NOT NULL,
start_time TEXT NOT NULL,
end_time TEXT NOT NULL,
room TEXT
);
도메인 모델의 "Course가 여러 Lecture를 가진다"가 lectures.course_id라는 외래키로 표현된 것. 이것이 데이터 설계의 핵심 산출물이다.