TIL

[240104] 심화 프로젝트 마무리 :: 트러블 슈팅

진진리 2024. 1. 4. 20:54
728x90
심화 프로젝트 발표를 준비하면서 팀원들이 경험한 트러블 슈팅에 대해서 정리해보고자 한다.

 

카테고리 및 카드 정렬 문제

칸반보드 협업 툴인 Trello와 비슷한 칸반보드 서비스를 구현하는 프로젝트이기 때문에 카드와 카테고리를 드래그해서 움직이면 해당 카드와 카테고리의 순서가 바뀌게 된다.
이를 구현하는 과정에서 어떤 방법을 사용하는 것이 좋은지에 대한 문제에 부딪히게 되었다.
  • 제안된 방식들
    1. 컬럼 테이블의 필드로 json으로 카드 순서를 저장 ex) [1,2,3,4,5] -> [1,2,4,3,5]
    2. 카드 테이블의 필드로 전, 후의 카드id를 저장 - 최대 4번 요청
    3. 순서 테이블을 만들어서 이용 (1, 2번을 혼합)
    4. 변경 전후의 seq 값을 더해서 2로 나눔

일주일이라는 주어진 시간 안에 구현해야 하는 기능이 많다보니 프로젝트가 빠르게 진행되었다.

그러다보니 더 많은 방법을 생각해보기에는 시간이 부족했다.

요청 쿼리의 갯수와 구현 난이도를 고려해보았을 때 4번 방법이 현재로서는 가장 좋은 방법으로 보였고 이 방법으로 구현하게 되었다.

 

하지만 double 값의 유효자릿수로 인해 정렬 시마다 평균값을 구하다보면 정합성 문제가 발생할 수 있다고 생각이 들어서 이를 보완하기 위해 스케줄러를 도입하였다.

스케줄러를 통해 매일 한 번씩 카테고리와 카드의 순서를 한 번에 새로 값을 대입하여 주게 된다.

@Service
@EnableScheduling
@RequiredArgsConstructor
public class CardSchedulingServiceImpl implements CardSchedulingService {
    private final CardRepository cardRepository;
    private final double ADD_SEQUENCE = 1.0;

    @Scheduled(cron = "0 0 0 * * ?")
    @Transactional
    public void resetSequence() {
        List<Card> cards = cardRepository.findByOrderByCategoryCategoryIdAscSequenceAsc();
        if (CollectionUtils.isEmpty(cards)) {
            return;
        }

        Long prevCategoryId = cards.get(0).getCategory().getCategoryId();
        double sequence = 0.0;
        List<Card> newCards = new ArrayList<>();
        for (Card card : cards) {
            sequence = getNewSequence(sequence, prevCategoryId, card.getCategory().getCategoryId());
            newCards.add(
                    Card.builder()
                            .cardId(card.getCardId())
                            .name(card.getName())
                            .description(card.getDescription())
                            .fileUrl(card.getFileUrl())
                            .sequence(sequence)
                            .deadline(card.getDeadline())
                            .category(card.getCategory())
                            .build());
            prevCategoryId = card.getCategory().getCategoryId();
        }
        cardRepository.saveAll(newCards);
    }

    private double getNewSequence(double sequence, Long prevCategoryId, Long nowCategoryId) {
        if (!prevCategoryId.equals(nowCategoryId)) {
            return ADD_SEQUENCE;
        }
        return sequence + ADD_SEQUENCE;
    }
}

 

 

Mail 링크 인증 방식의 보안성 고려

이번 프로젝트에서는 회원가입 시의 이메일 인증과 멤버 초대 시 초대 메일 발송에서 mail을 적용하였다.
이때 메일로 전송하는 링크에 메일 주소와 인증 코드를 담아서 전송하였는데 이에 대해 팀원분께서 하신 고민을 공유해주셨다.
  • 메일 전송 시, 사용자의 email을 노출시키는 것이 보안상 취약하다고 판단하여 링크에서 제외하는 방식을 고려하였으나, email을 제외하고 작성하니 하이퍼링크가 생성되지 않는 문제가 발생하였음.
  • 알아보니, naver나 google과 같은 도메인마다 이를 링크로 인식하는 방식이 달라 하이퍼링크가 생성되지 않는 문제가 있다고 함.
  • a 태그로 직접 하이퍼링크를 만들어주는 것이 가장 좋은 방식이라고 생각하였음

 

JPA query 메서드명 관련 오류 발생

User entity에는 소셜 로그인을 위한 oAuthId라는 필드가 존재하는데 카멜케이스를 적용하다보니 DB에 칼럼명이 o_auth_id로 생성된다.

그러나 JPA 쿼리 메서드를 다음과 같이 findByOAuthId로 작성할 때 쿼리의 조건이 oauth_id = ? 로 나가게 된다.

그러다보니 에러가 발생하게 되었다.

 

팀원은 이에 대한 해결 방법으로 두 가지를 제안하였다.

  1. 쿼리 메소드명 변경 : User findByoAuthId(String oAuthId);
  2. 필드명 변경 : oauthId

팀원분이 작성하신 TIL : https://github.com/junxtar/TIL/blob/main/Problem/jpa-query.md

 

 

Redis repository test 빌드 에러 문제

이번에 이메일 인증 부분을 구현하면서 5분이라는 시간 동안 이메일 인증 여부가 유효하도록 설정하기 위해 Redis를 사용하였다.
따라서 Spring에서 Redis를 테스트하고자 하였는데 Embedded Redis를 설정하여 테스트 환경을 만들었다.
로컬에서는 잘 작동하였으나 develop 브랜치와 합치는 과정에서 빌드 에러가 발생했고 이는 시간이 부족하다보니 해결하지 못하였다.

 

  • 참고한 블로그

https://devoong2.tistory.com/entry/Springboot-Redis-%ED%85%8C%EC%8A%A4%ED%8A%B8-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-Embedded-Redis-TestContainer

 

스프링 Redis 테스트 환경 구축하기 (Embedded Redis, TestContainer)

예제 및 테스트 코드는 github 에서 확인 가능합니다. Spring 에서 Redis를 테스트 하는 방법 이번엔 Spring 에서 Redis를 테스트 하는 방법에 대해 알아보려 합니다. Embedded Redis Test-Containers Redis를 테스트

devoong2.tistory.com