1년 반 전 즈음 학과의 커리큘럼 페이지를 전담해서 구축한 적이 있다.

아무것도 모르는 상태로 구현하니, 굉장히 구린 페이지가 완성 됐는데 졸업 전 이걸 해결하고 졸업하고 싶어 친한 지인(ㅁㄱ님, ㅅㅇ님)께 부탁드려 갈아엎기로 했다.
전공 커리큘럼 페이지를 다시 만들면서 가장 많이 고민했던 질문은 이것이었다.
“매년 바뀌는 전공 이수 기준을, 어떻게 하면 구조적으로 깔끔하게 표현할 수 있을까?”
단순히 과목 목록을 보여주는 서비스라면 쉽다. (기존의 서비스)
하지만 내가 만들고 싶었던 것은:
- 학번(년도) 기준으로 졸업 이수 표준을 보여주고
- 학기(1-1 ~ 4-2)별로 과목을 배치하고
- 각 과목이 전공필수(M)인지, 전공선택인지, 핵심(C)인지를 명확히 표시하고
- 커리어 선택 시 관련 과목을 강조해주는 UI였다.
문제는 이 기준이 매년 바뀐다는 점이었다.
매번 학사서비스에 들어가서 내 학번 기준 졸업 기준을 찾아보거나 학과 사무실에 문의해야 하니, 추가적인 업무로 이루어진다는 불편함이 있다.
처음 떠올린 단순한 생각: “Subject에 year만 넣으면 되지 않을까?”
가장 처음 든 생각은 굉장히 단순했다.

“그냥 Subject 테이블에 year 컬럼 하나 추가하면 되는 거 아닌가?”
예를 들면 이런 식이다.
Subject
- id
- name
- semester
- credits
- requirementType (전필/전선)
- year
하지만 이 구조를 조금만 현실적으로 생각해보면 바로 문제가 드러난다.
왜 Subject.year 방식은 위험한가?
문제 상황 예시: 같은 과목, 다른 년도
“자료구조”라는 과목이 있다고 하자.
기준 년도학기이수구분
| 2024 | 2-1 | 전공선택 |
| 2025 | 1-2 | 전공필수 |
이걸 Subject.year로 표현하려면 결국 이렇게 된다.
Subject
- id=10, name="자료구조", year=2024, semester=2-1, requirementType=전선
- id=55, name="자료구조", year=2025, semester=1-2, requirementType=전필
즉, 과목 자체가 년도마다 복제된다.
복제의 후폭풍
과목이 복제되면 문제가 연쇄적으로 발생한다.
- 선수과목 관계는 어느 자료구조를 가리켜야 할까?
- 커리어 추천은 2024 자료구조? 2025 자료구조?
- 트랙(마이크로전공)에 포함된 과목은 어떤 id를 써야 할까?
결국 모든 관계 테이블이 년도별 Subject 복제본을 기준으로 다시 연결되어야 한다.
이건 단순히 컬럼 하나 추가로 끝날 문제가 아니었다.
오히려 데이터 중복 + 관계 복잡도 폭발로 이어진다.

“바뀌는 건 과목이 아니라, 과목의 ‘역할’이다”
이 시점에서 관점을 바꿨다.
과목이 년도별로 바뀌는 게 아니다
년도별로 ‘과목의 위치와 역할’이 바뀐다
즉,
- 과목명, 코드, 기본 설명 → 거의 안 바뀜
- 어느 학기에 배치되는지
- 전공필수인지 / 전공선택인지
- 핵심 과목인지
- 정렬 순서, 학점
이 값들이 년도(졸업 기준)에 따라 바뀐다.
그래서 이걸 분리하기로 했다.
설계 전환: Curriculum + CurriculumSubject
1. Subject: 과목 그 자체 (카탈로그)
Subject
- id
- code
- name
- description
- isOriginalLanguage
- “자료구조”는 여기서 단 한 번만 존재
- 선수과목/연계과목 같은 논리적 관계의 중심
2. Curriculum: 졸업 이수 기준 (년도 / 학번 기준)
Curriculum
- id
- year (예: 2025)
- name (예: "2025학번 졸업요건")
- isActive
- 사용자가 선택하는 “년도” = 사실상 학번 기준
- 매년 하나씩 추가, 보통은 이전 년도 복제 후 수정
3. CurriculumSubject: 년도 기준에서의 과목 역할
CurriculumSubject
- curriculum_id
- subject_id
- semester (1-1 ~ 4-2)
- credits
- requirementType (전필/전선)
- isCore
- displayOrder
여기에 년도별로 바뀔 수 있는 모든 값을 몰아넣었다.

예시로 보면 확실해진다
“자료구조” 하나로 두 년도를 표현해보자
Subject
- id=10, name="자료구조"
Curriculum
- id=1, year=2024
- id=2, year=2025
CurriculumSubject
- curriculum_id=1, subject_id=10, semester=2-1, requirementType=전선, isCore=false
- curriculum_id=2, subject_id=10, semester=1-2, requirementType=전필, isCore=true
과목은 하나
년도별 차이는 CurriculumSubject row로만 표현
관계(선수과목, 커리어 추천, 트랙)는 Subject 기준으로 그대로 유지
이 구조가 주는 장점
1) 년도별 졸업 기준 표현이 자연스럽다
- “2025 기준 전필 과목”
- “2024 기준 2-1 학기 표”
2) 데이터 중복이 없다
- 과목은 한 번만 정의
- 관계 테이블 재연결 필요 없음
3) 매년 개편 대응이 쉽다
- Curriculum 복제
- CurriculumSubject 일부 수정
4) UI 요구사항과 정확히 맞는다
- 학기 탭
- 전필(M) / 핵심(C) 뱃지
- 커리어 선택 시 하이라이트
정리
처음엔 “year 하나만 추가하면 되지 않을까?”라고 생각했다.
하지만 요구사항을 졸업 기준, 학기 배치, 이수 구분 관점으로 재해석하면서 깨달았다.
커리큘럼 페이지에서 년도에 따라 바뀌는 건 과목이 아니라, 과목의 ‘역할’이다.
그래서 선택한 구조는:
- Subject: 변하지 않는 과목
- Curriculum: 년도(학번)별 졸업 기준
- CurriculumSubject: 그 기준에서 과목이 어떤 역할을 하는지
이 분리가,
매년 바뀌는 전공 이수 기준을 가장 덜 아프게 감당할 수 있는 방법이라고 생각한다.
'프로그래밍' 카테고리의 다른 글
| [트러블 슈팅] 중복 객체 저장으로 인한 StackOverflowError와 중복 검사 최적화 (1) | 2025.05.20 |
|---|---|
| 나이스 교육 정보 OpenApi 사용 방법 및 후기 (1) | 2025.05.02 |
| MariaDB 설치 및 spring 연결(mac M1) (0) | 2024.04.06 |
| github (1) - github 기초 사용법 (0) | 2023.08.29 |
| 해커톤(4) - youtube 자막 추출 및 python파일 java에서 실행 (0) | 2023.08.23 |