문제 상황

1차 MVP에서는 사용자가 객관식 4지 선다만을 출제할 수 있었습니다. 당시에는 추후 문제 유형을 추가할 계획이 없었기 때문에 UI 및 데이터 구조가 객관지 4지 선다를 중심으로 구성되어 있었습니다.

3차 MVP 당시 새로운 문제 유형 추가에 대한 논의가 나오면서 낱말 맞추기 문제 유형을 구현하게 되었습니다. 단순히 기존 데이터 구조에 필드만을 추가하는 방식으로는 새로운 문제 유형을 구현할 수 없어 기존에 존재했던 데이터 구조 및 UI 구현 방식을 크게 변경해야 하는 상황이 발생했습니다.

해결 방법 논의

1. 문제 유형에 따른 데이터 구조 설계

우선 각 문제 유형에 따른 데이터 구조 설계를 진행하였습니다. 기존 4지 선다와 같은 경우, 다음과 같은 데이터 구조를 가지고 있었습니다.

data class Question(
    val id: String,
    val title: String,
    val solution: String?,
    val description: String,
    val answer: Int,
    val choices: List<String>,
    val userAnswers: List<Int>,
)

낱말 맞추기 문제 유형에 대한 데이터 구조를 설계했을 때, id / title / solution을 제외한 나머지 필드 부분이 완전히 다른 구조를 가져야 했습니다.

data class BlankQuestion(
    val id: String,
    val title: String,
    val solution: String?,
    val userAnswers: List<String>,
    val questionContent: List<Map<String, String>>,
) : Question()

스크린샷 2024-12-01 오후 10.37.24.png

2. 퀴즈 유형에 따라 화면을 다르게 그려야 한다고??

하나의 퀴즈에는 4지선다 객관식 / 낱말 맞추기 두 유형의 문제가 들어갈 수 있습니다. 서버에서 데이터를 내려주면 어떤 유형인지를 파악하고 그에 알맞은 화면을 그리기 위해서는 내려주는 데이터 속에 문제 유형을 나타내는 필드가 존재해야 했습니다.

이를 위해 저희는 Server Driven UI를 학습해 적용하였습니다. Server Driven Ui란 서버에서 내려주는 데이터를 바탕으로 화면을 그리는 방식을 말합니다. 저희는 전체 화면의 디자인을 서버에서 내려주기 보다는 문제 유형에 대한 타입을 서버에서 내려주는 방식을 적용하고자 하였습니다.

data class BlankQuestionDTO(
    val title: String? = null,
    val solution: String? = null,
    var questionContent: List<Map<String, String>>? = null,
    val type: String? = null,
    var userAnswers: List<String>? = null,
)

data class ChoiceQuestionDTO(
    val title: String? = null,
    val description: String? = null,
    val solution: String? = null,
    val answer: Int? = null,
    val choices: List<String>? = null,
    var userAnswers: List<Int>? = null,
    val type: String? = null,
)
  

3. 문제 유형 추상화

fireStore는 NOSQL이기 때문에 하나의 collection(table) 안에 서로 다른 데이터 구조 넣을 수 있습니다. 이를 받아와 위에서 정의한 BlankQuestionDTO / ChoiceQuestionDTO로 변환한 후, 하나의 List를 만들기 위해서는 타입 추상화를 진행해야 합니다.

스크린샷 2024-12-01 오후 11.00.26.png

이를 위해 다음과 같이 상위 문제 유형인 Question을 두고 공통 필드를 구성하였습니다.

그리고 BlankQuestion / ChoiceQuestion을 각각 구성해 Question의 하위 타입을 구성했습니다.