[우아한테크코스 5기] 레벨 3 - 5주차 회고

Glen·2023년 7월 29일
0

회고

목록 보기
20/25

7월 24일 월요일

드디어 돌아온 잠실 🏠

레벨3가 5주 차에 들어서는 날

드디어 선릉을 벗어나, 잠실로 등교하게 되었다.

다시 한번 말하지만, 선릉이 싫은 것은 아니다. ㅋㅋㅋ

잠실이 선릉보다 시설이 좋을 뿐...

캠퍼스가 바뀌어서 자리를 지정해야 했는데, 자리 지정은 사다리 타기로 등수를 매겨 결정하기로 했다.

선릉에서는 9개의 조가 모여있는 강의장에 배정되어 분위기가 산만하고 집중하기 조금 어려워서 이번에는 2~3개의 조가 모여있는 작은 강의장을 배정받고 싶었다.

잠실에는 2개의 작은 강의실이 있고 5개의 조가 들어갈 자리가 있어서 5순위 안에만 들면 작은 강의실을 배정 받을 수 있었다.

다행이 운이 좋게, 5등에 걸려서 2개의 조만 있는 강의실에 배정받을 수 있었다. 👍

오늘 오후 6시까지 해야 하는 과제가 있고, 내일 오후 2시까지 해야 하는 과제가 있어서 오늘은 프로젝트의 진도를 나가지 않고, 해당 과제에 집중했다.

또한 매주 월요일 15시에 정기 근로 회의가 있어서 실제로 활동에 투자할 수 있는 시간은 매우 적었다. 😂

그래도 순간의 집중력을 발휘하여 당장 수행해야 할 과제들을 빠르게 끝낼 수 있었다.

그나저나 3차 데모데이에서 발표해야 할 기능들이 산더미같이 쌓여있는데, 과연 해치울 수 있을지 모르겠다...

우선 가장 중요하게 처리해야 할 도메인 구매와 예외 처리 그리고 로깅 전략 등에 대해 내일 고민을 해봐야 할 것 같다.

그리고 3차 데모데이에 구현할 기능을 정리하여 이슈로 남기는 작업도 해야할 것 같다.

JPA 미션도 해야하고, 레벨 인터뷰 준비도 해야 하고... 할 게 너무 많은 것 같다. 😂

면접 대비 CS 공부와 알고리즘 문제는 또 언제 해야 할지...

산넘어 산이다...

무엇을 준비해야 할지 모르겠다.

7월 25일 화요일

3차 데모데이 대비 API 설계 및 UX 워크숍 2일 차 🚀

간만에 오전 10시에 잠실로 등교하는 날

우테코에 처음 발을 디딘 곳은 선릉이지만, 레벨 1부터 2까지 쭉 함께 해온 건 잠실이다.

잠실역 8번 출구를 나오며, 아침 햇살을 느낄 때 비로소 고향에 돌아온 것 같은 기분이 든다.

늘 그랬듯이, 데일리 미팅을 진행하고 프로젝트에 대한 작업을 시작했다.

3차 데모데이 일정이 빡빡하기 때문에 우선, 필요한 기능들을 정리하기 위해 API 명세를 빠르게 작성했다.

API 명세를 작성하며, 프로젝트의 작업을 진행한 것도 있지만, 기존에 작업했던 도메인의 필드가 불필요하다는 것을 알게 되었다.

이래서 처음부터 완벽하게 설계할 필요가 없다고 한 건지 모르겠다. 😂

조원 모두 API 명세 작성에 완전히 몰입하느라, 점심시간이 됐는지도 모른 채로 집중했다. 🔥

늦은 점심을 먹고 13시 30분에 UX 워크숍 2일 차 강의가 진행되어, 조원들과 강의를 들었다.

강의에선 이전에 진행했던 UX 워크숍 1일 차 내용에 이어서 어떻게 해야 사용자가 우리 서비스를 믿을 수 있을 수 있을지에 대한 내용을 배웠다.

우리가 제공하는 서비스가 사용자에게 주고자 하는 핵심 가치, 핵심 경험은 과연 무엇인가?

사용자는 왜 우리의 서비스를 사용해야 할까?

조금 추상적이고 정답이 없는 문제이지만..

충분히 고민해야 하고, 생각해 봐야 하는 문제에 대해 알게 된 것 같다.

지금, 이 글을 쓰며, 우리가 만든 서비스가 일상에서 사용될 가능성이 있을지 생각이 든다.

강의는 약 1시간 정도로 진행됐고, 그 후에 일정은 담당 코치의 조들이 모여, 서로가 작성한 서비스 소개 글을 피드백하는 시간을 가졌다.

