한결과 레지아이스

[42GG] 시퀀스 다이어그램 2부 - 로직을 중심으로 본문

42GG/설계

[42GG] 시퀀스 다이어그램 2부 - 로직을 중심으로

miniwho 2022. 8. 12. 13:56

  42GG 백엔드 시퀀스 다이어그램 2부입니다.

  이번 글은 정보 전달이라기보다는 기록에 의미를 두고 작성하게 되었습니다.

  백엔드에서 사용한 컨트롤러가 이것뿐이지는 않지만, 구현할 때 애를 먹거나 단순 조회가 아니고 무언가 로직이 들어간 부분들에 대해서 정리해 보았습니다.

  개인적으로는 로직도 중요하지만 어떤 예외 처리를 어떤 이유로 했는지도 꽤나 많이 배우게 된 부분입니다. 로직을 만드는 것은 누구나 고생한다면(혹은 하지 않아도) 만들 수 있지만, 서비스로서 원활히 돌아가게 하기 위해선 수많은 예외 상황들을 생각하고 이에 대해 적절한 처리를 해줘야 한다고 느꼈습니다.

  사실 저희 서비스에서 로직은 어려운 부분도 아니고 누구나 비슷하거나 어쩌면 다른 더 나은 방식으로도 비슷한 결과를 낳도록 구현하는게 어렵지 않을 거라고 생각합니다. 그래서 예외에 대한 부분이나 개선하고 싶은 부분들에 대해서 쓰려고 노력했고, 그런 부분을 봐주시면 감사하겠습니다.

 

슬롯 조회 시퀀스

  42GG에서 슬롯은 보통 게임에서 사용하는 방의 개념이다. 크레이지 아케이드나 카트라이더 같은 게임의 방을 생각하면 유사하다고 볼 수 있다.

  슬롯은 open, close, mytable 세 가지 상태를 가진다. 그리고 현재 방의 인원수도 표시한다.

  유저가 슬롯을 조회할 때는, 오늘의 모든 슬롯에 대해서 세 가지 상태 중 어떤 상태에 있는지를 확인한다. 기본이 open이다. 이미 슬롯의 시간이 지난 경우, 슬롯에 현재 사람이 있고 그 사람과 나의 점수(PPP) 차가 기준치 이상으로 큰 경우, 방의 정원이 가득 찬 경우(단식 2, 복식 4), 나는 단식을 골랐는데 복식으로 구성된 방일 경우(혹은 반대)에 close가 된다. 그리고 내가 이미 어떤 슬롯에 들어가 있는 경우, 그 슬롯은 mytable 상태를 가지고 이때는 다른 슬롯에 들어갈 수 없게 된다.

 

매칭 취소 시퀀스

  이제 위에서 조회한 슬롯을 바탕으로, mytable이 있는 경우 해당 슬롯을 눌러서 유저는 취소 요청을 할 수 있다. 그런데 2번을 보면 등록된 슬롯이 있는지를 확인한다. mytable을 눌렀는데 대체 왜 확인하는가? 이런 부분이 처음에는 익숙하지 않았는데, 확인하는 이유는 다음과 같다.

  유저는 프론트 화면을 통해서만 요청을 보낼 수 있는 것이 아니다! 유저는 proxyman 같은 프로그램을 이용해 어떤 API 요청이 이루어지는지 상세하게 확인할 수 있고, postman이나 curl 요청 등으로 자신이 원하는 요청을 프론트를 거치지 않고 보낼 수 있다.

DELETE /pingpong/match/slots/1

  슬롯에서 나갈 때는 이러한 API 요청이 이루어지게 된다. 1이라는 id를 가진 슬롯에서 유저를 제거해주는 기능을 가지는데, 이때 id를 임의로 변조해서 값을 보낸다면 유효하지 않은 요청이 될 것이다. 그래서 유저가 등록한 슬롯이 있는지 먼저 확인하고, 만일 없다면 400 에러를 반환한다.

  다른 경우는 기능적인 부분이다. 성사된 게임이 임박한 경우 갑자기 유저가 나가게 된다면 상대방은 피해를 보게 된다. 이런 때에도 퇴장은 불가능하다.

  그리고 이미 성사된 게임에 대해서는 임박하지 않은 경우에 한해 퇴장이 가능하다. 한 유저가 퇴장하면 다른 유저는 상대방이 나갔다는 웹 내 알림 메시지와, 메일 알림을 받게 된다. 이때 메일 알림이 JavaMailSender에 의해 보내지는데, 하나의 메일이 보내지는데 약 3초가 걸린다. 메일 송신은 비동기적으로 처리해 유저의 요청에 대한 응답이 밀리지는 않지만, 문제가 될 여지가 있었다.

  바로 한 유저가 다른 유저가 있는 방에 입장했다 퇴장했다를 수없이 반복하는 경우였다. 이런 경우에는 메일을 보내주는 ThreadPool-Scheduler의 대기열에 메일이 한없이 쌓이게 되고, 다른 유저들이 받아봐야 할 알림이 계속해서 밀리고 늦게 도착하게 되는 문제가 있었다. 그래서 상대가 존재하는 슬롯에서 나가는 경우, 1분 동안은 다른 방에 들어갈 수 없도록 페널티를 부여했다. 이때 페널티는 레디스에 1분간 정보를 올려놓는 방식으로 구현했다.

 

