지속 성장 가능한 코드: import문도 코드이다.
·
프로젝트/COTATO.KR
지속 성장 가능한 코드: import도 코드어느 덧 9기가 끝나가며 자신있게 출시(?)한 프로젝트를 운영한지도 6개월이 되어간다.그냥 박치기로 시작했던 프로젝트를 운영까지 하고 있으니 리팩토링을 하거나 새로운 기능을 짤 때 ‘변경한 코드의 파급력’을 고려하지 않을 수가 없다.그렇다고 확장을 하지 않을수도 없는데, 크고 작은 기능이 추가되며 하나의 클래스에 메서드가 증가하고 의존성이 더해지며 코드가 복잡해지는데 기수가 끝나가는 하나의 전환점인 지금 아래와 같은 고민이 생긴다. 지금 우리의 프로젝트는 새로운 개발자가 와서 읽기 좋은 구조인가? 언젠가는 누군가가, 적어도 ‘홍보’ 관련 도메인은 가져가야하는데 이게 맞나 싶은 포인트가 생겨 고민이 드는 요즘이다.이게 맞나?import 문에 와일드 카드 사용을 하..
Refresh Token Rotation
·
프로젝트/COTATO.KR
일반적으로 인증과 인가를 구현할 때, AccessToken과 RefreshToken을 사용한다. 우리 프로젝트에서도 둘을 활용한 인증을 구현했는데 이번 글에선, COTATO 프로젝트의 인증, 인가를 구현하며 고민한 RefreshToken 탈취 문제와 관련된 내용을 정리하겠다.배경 지식해당 글을 위해선 인증과 인가, 토큰 인증 방식에 대한 이해가 필요한데 공부가 급하다면 우선은 아래와 같은 내용으로 이해하자. 인증 : 너가 너가 맞는지 확인하는 것인가: 너가 자격이 있는지 확인하는 것토큰: 서버의 부담을 덜기 위해, 사용자에게 입장권을 주고 입장권이 적절한지 확인하는 방식세션: 인증된 사용자의 목록을 서버에서 관리해 인증하는 방식AccessTokenAccessToken이란, 일반적인 웹 어플리케이션에서 사..
선착순 퀴즈 프로젝트 V1 회고
·
프로젝트/COTATO.KR
지난해 10월부터 진행한 선착순 CS퀴즈 프로젝트의 버전1이 마무리되고 이제 버전2를 운영 중이다.버전2에선 해당 사이트를 동아리 홍보 사이트, 운영 과정에서 부원 필요 기능 추가 등을 목적으로 확장 중에 있는데 보다 나은 버전2 개발 진행을 위해 프로젝트를 진행하며 느낀점, 리팩토링 과정에서 느낀 아쉬움과 운영 과정에서 필요를 느낀 내용에 대해 KPT 회고를 해보고자 한다.선착순 퀴즈 프로젝트란?사전에 등록된 문제에 대해 관리자가 실시간으로 문제 풀이가 진행된다. 이 중 가장 빠른 정답자를 득점자로 인정하고 이를 통해 우승자를 결정하는 프로젝트이다.기획 의도7, 8기 교육팀으로 활동하며 교육을 진행하고 CS퀴즈를 진행했다. 기존 기수엔 카카오톡 채팅방을 통해 아래와 같이 가장 빠른 정답자를 득점자로 인..
선착순 로직 개선기 (2) - Redis 분산락
·
프로젝트/COTATO.KR
지난 글에선, 낙관적 락을 사용하기, 테이블 구조 변경을 통해 선착순 제출 로직의 동시성 문제를 해결했다. 이 글에선 테이블 구조를 별도로 변경하지 않고 Redis의 분산락을 통해 문제를 해결해본 과정을 적을 예정이다.Redis를 통한 동시성 해결동시성 문제가 발생하는, 락이 필요한 부분은 ‘정답 제출’하는 득점자를 생성하는 과정이다.제출한 요청 중 ‘정답’으로 판별된 내용을 기준으로만 득점자를 파악하면 된다.따라서, 아래 득점자 확인 및 등록 로직에 대해서만 lock을 적용하면 된다.득점자 존재 여부를 확인한다.존재한다면, 본인이 더 빠른 요청일 경우, 존재하지 않으면, 본인을 득점자로 생성한다.Lettuce 분산락redis의 setnx 명령어를 통해 분산락을 구현할 수 있다.. 특정 키에 대한 va..
선착순 로직 개선기 (1) - 낙관적 락 활용
·
프로젝트/COTATO.KR
개요CS퀴즈 프로젝트의 핵심 로직은 ‘선착순’으로 가장 빠른 정답을 제출한 득점자를 확인하는 것이다.따라서, 여러 정답자 중에 가장 빠른 정답자의 득점 기록을 바탕으로 득점자를 생성해야한다.문제풀이의 기본적인 로직은 아래와 같다.관리자가 문제 풀이를 허용한다.부원들이 문제 풀이 신호를 확인한다.정답을 제출한다.정답 요청이라면, 득점자가 존재하는지 확인한다.득점자가 존재하지 않는다면, 해당 요청을 기반으로 득점자를 생성한다.하지만, 일반적인 로직을 통한 구현은 동시성 문제를 겪기 쉬운데 이 글에선 여기서 발생하는 동시성 문제와 해결책을 담은 예제를 통해 찾아보도록 하겠다.우선, 위에서 말한 로직을 간단하게 구현하면 아래와 같다.@Transactionalpublic ReplyResponse submitAns..
Enum 그룹화를 통한 MemberRole 관리
·
프로젝트/COTATO.KR
현재 CS 퀴즈 프로젝트에서는 회원 역할을 통해 권한을 부여하고 있다.Ver1에선 대표적으로 아래와 같이 권한을 구분한다.현재 활동중인 부원(MEMBER) : 문제 풀이 가능교육팀원(EDUCATION) : 문제 업로드 및 풀이 진행, 결과 확인 가능운영진(ADMIN): 부원 관리 기능 및 모든 기능 가능//MemberRole.javaREFUSED("ROLE_REFUSED"),GENERAL("ROLE_GENERAL"),MEMBER("ROLE_MEMBER"),OLD_MEMBER("ROLE_OM"),ADMIN("ROLE_ADMIN"),EDUCATION("ROLE_EDUCATION");이외에도 현재 활동 중이지 않은 OM, 거절된 사용자, 승인 대기중인 부원 등 총 6가지의 역할이 존재한다.지금까진 특정 API..
정답 제출 API 멱등성 처리하기
·
프로젝트/COTATO.KR
앞선 글에서 HTTP 멱등성과 API의 멱등성을 구현하는 과정에 대한 내용을 정리했다.이번 글에서는 현재 Cotato 정규 세션 문제 풀이에서 사용하는 로직인 ‘정답 제출’ API에 멱등성 처리를 하는 과정을 글로 정리하겠다.정답 제출 API의 멱등성 처리 필요성정답 제출 API의 서비스 로직을 간단하게 정리하면 아래와 같다.정답이 아니면 제출 기록을 생성 후 저장한다.정답인 경우이미 득점처리가 되었는지 확인한다.득점자보다 해당 제출 기록이 더 빠르면 득점자로 대체한다.득점자보다 느리면 단순히 기록을 저장한다.이때 핵심은 정답 처리가 된 요청은 하나만 생성되어야한다는 점이다.하지만, 우리는 선착순으로 득점자를 정한다. 그렇기 때문에 사람들은 풀이가 허용되는 시점 이전에 무수한 요청을 보내는데 요청이 처리..
멱등성을 통한 정답 제출 API 중복 요청 방지 (이론)
·
프로젝트/COTATO.KR
지난 4월 27일 토스 서버 개발자 챌린지를 보며 결제 요청 타임아웃 처리에 관한 서술형 문제를 봤다. 💡 결제 요청간에 타임 아웃이 발생했다. 해당 요청이 성공했는지 실패했는지 사용자는 알지 못하지만, 결제 요청이 2번되어서는, 안되어서는 안된다. 어떻게 이 문제를 해결할 수 있을까?나는 이 문제에 답을 하지 못했는데, 이후 오픈카톡방의 후기를 보니 ‘멱등성’을 통해 결제 요청 처리를 한다는 이야기가 나왔고 관련된 검색을 하던 중 토스의 멱등성에 관한 글을 읽게 되어 멱등성에 대해 공부하게 되었다.읽고보니 비슷한 상황으로 인해 우리 코테이토 문제 풀이 요청 또한 결제 과정과 유사한 부분이 많다고 느껴졌고 멱등성 처리를 할 필요가 있다는 생각이 들었다.따라서, 오늘은 멱등성에 관한 내용을 정리하고, 이..
퀴즈 객체 양방향 매핑 없애기
·
프로젝트/COTATO.KR
현재 퀴즈 ←→ 선지 , 퀴즈 ←→ 주관식 정답에선 양방향 매핑이 되고 있다. MultipleQuiz.java: Choice를 List로 매핑하고 있다. @Entity @DynamicInsert @NoArgsConstructor(access = AccessLevel.PROTECTED) @DiscriminatorValue(value = "MultipleQuiz") @Getter public class MultipleQuiz extends Quiz { @OneToMany(mappedBy = "multipleQuiz", cascade = CascadeType.ALL) private List choices = new ArrayList(); @Builder public MultipleQuiz(int number,..
여러 객체를 삭제할 때 쿼리 줄이기
·
프로젝트/COTATO.KR
현재 문제 업로드를 할 때 임시저장 기능 구현을 아래와 같이 하고 있는데, 임시저장과 최종 업로드 하는 기능을 같은 API로 사용하고 있다.사용자가 저장하기 버튼을 누르면 아래와 같은 작업이 수행된다.현재 해당 교육에 업로드된 모든 퀴즈를 삭제한다.요청 온 퀴즈를 다시 업로드한다.문제 상황현재 로직@Transactionalpublic void createQuizzes(Long educationId, CreateQuizzesRequest request) { Education findEducation = findEducationById(educationId); checkQuizBefore(findEducation); validateDuplicateNumber(request); q..
유쓰응
'프로젝트' 카테고리의 글 목록