이러쿵저러쿵 여러 얘기가 오가고, 16시쯤 다시 프로젝트를 진행했다.

1시간가량 진행 후 API 설계가 최종적으로 마무리되고, 그 후 자잘한 작업을 진행했다.

API 설계가 마무리됐으니, 이제 구체적인 작업에 들어갈 일만 남았다.

내일은 어떤 일을 시작해야 할 지 조원들과 얘기를 해봐야 할 것 같다.

기술 블로그를 만들어 볼까 생각은 해봤는데, 지금 3차 데모데이 일정이 바빠서 어떻게 될지 모르겠다. 😂

하고 싶은 것은 많은데, 시간이 너무 모자란 것 같다.

7월 26일 수요일

커스텀 예외 생성 및 3차 데모데이 대비 이슈 생성 💣

오늘은 커스텀 예외를 어떻게 만들고 사용할지 이야기를 나눴다.

이전에 했던 미션이나 프로젝트에서는 RuntimeException을 상속받은 예외를 만들어 사용했다.

여러 상황이나 도메인에 관한 예외가 발생한다면 그에 따른 예외도 추가로 만들어 사용했다.

이때 생기는 문제가 예외 클래스가 점점 많아진다는 문제점이 생겼다.

따라서 이번 프로젝트에서는 우리 프로젝트에서 사용되는 최상위 예외를 만들고, 최상위 예외를 상속하는 예외를 만들었다.

FestagoException -> BadRequestException, NotFoundException, InternalServerException

그리고 상황에 따른 처리는 예외의 필드로 ErrorCode를 두어서 상황에 따른 예외를 분류했다.

ControllerAdvice에서 예외 핸들러는 최상위 예외를 상속한 예외를 잡은 뒤, 상속한 예외에서 사용자 측에서 잘못된 요청으로 인해 발생하는 예외는 ErrorCode에 정의된 메시지와 함께 응답을 보내주기로 했다.

그리고 서버 측에서 발생할 수 있는 예외는 단순히 서버에 오류가 발생했다고 응답을 보내주기로 했다.

추가로, 예외의 필드에 어떠한 엔티티의 Id에서 예외가 발생했는지 적어주려고 했지만, 요청에 여러 엔티티가 사용되는 경우 어떠한 엔티티의 Id를 사용할 것 인지 논의가 길어져, 우선 ErrorCode만 사용하기로 했다.

추후 엔티티의 Id가 필요한 상황이 오면 그때 추가해야 할 듯하다.

그 뒤 점심을 먹고 본격적인 프로젝트 개발에 앞서 무엇을 진행해야 할지 정리를 할 겸 이슈에 작업 단위별로 등록했다.

내일 애쉬가 개인 용무로 인해 오지 못하게 되어, 3명이 최대한 작업을 해야 한다. 😂

대략 정리가 끝나고, 피플행복 근로 활동이 있어서 회의하고, 기획한 이벤트에 관해 컨펌을 요청했는데...

❓이모지와 함께, 단호하게 반려되었다. 😭

월요일에 있던 근로 회의에서 나온 기획이었지만, 뭔가 부정적인 피드백이 있어 약간의 걱정은 했지만 그래도 다른 기획이 떠오르지 않아 제출했는데...

큰 시간을 투자한 기획은 아니라 다시 기획안을 생각하면 되지만... 그래도 고민했던 기획이 반려되니 기분이 좋지는 않았다. 😭😭😭

프로젝트 기간이라 다들 바빠서, 시간에 부담받지 않고 간단하게 진행할 수 있는 기획이 뭐가 있을지 모르겠다.

7월 27일 목요일

본격적 페어 프로그래밍 시작 👥

오늘은 애쉬가 개인 용무로 인해 불참하여, 세 명이 개발을 진행했다.

개발은 중요도를 나눠, 혼자서 할 수 있는 것과 페어로 진행할 수 있는 것을 나누고, 사다리 타기로 누가 혼자서 할 것 인지 정했다.

사다리 타기의 결과로 푸우가 혼자서 개발하기로 결정이 됐다. 😂

이전에 협업을 진행했을 때도 그렇고, 다른 크루의 얘기를 들어보면서 그렇고 협업을 통해 제일 힘들었던 점을 꼽자면, 서로의 성격 문제나 컨벤션 문제가 아닌 충돌을 해결하는 것이 가장 힘들지 싶다.

4명이 각각 개발을 한다면 처리량은 사람 수만큼 되겠지만, 서로의 작업 내용이 겹치게 된다면...?

충돌을 해결하느라, 온 시간을 쏟게 될 것이다. 😂

따라서 혼자서 개발을 하는 사람은 가장 덜 중요한 관리자의 기능을 맡기로 했다.