매칭 등록 시퀀스

  매칭 등록에서도 postman 등 프론트를 거치지 않은 요청에 대한 에러 처리가 우선이었다. close된 슬롯에 입장하려는 요청이나, 이미 슬롯에 들어가 있는 유저의 요청, 또는 위에서 받은 1분 페널티 대상자일 때는 에러를 반환한다.

  이 예외처리를 지나게 되면, 먼저 유저의 현재 매치 정보를 기록하는 CurrentMatch가 추가된다. 이후 슬롯에 유저를 등록하는 과정에서, 점수(PPP) 정보를 슬롯과, 슬롯 내에 존재하는 팀에 갱신해준다. 슬롯의 점수는 새로 들어오는 유저가 슬롯 전체 평균과 기준치 이상 벗어나는 경우를 거르기 위해서, 팀의 점수는 점수차가 기준치 이상인 유저와 한 팀이 될 수 없도록 하기 위해 만들었고, 복식을 위해 구현한 부분이다.

  이런 절차를 거친 후에 다른 유저들의 currentMatch 정보를 수정해야한다. 슬롯이 가득 찬 경우 isMatched 변수의 값을 true로 바꿔준다. 그리고 매치가 성사되었다는 알림을 메일과 함께 보낸다. 유저의 매치 등록은 대략 이런 과정으로 이루어진다.

 

게임 결과 입력 시퀀스

  다음은 우리 서비스에서 내가 생각하기에 가장 아쉬운 부분이다. 게임 결과 입력 시퀀스인데, 현재 어떤지, 어떤 식으로 바꾸고 싶은지에 대해서 적어보았다.

  현재는 게임에 참여한 유저 중 한 명만 스코어를 입력해도 된다. 42 커뮤니티라는 특성에 기반해 신뢰성이 보장된다고 생각하여 이런 방식으로 구현했다. 유저 중 한 명이 입력하면 다른 한 명은 입력하지 않아도 되는데, 게임이 끝나고 대면한 상황에서 점수를 입력하기에 큰 문제가 없을 것이라 생각했다.

  실제로 서비스 과정에서 점수 입력으로 다툼이 생겼다거나 하는 등의 문제는 없었다. 다만 아쉬운 점은 더 나은 방법이 있었을 것이란 부분이다. 그리고 문제가 없었던 부분이 우리가 운이 좋았고 사람들이 우리의 예상대로 행동해주었기 때문이라는 점이다.

문제가 되는 현재의 시퀀스는 이렇다. 스코어가 유효한지 검사해 유효하지 않다면 에러를 반환한다. 유효하다면, 이미 점수가 입력된 게임인지, 혹은 아직 게임이 시작되지 않았고 대기 중인 게임인지 확인한다.

  이미 점수가 입력된 게임인지 검사하는 이유는 두 가지이다. 예저녁에 끝나고 결과도 입력한 게임에 대해 다시 시도하는 경우. 아니면 상대가 입력을 마친 경우에는 내 입력이 필요 없기 때문이다.

  입력을 받고 예외처리를 지나고 나면 CurrentMatch를 삭제한다. 현재 유저가 매치를 가지고 있지 않음을 의미하기 위한 작업인데, DB에서 이 정보를 아예 삭제한 것은 아쉬움으로 남는다. 나중에 통계를 확인할 때 문제가 있었기 때문이다. 이 부분은 각 정보가 유효한지 표시하는 Bool 변수를 추가하거나, 삭제된 매치를 이력을 남기는 테이블로 옮겨주거나 하는 등으로 리팩토링 할 예정이다.

이후 게임 결과를 저장하고 유저 정보도 그에 맞춰 바꿔주면 시퀀스가 끝난다.

  한 명만 입력해도 된다는 게 아쉬운 부분이라, 두 유저의 입력을 다 받고 두 입력값이 다르다면 양 측에 재요청을, 같다면 결과 저장을 하는 방향으로 로직을 바꾸고 싶다. 다만 이 과정에서 소켓통신을 하지 않는다면 재요청을 하기 위해 유저가 새로고침을 하는 등의 작업이 필요할텐데, 사용성이 좋은 방법을 찾아나가는 것이 해결할 과제이다.

 

 

  시퀀스 다이어그램에 대한 글이 끝났습니다. 열심히 적어는 보았지만 저희 서비스가 어떤 식으로 구성되어있는지 제대로 설명하지 못한 것 같습니다. 슬롯이라던가, 게임이라던가 팀이라던가에 대한 명확한 정의를 보여드리지 않고 썼기 때문입니다. 그런 것을 자세히 밝히지 않은 이유는, 제가 전달하고 싶은 게 저희가 구현한 로직이라기보다는 어떤 예외사항들을 예상하고 대처했는지에 대해 보여드리고 싶었기 때문입니다. 마지막 게임 결과 입력 시퀀스도, 앞서 목표했던 대로 저희가 부족했던 점과 나아가고 싶은 방향을 중점적으로 써보려고 노력했습니다.

'42GG > 설계' 카테고리의 다른 글

[42GG] DB설계 수정기  (0) 2022.08.02
Comments