첫 사이드 프로젝트 플케어(PLL-Care)를 끝내고 난 뒤에 커뮤니티를 둘러보던 중 또다른 사이드 프로젝트 팀원 구인글이 있어서 참여의사를 전달했고, 백엔드 개발자로 참여하게 되었다.
약 2달간(10월 ~ 11월) 진행했던 사이드 프로젝트 '하이디'(Hi-D)에 대해 회고해보려한다.
나의 경우 프로젝트 진행중에 중간에 합류한 터라, 내가 합류한 후의 팀원 구성은 다음과 같았다.
원래 PM이었던 분의 계획에 따르면 10월 한달동안 빡빡하게 진행해서 마치려고 했었던 것 같은데, 디자인 와이어프레임의 수정이나 자잘한 개발 간의 버그 수정들을 하다보니 11월 3주차 즈음에 프로젝트가 완료 되었다.
새로 만들어내는 것보다 기존에 있는걸 제대로 돌아가게하는게 문제다.
개인적으로는 이번 프로젝트가 저번 프로젝트보다 배울점이 더 많았다고 생각하는데, 그 이유는 다음과 같다.
첫번째 이유로는 저번 프로젝트에 비해 이번에 함께한 팀원들의 개발적 역량이 더 좋았다. (매우 주관적인 의견입니다.)
아무래도 저번 프로젝트 때는 모든 팀원들이 대학 재학생들이었는데, 이번 프로젝트에는 모두 취업을 준비하는 사람들이었어서 그런지 좀 더 경험치가 높았던 것 같다. 특히 다른 백엔드 팀원분이 아는 것도 많으셨고, 개발 경험도 많으셔서 그런지 내가 이것저것 물어보기도 하고 서로 특정 이슈에 대해서 의견을 나누면서 많이 배운 것 같다.
두번째 이유로는 새로운 기술 스택을 사용했다는 점이다. 사실 첫번째 이유보다 이게 더 크게 와닿는 것 같은데, 이전 프로젝트에서 개선해야할 점으로 적어놨었던 부분들을 이번 프로젝트에서 모두 시도해보았고, 스프링 프레임워크의 새로운 기능도 사용해보았다. 이에 대해 좀 더 자세히 얘기해보자.
이전 프로젝트에서 Docker와 GitHub Actions를 이용해서 빌드 및 배포 과정을 자동화해놨었다. 그래서 한번 구성해놓으면 얼마나 편리한지 잘 알고 있었다. 늘 새로워 짜릿해!
그런데, 그 자동화 과정 구성을 내가 아닌 다른 백엔드 개발자 팀원이 해놨었기 때문에 나는 Docker가 어떤 원리로 동작되는지 정도만 개념적으로 이해하고 있었다. 이번 프로젝트에서도 자동화를 해놓는게 당연히 좋겠다고 생각이 들어서 시도했고, 성공했다. 워낙 레퍼런스가 많아서 잘 참고하면서 했더니 생각보다 그렇게 오래걸리지도 않았다(2~3일).
완벽한 CI/CD의 전체 프로세스를 경험한 것은 아니지만, 경험을 했다는데에 의미를 두면 좋을 것 같다.
이번 프로젝트에서 주어진 키워드나 정렬 조건등에 맞게 게시물 데이터를 반환해야하는 API가 있어서 동적쿼리를 작성해야했고, 저번 프로젝트 때는 사용하지 못했었던 QueryDSL을 학습하여 사용했다.
QueryDSL을 사용하면서 느꼈지만, 만약 MyBatis같은 SQL Mapper를 사용하지 않고 JPA를 사용한다면, 진짜 QueryDSL이 필수일 수 밖에 없다는 생각이 들었다. 개인적인 의견이지만 왜 스프링부트에서 QueryDSL을 스타터로 지원하지 않는지 살짝 의문이 든다. QueryDSL 기습 숭배
그리고 이전 프로젝트에서는 대부분 Spring Data JPA가 제공하는 쿼리메서드 기능이나 @Query에 JPQL을 작성하는 식으로 모든 SQL 쿼리를 해결했었는데, 이번 프로젝트에서는 partition by와 같은 윈도우 함수를 사용하기 위해 Native Query를 작성하여 사용했다. 짜놓은 Native Query를 보며, 확실히 JPA랑 QueryDSL이 모든 것을 커버해주지 않는다는 것을 느꼈다.
테스트 코드를 작성해본 것이 이번 프로젝트에서 가장 값어치가 높은 성과인 것 같다. 일전에는 테스트 코드에 대해 내가 알고 있는 내용이 거의 0에 수렴했었는데, 이번 프로젝트를 하면서 MockMvc를 이용해서 API 요청을 수행 및 검증해보니 테스트 코드에 대해 무엇을 학습해야하는지 방향성을 잡을 수 있었다. 실제로 프로젝트가 끝나고 테스트 코드와 관련된 강의를 찾아 수강해보았고, 테스트 코드 작성법이나 작성해야하는 이유를 이해하는데 매우 도움이 되었다.
이번 프로젝트의 기능중에 실시간 알림 기능과 1대1 채팅 기능이 있었다. 해당 기능들을 구현하기 위해 웹소켓 통신을 선택했고, 스프링부트에서 제공하는 웹소켓 스타터를 사용해서 구현했다.
웹소켓에 대해서는 네트워크를 공부할 때 이론적으로만 알고 있었는데, 이번에 기능을 구현하면서 웹소켓을 실제로 연결해서 사용해보고 더불어 웹소켓에서 사용할 수 있는 STOMP 프로토콜에 대해서도 알게되었다.
최근 개발자 채용공고를 보면 MSA(Micro Service Architecture)에 대한 경험을 우대하는 경우가 상당히 많다. 나도 MSA가 정확하게 어떤 개념인지 잘 모르지만, 소프트웨어의 아키텍쳐를 설계할 때, 큰 하나의 서비스를 여러개의 작은 서비스로 잘게 쪼개서 서비스간의 통신으로 나눠서 관리한다고 이해하고 있다.
하지만 지금까지 내가 했던 모든 사이드 프로젝트는 monolithic한 구조를 갖고 있다. 하나의 프로젝트 저장소에 모든 코드가 들어있고, 프로젝트 내의 각각의 서비스를 분리해서 별도의 물리적 서버에서 실행하는 것이 아닌 하나의 SpringBoot 서버만 실행하여 모든 요청을 처리한다.
프로젝트가 마무리되어 갈 즈음에 다른 백엔드 개발 팀원분과 우리의 서버를 목적에 따라 분리하면 좋지 않겠냐는 얘기를 했었다.
구체적으로 얘기하자면, 아래와 같다.
가장 처음에는 '실시간 통신과 관련된 코드인가?'를 기준삼아서 분리했는데, 그 이유는 성능 때문이었다. 웹소켓을 사용한 실시간 통신의 경우 클라이언트와 서버가 웹소켓 연결을 계속 유지하고 있어야하기 때문에, 그만큼 서버의 리소스를 잡아먹는다고 생각했고, 그 와중에 같은 서버에서 일반적인 API 요청에 대한 처리도 담당한다면 너무 많은 부하가 걸릴 것이라고 추측했다.
두번째 기준은 '어떤 사용자가 사용하는가?'였다. 말 그대로 일반 사용자는 관리자의 기능을 사용할 수 없는데, 같은 클래스 내에서 이를 모두 품고 있어서 이를 분리하려고 하였다.
결과적으로 위처럼 고민은 해봤지만, 실제로 MSA 구조로 프로젝트 코드를 나눈다거나 서버를 분리하진 않았다. 그렇게 하기엔 MSA에 대해 추가적으로 학습해야할게 너무 많았고, 가용할 AWS 자원이 없었다.
참... 아이러니하다. 대부분의 기업에서는 '대규모 사용자'에 의한 서비스 요청을 처리해본 경험이 있는지를 요구하는데, 정작 취준생 입장에서는 기업에 들어가지 않으면 이를 시도해볼 수 있는 리소스를 경험할 수가 없다. 물론 돈이 많으면 상관없겠지
그래서 기회가 된다면 MSA를 학습해서 이를 프로젝트 구조에 적용해보면 좋을 것 같다.
이번 프로젝트에서 queryDSL을 사용해서 동적쿼리를 작성했고, 이 동적쿼리를 데이터 검색 쿼리로 사용했다. 하지만, 사실 이는 그렇게 강력한 기능은 아니었다. 단순히 DB에 저장된 게시물 데이터의 제목과 본문에 특정 단어를 포함하고 있는지만 체크하는 쿼리를 작성했기 때문이다. 물론, 쇼핑몰 서비스같은 곳에서는 데이터를 주어진 일자로 검색하고, 가격같은 기준으로 정렬하기 때문에, 동적쿼리는 반드시 필요하다. 하지만, 검색 엔진에서 사용하는 데이터 검색 쿼리는 단순한 SQL 쿼리로는 해결할 수가 없다. 이를 해결하는 솔루션으로 ElasticSearch와 같은 기술들이 있는데, 학습이 필요할 것 같다. 공부해야하는 내용이 1 늘었습니다!
위에서도 짧게 얘기했지만 이번 프로젝트에서 테스트 코드를 작성해보고, 프로젝트가 완료된 후에 테스트 코드와 관련된 강의를 수강했다. 원래라면 [강의 수강 -> 테스트 코드 작성] 의 순서로 하는게 맞겠지만, 그냥 맨땅에 헤딩하는 기분으로 백엔드 개발 팀원의 코드를 레퍼런스 삼아 테스트 코드를 먼저 작성해보았다. 그리고 이후에 강의를 듣고 보니, 내가 작성했던 테스트 코드는 아직 개선해야하는 부분이 많다라는 것을 느꼈다. Controller, Service, Repository 와 같은 계층을 나눠서 테스트를 작성하고, 이에 따라 어떤 부분을 Mocking 해야하는지 강의를 통해 학습했기 때문에 체화를 위해 직접 테스트 코드를 작성해보는 과정이 필요할 것 같다. 또, 현재의 테스트는 단일 API 요청을 가정하여 테스트 코드가 실행되고 있는데, 실제 서비스는 불특정 다수의 사용자가 동시에 API를 요청하는 상황이 일반적이기 때문에, 해당 환경도 고려한 테스트 코드 작성이 필요할 것이다.
그 밖에도 추후에 도전해볼만한 주제를 얘기해보자면, 실제 API 요청을 하는 과정에서 스프링 부트 서버 내부에서 예외가 발생했을 때 로그를 저장하여 보관하는 환경을 구축한다거나 삭제류의 API가 요청되었을 때, 데이터베이스에서 Hard-Delete하는게 아닌 Soft-Delete를 하는 로직을 구현하는 것을 도전해볼 수 있을 것 같다. 마지막으로, 프로메테우스, 그라파나, 스카우터, 핀포인트같은 모니터링 시스템을 실제 동작하는 서버에 붙여서 성능을 모니터링하는 환경을 구축하는 것도 도전해봄직하다.