그리고 나와 오리는 사용자가 티켓을 예매하는 기능을 구현했다.

그런데... 구현하다가 턱 막혀버렸다.

우리의 비즈니스 흐름은 다음과 같다.

  1. 티켓은 공연과 N:1 관계이다.

  2. 티켓은 입장 시간이 각각 다르다.

  3. 티켓들은 재학생, 외부인으로 타입이 구분된다.

  4. 사용자가 티켓을 예매할 때, 공연의 Id와 타입으로 요청을 보낸다.

  5. 서버는 공연의 Id와 타입으로 남아있는 시간대의 티켓을 조회하여 가장 빠른 입장 시간을 가진 티켓을 예매한 뒤 티켓의 번호를 응답으로 반환한다.

여기서 티켓 예매는 동시에 요청이 매우 많이 들어온다.

따라서 티켓 예매는 빠르게 요청을 처리해야 한다.

하지만 남아있는 시간대의 티켓을 조회하려면...?

해당 티켓의 발급 수와 사용자들이 예매한 티켓 수의 합을 비교하여, 예매를 더 할 수 있는지 비교한다.

만약 예매를 못 하는 티켓이면 다음으로 빠른 입장 시간을 가진 티켓을 예매한다.

이런 사이클이 반복되는데, 예매할 수 있는 티켓인지 검사를 하는 로직이 계속 반복된다.

즉, 하나의 티켓을 예매하는데, SELECT 문이 N번 날아가게 된다.

이것은 하나의 요청에서 티켓 예매를 처리하는데, 데이터베이스 커넥션을 오래 잡고 있게 되고, 다른 요청들이 커넥션을 잡지 못해 오래 대기하게 되어, 결과적으로 동시성 처리를 할 때 성능에 문제가 발생할 게 뻔했다.

또한 티켓의 번호를 응답으로 줘야 하는데, 하나의 공연에서 티켓의 번호는 고유해야 한다.

따라서 티켓의 번호를 반환하여 줄 때, 공연에 대해 예매된 티켓의 갯수를 구해 + 1 해 준 값을 설정해줘야 한다.

또 한 번 SELECT 쿼리가 날아가게 된다. 😂

동시에 가장 트래픽이 많이 몰리는 기능인데, 쿼리가 날아가는 갯수가 어마무시하게 많다.

이렇게 된다면 어떻게 동시성 문제는 해결할 수 있어도, 성능에 대한 문제는 해결할 수 없을 것이다.

또한, 티켓을 예매할 때 남은 티켓의 수량을 표시해야 하는데, 이것 또한 티켓의 목록이 있을 때 티켓의 타입 개수만큼 SELECT 쿼리가 날아간다...

뭔가 엄청나게 잘못되었다는 것을 느꼈다... 😂

그 뒤 머리를 싸매며 여러 방법을 생각해 봤는데..

  1. 티켓의 번호는 단순히 자동 생성된 PK로 반환한다.
  • 사용자가 티켓의 번호를 알고 있다고 해도, 결국 QR을 찍고 들어가고 입장 시간이 지나도 입장이 가능하므로 티켓의 번호는 순서가 아니라 고유번호 같은 개념이다.
  1. 티켓에 남은 개수 필드를 추가한다.
  • 마치 쇼핑몰에 상품의 재고처럼 관리한다. 이렇게 되면 티켓을 예매할 때 -1씩 해주어야 할 것이다.
  1. 입장 가능 시간을 Lazy 하게 처리하여, 티켓의 재고만 확인하고 예매의 성공 여부만 알려준다. 그리고 스케쥴링이나 배치 등을 통해 입장 시간은 나중에 알려준다.

여러 방법이 더 있겠지만 오늘로 생각한 해결 방안은 이것이다.

기획 단계에서 드러나지 않던 문제들이 본격적인 구현 단계에서 드러나기 시작했다.

당장 다음 주 금요일에 3차 데모 발표를 해야 하는데...

걱정이 참 태산이다. 😂

1번, 2번은 쉽게 해결할 수 있겠지만... 3번은 어떻게 해결할 수 있을지 모르겠다... 😂😂😂

우선 빠르게 해결할 수 있는 문제부터 해결해야 할 것 같다.

7월 28일 금요일

도메인 대공사 🚧

오늘은 어제 고민했던 부분들에 대해 크루들과 회의를 진행했다.

어제 애쉬가 개인 사유로 출석하지 못하여, 어제 있었던 일을 쭉 정리했다.

그리고 팀원들과 회의 결과는 다음과 같다.

티켓의 번호는 사용하지 않거나 특정 문자열로 이루어진 고유한 값으로 설정하기로 했다.

  • 입장을 할 때는 티켓의 QR 코드로 검사하므로, 번호가 의미가 없다고 판단했다.

