어떤 기능들이 필요한가
Online Judge 라고 하면 필요한 기능에 대해 생각해보자. 간략히 생각해보면 아래 기능이 있을 것이다.
- 사용자는 계정을 만들 수 있다.
- 사용자는 로그인을 할 수 있다.
- 사용자는 계정을 삭제할 수 있다.
- 사용자는 문제 목록을 볼 수 있다.
- 사용자는 문제를 만들 수 있다.
- 사용자는 문제를 볼 수 있다.
- 사용자는 문제에 대한 답안을 제출할 수 있다.
- 사용자는 제출한 답안에 대한 채점 결과를 테스트 케이스 별로 볼 수 있다.
위 기능 요구사항에 어떤 구성 요소가 존재하는가
그렇다면 위 기능 요구사항에서 어떤 개체를 추출할 수 있는가? 위 요구사항 문장들에서 명사를 추출해보면 알 수 있다.
또한 각 개체들이 어떤 정보를 가져야 하는지, 어떤 역할을 하는지 함께 알아보자.
1. 사용자 (User)
- 기본키: id (UUID)
- 속성: name, password, email
- 역할: Online Judge 시스템 이용 주체, 문제 생성 및 답안 제출을 할 수 있다.
2. 문제 (Problem)
- 기본키: id (UUID)
- 외래키: userId (문제 생성자)
- 속성: title, description, cpuTimeLimit, wallTimeLimit, memoryLimit
- 역할: 해결해야 할 코딩 문제 정보
3. 테스트 케이스 (TestCase)
- 기본키: id (UUID)
- 외래키: problemId
- 속성: expectedInput, expectedOutput
- 역할: 문제의 입출력 검증 데이터
4. 제출 (Submission)
- 기본키: id (UUID)
- 외래키: problemId, userId
- 속성: language (enum), code
- 역할: 사용자가 제출한 답안. 코드 본문과 언어 정보를 가지고 있다.
5. 채점 결과 (Judgment)
- 기본키: id (UUID)
- 외래키: submissionId
- 속성: status (JudgmentStatus enum)
- 역할: 제출에 대한 전체적인 채점 결과
6. 테스트 케이스 별 채점 결과 (TestCaseResult)
- 기본키: id (UUID)
- 외래키: testCaseId, judgmentId
- 속성: executionStatus, executionCpuTime, executionWallTime, memoryUsage, stdout, stderr
- 역할: 개별 테스트 케이스의 실행 결과
7. 언어 (Language)
- 값 객체: enum (C, CPP, Java, Python3)
- 역할: 지원하는 프로그래밍 언어
개체-관계 Diagram
그렇다면 각 구성 요소는 어떻게 상호작용하는지 개체-관계 분석을 통해 알아보자.
엔티티 간 관계
1. User ↔ Problem (0:N)
- 설명: 한 사용자가 0개 이상 문제를 생성할 수 있다.
2. User ↔ Submission (0:N)
- 설명: 한 사용자가 0개 이상 답안을 제출할 수 있음
3. Problem ↔ TestCase (0:N)
- 설명: 한 문제는 0개 이상의 테스트 케이스를 가진다.
4. Problem ↔ Submission (0:N)
- 설명: 한 문제에 대해 여러 사용자가 답안을 제출할 수 있다.
5. Submission ↔ Judgment (0:N)
- 설명: 하나의 제출에 대해 여러 번의 채점이 가능하다. (재채점이 가능하다.)
6. Judgment ↔ TestCaseResult (1:N)
- 설명: 하나의 채점은 여러 테스트 케이스 채점 결과를 포함한다.
7. TestCase ↔ TestCaseResult (0:N)
- 설명: 하나의 테스트 케이스는 여러 제출에 대해 실행될 수 있다.
E-R Diagram
그렇게 하여 최종적인 개체-관계 다이어그램은 다음과 같다.
개체-관계 다이어그램이다.
다음 글에서는 간단한 구현을 바로 시작해보자. 가장 간단한 기능 요구사항부터 만들어 나가보도록 하겠다.