토이 프로젝트 일지 9: 음악 스트리밍 마이크로 서비스 만들기

그림 1. 이벤트 스토밍 설계도

그림 2. 프론트엔드 페이지들

1. 시작 계기

플랫폼 비즈니스 교육에서 수행되는 1차 팀 경진대회에서 조장을 맡아서 구현하게 된 서비스다. 이 경진대회에서 1등으로 대상을 받게 되었다.

2. 프로젝트 개요

가. 프로젝트 소개

1. 프로젝트 유형: 팀 토이 프로젝트(총 8명)

2. 구현 서비스: 음악 스트리밍 서비스

3. 개발 환경: VS Code, Msaez

4. 활용기술

    프론트앤드: React, MUI
    백엔드: Spring-Boot, JPA, MySQL
    구조설계: MSA(Event Driven Architecture), CQRS, SAGA, Kafka, JWT
    빌드 및 배포: EKS
    협업: Slack, Trello, GitWiki

5. 개발 기간: 2024.01.16 ~ 2024.01.30

6. 담당 역할: 팀장(일정 관리, 작업 분배, 코드 평가 및 통합 작업, 프론트엔드, PPT 작성, 발표)

3. 프로젝트 구현

가. 팀 협업 및 역할 분담

그림 3. 팀 협업의 핵심요소

이 팀 프로젝트에서 제일 고민을 많이 했던 부분은 팀장을 포함해서 총 8명이나 되는 팀을 도대체 어떻게 해야 잘 운영할 수 있는지에 대한 문제였다. 거기에다 팀원들은 서로 시간이 맞지 않아서 오프라인으로 만나기도 힘들었기에 이 문제는 더욱 풀기 힘든 문제였었다. 하루 종일 이에 대해서 고민을 해본 결과, '요즘 우아한 개발'이라는 책을 참조해서 팀 협업을 위해서는 위의 4가지의 핵심 요소를 기반으로 설계해야 한다는 결론이 이르렀다.


그림 4. Trello로 활용한 '명확한 업무 분담 및 추적'

이렇게 팀원이 많을수록 개개인의 책임이 옅어져서 참여도가 떨어지게 될 것으로 생각해서 개개인에게 명확하게 업무를 분담시키고, 개개인의 업무를 철저하게 관리하는 것이 중요하다고 생각했다. 이를 위해서 에자일의 스프린트를 참조해서 할 일 목록을 만들고, 개개인의 책임 의식을 강화하기 위해서 개인마다 할 일 목록을 만들어서 별도로 관리했다. 이렇게 별도로 업무를 관리하니 각각의 팀원이 했던 일이 명확하게 보여서 참여도가 확실히 올라간 것이 느껴졌다.

또한, 개개인의 시간이 일치하지 않기 때문에 할당하는 일간의 의존성이 존재하면 도저히 시간 안에 끝낼 수가 없어 보였다. 그래서 각각 일의 의존성을 제거하기 위해서 Mock 서비스와 엔드포인트들을 마련해서 일들을 동시에 맡길 수 있도록 만들었다.

각각의 일에는 난이도를 할당시켜서 개개인에서 난이도의 합이 동등하게 분배하였다. 잘하는 사람에게는 더 많은 일을 시키는 게 좋을 수 있지 않겠느냐고 생각하기는 했으나 문제점은 여기에는 더 많은 일을 시킨 것에 대한 보상이 필요한데 현재로써는 이러한 부분이 불가능하기 때문에 결국에는 잘하는 사람한테 더 많이 시킬 뿐이라서 의지를 꺾을 수도 있어서 그냥 공평하게 분배하는 게 좋다는 결론을 지었다.


그림 5. Github Wiki로 활용한 '투명하고 상세한 문서화'

팀원 수가 많기 때문에 한명 한명 가르치는 것은 매우 비효율적이었으며, 차후에 새로운 팀원이 들어올 수도 있어서 결국에는 Wiki와 같은 지식 공유 저장소가 필요하다는 결론에 이르렀다. Github Wiki는 Jira Confluence에 비해서 Learning Curve가 낮고, 상대적으로 친숙하기 때문에 익숙하게 채용할 수 있었다.

