[Devcourse] - 최종 프로젝트 ∘ Devcourse 회고

청주는사과아님·2024년 12월 16일
0

side-story

목록 보기
3/7
post-thumbnail

2024-07-15 - 2024-12-13 101 일.

지난 주 금요일을 마지막으로 길면 길었던 데브코스 과정을 마무리 하였습니다.
끝나고 돌아보니 만족스러웠던 부분, 아쉬웠던 부분 모두 또렷이 기억나네요.

이번 포스팅은 그 모두를 기억하기 위해 마지막으로 진행했던 프로젝트와 데브코스 전체를 돌아보는 글을 적고자 합니다.


📌 최종 프로젝트

저희 팀의 프로젝트 주제는 포트폴리오 공유 & 자기계발 구인 플랫폼 이었습니다.
사용자는 자신의 포트폴리오를 게시해 다른 사용자로부터 피드백을 받을 수 있고, 직종에 맞는 자기계발 구인 게시글을 올려 네트워킹을 도모하는 플랫폼 이었습니다.

저는 서비스에서 다음 역할을 담당해 프로젝트를 진행하였습니다.

  • CI 파이프라인 구축
  • OAuth 2.0 을 이용한 회원가입 • 로그인
  • JWT 기반 사용자 인증
  • User 도메인 기능
  • MDC 를 이용한 요청 도메인별 로그 분리 저장

이 중 특히 공을 들인 부분은 OAuth 2.0 • JWT 통합MDC 로그 분리 였습니다.


OAuth 2.0 • JWT 통합

OAuth 를 이용한 소셜 로그인은 남들이 자주 사용하는 것만 봐왔지, 제가 직접 만들어 사용하는 것은 처음이었습니다.

그래서 OAuth 의 전반적인 이해가 필요하였고 다음 영상을 참고해 공부하였습니다.


[개발자 유미] - 스프링 OAuth2 클라이언트 JWT

이를 통해 소셜 로그인 자체는 성공적으로 구현하였으나, 로그인 후 자체 JWT 를 발급하는 부분이 문제되었습니다. OAuth 의 경우 프론트에서 href 로 인증을 진행하고 성공시 특정 urlredirect 되기 때문입니다.

이를 해결하기 위해 OAuth 로그인 성공 시 자체 임시 토큰을 url 에 넣어 토큰 발급 Endpointredirect 되는 방안을 고안했습니다.

  • Source code

    @Slf4j
    @Component
    public class OAuth2LoginSuccessHandler
            extends SimpleUrlAuthenticationSuccessHandler {
    
        private final JwtUtils jwtUtils;
        private final String successRedirectUri;
    
        /**
         * 로그인 성공해서 임시 토큰으로 진짜 토큰들 발급하는 {@code /token/issue?token=} API 로 redirect
         */
        @Override
        public void onAuthenticationSuccess(
                HttpServletRequest request, 
                HttpServletResponse response, 
                Authentication authentication
        ) throws IOException, ServletException {
    
            CustomOAuth2User customUserDetail 
                    = (CustomOAuth2User) authentication.getPrincipal();
            String temporaryToken 
                    = jwtUtils.createTemporaryToken(customUserDetail.getUser());
    
            log.info("Temporary token issued in CustomLoginSuccessHandler - token: {}", temporaryToken);
    
            // 임시 토큰으로 access, refresh 토큰 발급하는 endpoint 로 redirect
            // local profile 은 back 으로, deploy 는 프론트 주소로
            response.sendRedirect(successRedirectUri + "?token=" + temporaryToken);
        }
    }

이를 통해 OAuth 인증의 강점은 살리면서 JWT 통합을 성공적으로 완료할 수 있었습니다.


MDC 로그 분리

저희 팀은 Github ActionDocker 를 이용한 CD 파이프라인을 구추하였습니다.
그런데 실제 배포해 프론트와 연결하다 보니 다양한 에러가 발생하였고, 그 에러를 추적하는데 어려움을 겪었습니다.

Docker 로 서버를 올렸기 때문에 docker logs 명령어로 로그를 직접 볼 수 밖에 없기 때문이었습니다.

그래서 이를 개선하고자 Mapped Diagnostic Context 를 이용한 요청 도메인별 로그 분리 를 진행하였습니다.


