이번에 개발이 진행중이고 곧 스토어에 출시할 어플을 만드는 사이드 프로젝트에 참여하게 됐다.
여태까지 프로젝트를 진행했을 때 서비스 구상, 설계까지 초기부터 진행해왔었기 때문에 기존에 진행되던 프로젝트에 참여해보는 것은 처음이다.
어떻게 전체 구조를 파악하고 초기에 중요한 부분들을 어떻게 파악할지 알아보자.
첫 시작 - 프로젝트 온보딩
전체적으로 Notion, Git, Figma 초대를 받았다.
그리고 우선 도커파일이 없는 것을 보아 개발환경은 로컬로 띄우면 되겠다는 생각이 들었고, 리포지토리 클론을 하고 빌드를 바로 해보았다. 빌드를 할 때 부터 JDK 버전 충돌이 일어나 알맞은 JDK 버전을 설치했다.
이후 프로젝트의 구조와 개발 흐름을 파악하기 위해 Notion 문서부터 확인하기로 했다.
Notion에서 확인할 부분
기본적으로 코드 컨벤션, 커밋 컨벤션 등을 확인할 수 있었다.
그리고 EC2, DB 인스턴스 정보, S3 버킷 URL, 젠킨스 URL, API 로그 확인용 그라파나 서버, Swagger를 확인할 수 있었다.
그리고 .env 파일의 내용을 확인할 수 있다.
이 정보들을 활용해서 개발환경을 세팅해보자.
개발환경 세팅
아직 초기 MVP 단계라 복잡하게 되어있는 부분들이 없어 단순하게 Docker로 MariaDB를 띄우고 해당 DB에 주어진 DDL을 실행하면 되는 간단한 구조였다.
Jenkins
이 프로젝트에는 Jenkins를 통해 dev 환경 배포를 진행중이다.
로컬 개발 환경을 세팅하면서 Jenkins 사용 방식도 익혀보자.
URL, ID, PW가 Notion에 정리되어 있었고 접속했다.
Jenkins가 하는 일
JenkinsFile을 통해 Jenkins로 현재 무엇을 하고 있는지 파악해보았다.
- .env 파일 생성
- 보안 키 파일 복사 및 권한 설정
- Gradle 빌드, EC2 서버 내 디렉토리에 JAR 복사 후 서비스 재시작
- 이전 JAR 백업
- 성공 시 Discord 알림, 실패 시 롤백
리팩토링
회원 관련 도메인에서 리팩토링 요청을 받았다.
코드를 보고 있으니 이해가 가지 않는 부분들이 많았다. 내 생각이 틀릴 수도 있어 일단 리팩토링을 진행하고 코드리뷰를 받기로 했다.
- 기존 구조의 문제점
- Controller에 과도한 책임이 있다.
- OAuth2 리다이렉트 URI 핸들링부터 쿠키 세팅, URL 빌드까지 모두 Controller가 맡고 있어 가독성이 좋지 않다.
- 쿠키 생성 로직이 중복되 있다.
- Spring Security를 제대로 활용하지 못하고 있다. 로그인 성공 후 행동은 successHandler가, 토큰 검사는 OncePerRequestFilter가 맡아야 하는데 이를 직접 Controller에서 처리하고 있다.
- /api/v1/auth와 그 외 요청에 대해 서로 다른 SecurityFilterChain이 분리되어 있어 CORS, 예외 처리 정책이 꼬일 가능성이 있다.
- 핵심 로직이 Controller 메서드 내부에 모두 들어있어 단위 테스트가 복잡하다.
- GrantedTokenInfo를 반환해주고 있는데, 토큰이 자바스크립트 영역에 노출되어 탈취 위험이 커짐
- 이를 위해 쿠키에 세팅하는 것을 이용하면 Axios 인터셉터 사용해서 구현하는 것은 프론트측에서 불가능하긴 함.
- 컨트롤러에 담겨있는 핵심 로직들을 SuccessHandler로 옮기고, 기존 API는 Swagger 용도로 남긴다.
이러한 문제들이 있어 내가 기존에 작성했던 소셜 로그인 구현을 바탕으로 Code Grant 기반 구조로 변경하고, 필요한 부분들을 커스터마이징 해나갔다.
- 새 구조의 장점
- Controller는 순수하게 엔드포인트 정의 + DTO <-> HTTP만.
- SuccessHandler는 로그인 성공 후 작업을 정의
- JwtFilter, OncePerRequestFilter는 매 요청 토큰 검사
- OAuth2 로그인 로직은 Spring Security 확장점에 위임한다. 컨트롤러가 이렇게 길 필요 없다.
- 토큰 리프레시는 별도 컨트롤러에서 최소 로직만 수행한다.
- 단일 SecurityConfig로 한 곳에서 관리할 수 있도록 한다.
- 소셜 로그인 벤더 추가, 자체 로그인 도입, 권한 정책 변경 시 Security 레이어만 건드리면 된다.
- 쿠키 토큰 관련 유틸도 중앙화된 Util 클래스로 통일할 수 있다.
- 각 필터, 핸들러 단위 유닛 테스트가 가능하고 컨트롤러는 DTO 직렬화/역직렬화만 검증하면 된다.
기존 유지보수가 어렵고 복잡했던 코드를 간단히했고, 만약 새 소셜 기능이 붙는다면 기능 구현에 많은 시간이 들었을 부분에 대해 수정을 이어나갔다.
stater를 사용해 oauth2Login으로 자동처리하면 코드량이 대폭 감소하고 Spring Security의 버전이 오를때 알아서 따라갈 수 있다.
결과
내가 수정한 코드에도 문제가 있었다. 큰 문제는 아니었지만 생각해보지 못한 부분들이었다.
유지보수성이나 코드 품질에 대해 생각해왔었는데 아직 부족한 것 같다. 코드 품질 향상을 위해서는 여러 사람들의 코드를 보고 내 코드를 공유하는 것이 필요하다고 느꼈다.
그리고 기존 코드에서도 내가 잘 알지 못했던 새로운 방법들이 있었고 차차 알아나가야겠다고 느겼다.