Wiki 작성 시에 가장 중요시한 것은 내가 이것을 이해했는지를 체크할 수 있는 과제를 제시한 것이다. 이러한 문서를 읽기만 하면 자신이 이해했다고 착각할 수 있기 때문에 이러한 부분을 넣는 것은 학습에 상당히 도움을 줄 수 있다고 생각한다.


그림 6. Slack을 활용한 주제 토론 및 지식 공유

팀원끼리의 토론을 위해서는 Slack을 활용하였다. 팀원들끼리 서로 동일한 시간에 만나기 힘들기 때문에 메시지 시간을 보면 알 수 있듯이 상당히 긴 기간 특정 주제에 대해서 의견을 남기고, 이를 종합해서 투표하는 식으로 시간 관련 문제를 해결했다. Slack에 특정 주제에 대한 회의 내용을 남겨서 차후 새로운 팀원이 들어와서 이를 참조할 수 있도록 만들었다.


그림 7. Github PR을 통한 코드 손상 방지 및 자동 유효성 검사 테스트

팀원이 많을 경우 발생하는 또 다른 풀기 어려운 문제는 코드 스타일을 어떻게 통합하면서 일관되게 유지하는 것에 대한 문제다. 이 부분은 현재 환경에서는 어쩔 수 없이 중앙 집중적으로 PR 요청을 하나하나 검토하고, 리팩토링을 거침으로써 이러한 문제를 해결했다.

또한, 코드의 통합된 유효성을 검증하기 위해 사용자 시나리오를 기반으로 관련 셸 스크립트를 작성해서 이러한 부분을 조금이라도 개선할 수 있었다.

나. 요구사항 분석

그림 8. 요구사항 브레인스토밍 과정

그림 9. 최종적으로 도출된 요구사항

요구사항 도출을 위해서 우선, Slack에 관련 채널을 만들어서 요구사항 도출 브레인스토밍을 진행했다. 그리고, 기술적 & 시간상으로 어려운 요구사항들을 제거해서 최종적으로 요구사항 테이블을 생성했다.

다. 이벤트 스토밍 설계

그림 10. 이벤트 스토밍 설계도

총 6개의 BC를 도출했으며, 음악인 경우 역할 분리를 통해서 음악 정보를 관리하는 music BC, 음악 파일을 관리하는 file BC로 분리했다.

CollectedData에 관련 이벤트 내역을 수집시켜서 CQRS를 구현했고, file에서는 실패했을 경우 '...failed' 이벤트를 발생시켜서 실패 부분을 처리하도록 만들어서 SAGA 패턴을 구현했다.

라. 구현

라-1. 사용자 인증 구현

그림 11. JWT 기반 게이트웨이 통합 인증 

그림 12. 프론트엔드상에서 사용자 인증 구현

백엔드 상에서는 게이트웨이를 통한 단일 엔드포인트 통합 인증을 통해서 인증 부분은 게이트웨이에 완전히 이양시켜서 복잡성을 감소시켰다.

프론트엔드 상에서는 JWT를 컨텍스트상에서 관리하게 만들어서 다른 페이지에서 손쉽게 사용할 수 있도록 구현했다.

라-2. 음악 관리 구현

그림 13. 음악 파일 관리 부분에서의 SAGA 패턴

그림 14. 음악 관련 페이지에서의 컴포넌트 재활용

백엔드 상에서는 모든 파일 관련 요청에 'Failed...' 이벤트를 추가시켜서 SAGA 패턴을 구현했다.

프론트엔드 상에서는 음악 관련 페이지들에 음악 플레이어 부분을 독립적인 컴포넌트로 분리셔커서 리액트의 핵심 가치인 '컴포넌트의 재활용'을 최대한 활용해 보기 위해서 노력했다.

라-3. 플레이 리스트 관리 구현

그림 15. 플레이 리스트 부분 BC들

그림 16. 플레이 리스트 부분 프론트엔드 페이지들

백엔드 상에서는 성능 향상을 목표로 플레이리스트의 음악 개수를 별도의 변수로 분리했다.

마. 빌드/배포

