- TIL. 최종프로젝트(24) 정답 중복 입력 막기 목차
[오늘 한일]
- 피드백 & 버그 내용 수정
[오늘 배운점]
<정답 중복 입력 막기>
유저들에게 서비스를 시작하고 나니까, 여러가지 피드백과 문제점들이 속출했다.
특히 함께 겨루기 부분이 이슈가 많았다.
- 겨루기가 다 끝나고 마지막 정답 입력하면 퀴즈 결과처리가 반복되는 문제
- 전체적으로 버벅이고 버튼이 종종 죽는 문제
- 채팅이 두번씩 입력되는 문제
- 배틀방에서 나가도 방이 삭제 안되고, 방을 다시 못만들게 되던 문제
팀원분께서 배틀페이지.js파일을 싹 리팩토링 해주시고
js코드를 정렬해주셔서 대부분 위 문제들이 해결 되었다.
채팅이 두번 쳐지는 문제는 addEventListener 유형을 keydown에서 keypress로 변경하셨다.
리팩토링을 통해 퀴즈 종료도 확실히 되고,
어떤식으로든 방을 나가면 방이 확실히 지워져서, 방관련 문제도 없어졌다.
다만 마지막으로, 정답을 빠르게 따라서 입력하면 중복으로 정답을 맞출수 있는 문제가 남아있었다.
이때문에 퀴즈개수 카운트도 틀어져서 퀴즈가 제때 종료되지 않았고,
이는 또 다른 문제를 야기했다.(다음 퀴즈가 시작이 안되었고, 배틀 시작중 ↔ 종료 전환이 잘 안되었다)
서버와 여러 사용자가 웹소켓을 주고받게 되는데
특징은, 서버쪽에서 공동적으로 정보를 저장할 곳이 없었다.
서버는 각개 유저와 연결되어있고 이게 그룹으로 묶여있을 뿐이였다.
그래서 각 유저와 연결된 컨슈머 인스턴스는 각 유저에게만 할당되있지,
변수같은것을 공유하지 못했다.
클래스 변수를 만들까도 생각했지만,
방이 계속 새로 생기고, 여러방이 존재할수 있는 등의 성질이 있어 적합하지 않다고 생각했다.
우리는 이걸 어려운 난제라고 생각했고,
DB나 redis등 어딘가 공동진행상황을 저장할곳이 필요하다고 생각했다.
하지만 나는 기존의 로직으로도 충분히 할수 있는 구석이 있을거라고 여기고
한번 자세히 들여다봤다.
프론트에 있는 퀴즈 인덱스를 기준으로 분석했다.
백엔드는 처음 퀴즈를 10개 생성해 각 참여자 클라이언트로 전송한다.
각 클라이언트는 이를 보관한다.
(이는 공동 저장구역이 없다는 위의 특징때문이였다.)
퀴즈 풀이 로직에 따라(js) 퀴즈는 하나씩 제공되고 정답을 외친 정답자의
메세지는 백엔드에서 따로 계수를 하게된다.
그럼 이 정답 메세지가 발생한 순간,
즉 서버에서 첫 정답자를 처리하고 반환 메세지를 보낸것을,
각자 클라이언트가 받아 채팅창에 띄워주는 이 순간이 공통적인 순간이된다.
이순간에서 현재의 퀴즈를 가공하는 것이다.
※ 나는 이순간에 현재 퀴즈의 인덱스를 서버에 전송하는걸 시도해봤다.
서버에게 인덱스를 보내는데에는 성공했으나,
역시나 이 인덱스를 공동적으로 알게되는게 불가능했다.
서버는 언제나 한 클라이언트로부터 웹소켓을 수신한다.
현재 퀴즈라는 데이터는 js의 전역변수 중 하나이다.
전체 퀴즈중 현재퀴즈가 번갈아 담긴다.
다음 퀴즈로 넘어가면 현재퀴즈가 바뀌니, 그전까지만 현재퀴즈에서
재정답제출이 일어나지 않게하면 되었다.
나는 위의 순간에서 현재퀴즈에 (딕셔너리 데이터다)
solved라는 키와 true라는 값을 부여하도록 했다.
그뒤 처음에는, 정답처리 함수를 먼저 수정해봤다.
하지만 곧 정답처리 함수로 진입을 시키면 안된다는것을 알게됬고
그 전단계인 채팅 처리 부분에서
정답처리 함수로 진입하는 분기 조건문에
현재퀴즈에 solved라는 키값이 있는지 없는지를 추가 검사하도록했다.
그렇게해서 중복정답을 잘 막을수 있었다.
if (gameState.startGame && !gameState.nowQuiz.hasOwnProperty("solved")) {
correctQuiz();
}
해당 조건문 코드는 위와 같다.
조건식안에 &&를 쓰면 이는 AND와 같은 역할을한다.
(디테일하게는 앞의 조건을 먼저 검사하고 만족해야 뒤의 조건을 검사한다고한다.)
nowQuiz 뒤에는 값을 검사한게 아닌
hasOwnProperty라는 js기능으로 키값이 존재하는지 유무를 검사했다.
값이야 항상 true일것인데,
키값이 있는 상태, 없는 상태로 퀴즈가 풀렸는지 아닌지가 나눠지기 때문이다.
js에서는 hasOwnProperty라는 기능이 이런역할을 한다.
한편 !gameState.nowQuiz.solved라고 입력하면
gameState.nowQuiz.solved는 undefined이지만 이를,
논리 뒤집기하면 False가 되어버린다. (즉, undefined이 falsy한 값이 아니다.)
이러한 특성을 유의할 필요가 있다.