그리고 티켓에 남은 갯수 필드가 아닌, 예매한 갯수 필드를 추가하기로 했다.

  • 잔여 수량보다는 0부터 시작하는 예매한 갯수가 추후 관리하기 편해서이다.

입장 가능한 시간의 처리는 얘기가 많이 길어질 것 같아, 어제 작업했던 내용들을 우선 dev 브랜치에 합치기로 했다.

3~4개 정도의 작업한 브랜치가 있었는데 한두 개는 충돌 없이 원활하게 병합이 되었다.

하지만, 작업한 지 조금 시간이 지난 브랜치가 있었는데, 해당 브랜치를 병합하려고 하니 충돌이 발생해 버렸다. 😂

충돌을 해결하고자, origin/dev 브랜치의 내역을 rebase 시켜서 충돌을 해결했다. 하지만 충돌을 해결하니 또 충돌을 해결해야 하는 상황이 발생했다.

해당 원인은 추정하건데, push된 커밋을 리베이스하려고 해서 발생한 상황 같다.

그래서 우선 merge로 해결했고, 추후 무엇이 원인이었는지 실험을 통해 알아봐야겠다.

그 뒤 간만에 조원들과 같이 점심을 먹었다.

선릉에서 가격도 비싸고, 사람들도 많은 곳에서 밥을 먹다가 간만에 잠실의 맛집에서 밥을 먹으니 간만에 내려온 고향에서 집밥을 먹는 기분이었다. 😭

점심을 먹고, 나머지 기능들에 대한 병합을 전부 완료한 뒤 티켓 예매에 관한 기능에 대해 긴 얘기를 나눴다.

우선 Ticket 도메인이 크게 바뀌어야 할 것 같았다.

Stage와 Ticket은 일대다 관계이다.

Ticket에는 티켓 타입(재학생, 외부인), 최대 수량, 발급한 수량, 입장 시간이 필드로 있다.

여기서 사용자의 UI에 티켓의 남은 수량과 최대 수량을 보내주려면 Stage에 대한 모든 Ticket을 Join한 뒤, 해당 티켓의 개수를 모두 더 해 결과로 보여줘야 한다.

즉 어제 말했듯 티켓 개수만큼 SELECT 쿼리가 날아가기 때문에 성능이 매우 나쁠 것이다.

또한 예매할 때, 모든 티켓을 조회하고 예매할 수 있는 티켓을 찾아 티켓에 있는 발급한 수량 컬럼의 값을 변경시켜 줘야 하므로, 티켓 테이블에 락이 걸리게 된다. (락을 걸 경우)

티켓 테이블에는 조회에 필요한 컬럼들이 많은데, 락이 걸릴 경우 다른 요청에서 읽기만 할 때 읽을 수 없으므로 그또한 성능에 악영향을 줄 것 같다 판단했다.

따라서 Ticket, TicketAmount, TicketEntryTime(추후 이름을 바꿔야 할 것 같다.) 엔티티로 분리가 되었다.

TicketAmount는 Ticket과 1:1 관계이다.

Ticket이 가지고 있던 발급한 수량을 TicketAmount로 이전시켜 쓰기 작업에 필요한 컬럼을 이전시켰다.

또한, Ticket의 발급 가능한 최대 개수도 관리한다.

TicketEntryTime은 Ticket과 N:1 관계이다.

TicketEntryTime은 Ticket이 가지고 있던 입장 시간과 최대 수량을 분리한 엔티티이다.

따라서 Ticket은 개수는 입장 시간의 개수 * 타입의 개수가 아닌, 타입의 개수만 생성된다.

그리고 입장 시간에 티켓의 개수가 있으므로, 티켓의 개수도 컬럼으로 가지게 했다.

이렇게 엔티티를 읽기에 관련된 엔티티와 쓰기에 관련된 엔티티로 분리했는데 과연..

좋은 설계가 되었는지는 모르겠다.

아무튼 설계를 다시 바꾸느라 기존에 작성했던 코드들을 수정했다. 😂

이랬는데 추후 문제가 발생해서 다시 갈아엎어야 한다면 슬플 것 같다.

이제 3차 데모데이가 한 주밖에 남지 않아서 구현할 시간이 많이 남지 않았기 때문에 주말에 캠퍼스에 나와 HTTPS 적용을 해야 할 것 같다.

이번 주는 정말 바쁘게 보낸 것 같다.

다음 주는 더 바쁘겠지만...

profile
꾸준히 성장하고 싶은 사람

1개의 댓글

comment-user-thumbnail
2023년 7월 29일

정리가 잘 된 글이네요. 도움이 됐습니다.

답글 달기