마-1. EKS 배포

그림 17. 템플릿을 통한 EKS 배포

이전 경험에서 각각의 마이크로 서비스상에서 생성되는 Service, Deployment 관련 설정이 상당 부분 유사하다는 것을 알게 되어서 이번에는 이러한 유사한 부분을 최대한 줄이기 위해서 관련 부분을 '$'로 변수화시키고 'sed' 커맨드를 통해서 교체하는 식으로 중복된 코드를 상당 부분 줄일 수 있었다.

하지만, 나중에 추가로 공부하면서 k8s Kustomize라는 기능을 활용하면 이러한 것을 손쉽게 구현할 수 있다는 것을 알게 되어서 차후에는 활용을 해볼 예정이다.

마-2. EKS 기능 활용

그림 18. k8s 활용: 오토 스케일 아웃


그림 19. k8s 활용: 무정지 배포


그림 20. k8s 활용: 자동 복구

k8s의 다양한 기능들을 활용해 보았다.

4. Q&A

프로젝트 발표를 하면서 상당히 오랫동안 Q&A를 진행하게 되었고, 몇 가지 부분은 내가 전혀 생각하지 못했던 부분이었으나 그래도 적절하게 대처해서 대답할 수 있었다.

4-1. Q&A1

Q1. 팀원마다 서비스를 할당시키는 게 더 편하지 않은가? 왜 완전히 무작위로 팀원들에게 작업을 분배했는가?

A1. 물론 팀원마다 서비스를 할당하면 더 효율적일 수 있다. 하지만, 이번에는 색다른 시도를 해보고 싶었고 이렇게 완전히 무작위로 작업을 분배할 경우 다음과 같은 이점이 있을 수 있다.

1. 갑자기 특정 팀원이 일을 그만두게 되어도, 완전히 무작위로 작업이 분배되었기 때문에 각각의 팀원들이 전체적인 흐름을 어느 정도 이해하고 있다고 볼 수 있다. 그러므로, 이러한 팀 인원 변동에 상당한 내성을 지닐 수 있게 된다.

2. 무작위로 작업이 분배되기 때문에 각 서비스 코드 작업 시에 항상 새로운 사람이 들어올 것을 염려하게 된다. 그러므로, 필연적으로 문서화를 치밀하게 하게 되며 이것 또한 프로젝트 유지보수를 견고하게 할 수 있을 것이다.

4-2. Q&A2

Q2. 다음에 어떠한 식으로 확장할 수 있겠는가?

A2. 다음과 같은 확장 시나리오를 고려할 수 있다.

1. AI를 활용한 음악 추천 서비스를 구현한다면 좀 더 타 서비스와의 차별점이 생길 수 있을 것이다.

2. 음악 파일 또한 용량이 클 수 있다. 자주 접근하는 음악들은 따로 CSP와 같은 캐시서버에 저장한다면 성능향상을 노려볼 수 있다.

3. 현재 백엔드는 전부 비동기적으로 처리되도록 만들어져 있어서 클라이언트는 이러한 부분을 불편하게 여길 수 있다. ReadModel에 웹 소켓을 붙인다면 클라이언트 측에서는 동기적으로 이러한 부분을 느끼게 되므로 사용성이 향상될 수 있다.

5. 프로젝트 소감

이번 프로젝트를 통해서 큰 규모의 팀 프로젝트를 어떻게 운영할 수 있는지에 대해서 상당한 통찰력을 얻을 수 있었다. 기존의 2~3명 규모의 팀 프로젝트에서는 마주하지 못했던 수많은 문제가 발생했지만, 이러한 부분을 적절하게 대처할 수 있게 되었다는 점에서 다시 한번 성장했다는 느낌이 들었다.

이 블로그의 인기 게시물

토이 프로젝트 일지 6 : React/SpringBoot 기술 스택으로 코딩 테스트 서비스 만들기

토이 프로젝트 일지 7 : RedKiwi와 유사한 이벤트 스토밍 기반 마이크로 서비스 만들기

토이 프로젝트 일지 2 : ChatGPT 서비스를 활용하는 크롬 플러그인 만들기