미리보기
기본 정보
프로젝트의 성능을 향상 시킬 방법이 무엇인지, 내가 사용하고 있는 방식이 최선일지, 내 코드는 동료들이 읽기에 편한지에 대한 생각을 많이 합니다.
경력
주식회사 유니온클래스
팀원 | 개발팀 | 재직 중
2024.02. ~ 재직 중 (9개월)
신규 서비스 런칭에서 기획, 설계, 인프라, 백엔드 개발을 담당하고 있습니다.
현재 '반려동물 제목 생성 Shorts-Image Platform 서비스' 를 개발 및 운영중입니다.
내가 작성한 코드를 확실하게 이해하여 언제든 활용할 수 있도록 하는 것과, 누구든지 내 코드를 읽고 빠르게 이해할 수 있도록 가독성에 초점을 두고 개발합니다.
개발중에 발생한 트러블 슈팅을 블로그에 기록하고 팀원들과 공유하는 것을 즐깁니다.
내가 맡은 서비스에서 어떤 방법이 더 좋은 방법일지 주도적으로 고민하고 개선합니다.
기술 스택
Spring Boot, Java, MySQL, querydsl, spring-jpa
프로젝트
반려동물 제목 추천 서비스 Untitled
주식회사 유니온클래스
2024.02. ~ 진행 중
유저가 업로드한 반려동물 사진에 대해 생성형 AI가 알맞은 제목을 생성해주는 Shorts-Image Platform입니다. (https://untitled-shorts.com)
담당 개발 사항
기획, ERD설계, Shorts 도메인 API 개발, 전체 도메인 유지/보수 및 필요한 API 개발, Infra 및 CI/CD 구축
도메인간 의존성 분리를 위한 Spring Event & Facade Pattern 도입
기존 레이어드 아키텍처에서 상위 모듈이 하위 모듈을 의존하는 문제를 해결하기 위해 DIP를 적용하여 의존성 역전
의존성 역전을 통해 기존의 통합 테스트를 단위 테스트로 변경하여 테스트 속도 향상 (대략 62.85% 향상)
GitHub Actions를 사용하여 CI/CD 구현
무분별한 외부 API 사용을 제한하기 위해 Rate Limiter 도입
성능 향상 및 모바일 화면 최적화를 위해, 정렬된 Cursor 기반 페이지네이션 사용
다형성을 활용하여 재사용성 높은 코드 작성
LogBack을 사용하여 Logging 처리
베타 버전 배포 완료
Untitled는 제가 진행했던 프로젝트 중 처음으로 실제 사용자에게 배포하는 것을 목표로 삼은 서비스입니다. 따라서 네다섯 명의 팀 동료가 아닌 불특정 다수를 상대할 때, 견고한 서버를 만들기 위해 얼마나 많은 것을 생각해야 하는지를 깨닫는 경험이 되었습니다.
무분별한 API 호출 제한
첫 번째로 생각했던 것은 무분별한 API 호출을 제한하는 것이었습니다. 서비스의 메인 기능에서 유료 API를 사용하고 있었기에 사용자들의 API 호출을 제한해야 했습니다.
이를 위해 Rate Limiter(Bucket4j)를 도입하여 Redis에 사용자의 호출 상태 정보를 저장하고, filter에서 특정 Request URL에 대해 사용자의 Bucket을 검사하여 하루에 n번까지만 호출할 수 있도록 제한을 두어 해결하였습니다.
하지만 정책이 변경되어서 Limit을 변경해야 하는 경우가 생길 수 있으므로, Redis에 저장되어있는 현재 Bucket의 설정과 BucketConfig 클래스를 비교하여 변경사항이 있을 시에 Bucket 설정을 대체하도록 해야했습니다. 하지만 Bucket에서는 기본적인 설정 정보들을 조회 할 수 있는 방법이 존재하지 않아서 현재 설정과 바뀐 설정을 비교할 수 없었고, 어쩔 수 없이 request마다 Redis에 있는 Bucket의 설정을 BucketConfig로 대체 해주는 방식을 사용하였다는게 아쉬운점으로 남았습니다.서버 노출 최소화
두 번째는 서버 노출을 최소화하는 것입니다. 기존에는 프론트 서버(nextjs)를 vercel로, 백 서버(spring)는 EC2로 배포를 하였습니다.각 서버가 따로 배포되어 있었기 때문에 클라이언트와 서버 도메인 간 통신을 하려면 EC2 보안그룹의 인바운드 규칙에서 서버의 포트를 열어두어야 했고, 혹시라도 포트 스캐닝 등에 의해 포트 번호가 노출된다면 추가적인 보안 문제가 발생하거나 악성 사용자가 swagger에 접근하는 등의 문제가 발생할 수도 있겠다는 생각을 하였습니다.
따라서 포트를 닫고 통신할 방법을 고민했고, client-server와 spring-server가 같은 Docker network에 존재한다면 외부 포트와 상관없이 통신이 가능하다는 생각을 하였습니다. 이를 적용하기 위해 프론트 서버에 github Actions를 사용하여 CI/CD를 구축하고 EC2로 배포를 진행하였습니다.
이때 각 서버의 port를 닫아뒀기 때문에 nginx proxy manager를 사용하여 각 서버의 도메인으로 들어온 request를 도커 내부의 각 서버 컨테이너로 전달하도록 reverse proxy를 설정함으로써 외부에서 통신할 수 있도록 하였습니다.이 덕분에 Docker 내부로만 통신하여 서버가 노출되는 위험을 줄일 수 있었습니다.
테스트 코드 작성을 통한 아키텍처 설계
세 번째는 테스트 코드 작성을 통한 아키텍처 설계입니다. 도메인 간 의존성을 최대한 분리하려고 노력해도 프로젝트가 점점 커지면서 한쪽의 변경사항이 다른 쪽에 영향을 미치는 일이 발생했습니다. 그러다 보니 전파된 오류가 배포 서버에 올라가는 일이 없도록 하기 위해 테스트 코드가 필요했습니다.
그런데 기존의 레이어드 아키텍처에서는 서비스 클래스 하나가 수많은 JpaRepository를 의존하고 있기에 어쩔 수 없이 통합테스트를 작성해야 했습니다. 그러다 보니 매번 DB에 필요한 데이터를 write/delete 해주어야 해서 테스트 코드 작성이 어려웠고, 모든 컨텍스트를 불러오다 보니 테스트 시간 또한 길어졌습니다.
이를 해결하기 위해 테스트 코드를 공부하다 보니 의존성 역전을 통해 해결할 수 있다는 것을 알게 되었습니다. Service가 곧바로 JpaRepository를 의존하는 부분에서, Service와 같은 계층에 Repository Interface를 만든 후 JpaRepository가 Repository Interface를 의존하게 함으로써 의존성 방향을 바꾸었고, 이 덕분에 비즈니스 로직 테스트 코드를 작성할 때 DB에 대한 의존성을 끊어낼 수 있었습니다.
그 결과로 DB를 신경 쓸 필요가 없다 보니 테스트 코드 작성이 좀 더 편해졌고, 통합 테스트에서 단위 테스트로 변경함으로써 테스트 시간 또한 줄일 수 있었습니다.
추가 계획
추가적으로 성능 향상을 위해 게시글 좋아요 개수와 같은 정밀한 데이터가 필요 없는 곳에서 count 쿼리로 조회하는 대신 테이블에 필드로 넣어두고 micro batch를 사용하여 업데이트하는 방식, 1초 이상이 소요되는 슬로우 쿼리를 파악하여 Buffer Pool 사이즈를 조절하거나 커버링 인덱스를 적용하는 등의 쿼리 튜닝을 계획하고 있습니다.
또한 서버의 고가용성을 위해, 호출된 API와 호출한 유저의 정보 로깅과 DB 백업, Redis의 영속성 보장 등을 공부하여 적용할 예정입니다.
포트폴리오
교육
부산대학교
대학교(학사) | 물리학과
2017.03. ~ 2024.02. | 졸업
신세계아이앤씨 Spharos Academy
사설 교육
2023.07. ~ 2023.12. | 졸업
대외활동
2024 지역사회 문제 해결을 위한 연합 해커톤
개인
부산대학교 LINC 3.0 사업단에서 주최한 "2024 지역사회 문제 해결을 위한 연합 해커톤"에서, 전통시장 과일 시가 정보 제공 플랫폼을 개발하여 특별상을 수상하였습니다
자격증
OPIC
IM2 | ACTFL
2024.03.