배포 서버에 도메인별 로그가 저장된 모습

  • Source Code

    /**
     * {@code Mapped Diagnostic Context} 이용한 도메인별 로그 저장(은 아니긴 한데 비슷한) {@code filter}
     */
    @Slf4j
    @Component
    @Order(Ordered.HIGHEST_PRECEDENCE)  // 이러면 filter 중에서도 가장 빠른? 필터로 되는듯. 신기하네
    public class MDCLoggingFilter extends OncePerRequestFilter {
    
        @Override
        protected void doFilterInternal(
                HttpServletRequest request,
                HttpServletResponse response,
                FilterChain filterChain
        ) throws ServletException, IOException {
    
            // 요청별 랜덤 uuid 생성 & 저장
            String requestUUID = UUID.randomUUID().toString();
            request.setAttribute("custom-request-uuid", requestUUID);
            log.info("REQUEST {} \"{}\" earned custom UUID : {}",
                    request.getMethod(), request.getRequestURI(), requestUUID);
    
            try {
    
                this.configureLogDirViaUri(request);
    
                this.logNewLines();
                log.info("============== REQUEST [{}] START ==============", requestUUID);
                filterChain.doFilter(request, response);
    
            } finally {
                log.info("============== REQUEST [{}] END ==============", requestUUID);
                this.logNewLines();
    
                MDC.clear();
            }
        }
    
        // uri 별 도메인 파악해서 MDC key 넣어주기
        private void configureLogDirViaUri(HttpServletRequest request) {
            String uri = request.getRequestURI();
            DomainType domainType = DomainType.of(uri);
    
            MDC.put("DOMAIN_LOG_DIR", domainType.getDomainLogDir());
    
            log.info("Domain logging directory has been set to : [{}]", domainType.getDomainLogDir());
        }
    
        private void logNewLines() {
            log.info("");
            log.info("");
        }
    }

백엔드 서버로 요청이 들어올 경우 요청별 고유한 UUID 를 생성 • 저장해 요청의 시작과 끝을 확실히 파악할 수 있도록 구성하였습니다.
또한 요청 처리 중 에러가 발생하면 따로 exception 폴더에 집계하도록 하여 에러 추적에 용이하도록 Logback 을 구성하였습니다.


배포 로그에서 요청 UUID 를 통해 에러를 추적하는 모습

이를 통해 원활한 에러 추적이 가능하였고 프론트와의 연결을 마무리할 수 있었습니다.


💭 최종 프로젝트 회고

저는 스스로 최종 프로젝트를 통해 배운 점이 정말 많다고 생각합니다.
OAuth 2.0, Logback 등 들어보기만 하던 내용들을 직접 구현하였으며, 앞서 언급하진 않았지만 QueryDSL 을 이용한 NoOffset 조회, Spring Security 구성 등을 진행하였기 때문입니다.

비록 최종 프로젝트에서 획기적이고 독특한 기능을 담당한 것은 아니지만, 스스로 성장하고 있음을 확신하는 경험이었습니다.


📖 데브코스 회고

돌이켜 보면 6 개월 전 자신이 얼마나 무모했는지 알 수 있었습니다.

백엔드의 도 모르던 초심자 주제에. 혼자서 이 모든 것을 독학하려 했다니. 정말 말도 안되는 하룻강아지의 객기였다고 생각합니다. 만약 데브코스에 참여하지 않았다면 절대로 지금의 자신 이 되지 않았으리라 확신합니다.

하지만 그렇다고 "데브코스" 그 자체를 찬양할 생각은 없습니다.
수강하며 불만족스러운 부분이 명확하게 존재했었고, 무엇보다 학습 의 본질은 자기 자신에게서 찾아야 한다 생각하기 때문입니다.

분명히 데브코스를 수강하며 성장한 것은 맞지만, 데브코스 만으로 성장한 것은 아니라 생각합니다.
데브코스가 학습 에 도움을 준 것은 맞지만, 같이 성장하는 동료, 강사님의 피드백, 그리고 스스로 학습하고자 하는 의지 가 없었다면, 절대로 이만큼 성장할 수 없었다 단언할 수 있습니다.

그래서 저는 데브코스좋은 부트캠프 라 말하고 싶지 않고, 백엔드를 향한 좋은 첫걸음 이라 말하고 싶습니다.


⏳ 앞으로의 길

데브코스를 통해 스스로 부족한 부분이 정말 많다고 느꼈습니다.

확실히 비전공자와 전공자의 4 년 차이는 무시할 수 없음을 느꼈고, 백엔드 이론과 기술, 그 모든 부분에서 뒤쳐져 있음을 체감하였습니다.

하지만 이럴 때 일수록 다시 기본으로 돌아가야 된다고 생각합니다.
Kafka, K8s 등 취업에 매력적인 기술들 이지만 이를 자기것으로 만들기 위해선 튼튼한 기초가 필요하다 생각합니다.

그래서 이제는 온전히 독학하는 시간을 갖고자 합니다. Design Pattern 부터 시작해 Spring Boot, Security, RDBMS 까지 기초적이지만 핵심적인 내용을 공부하고자 합니다.
물론 장담할 수 없을 정도로 오랜 시간이 걸리겠지만 그래야 속이 편한걸 어쩌겠습니까.
하여간 이 물리학 성격은 죽지를 않네요.

그럼 언젠가 더 성장한 자신을 기원하며 글을 마치도록 하겠습니다.


profile
나 같은게... 취준?!

0개의 댓글