[우아한테크코스 6기] 레벨3 돌아보기 (2024/07/02 ~ 2024/08/23)

 

 

어느덧 우아한테크코스의 레벨 3까지 끝나게 되었다.

프로젝트 팀원들과의 너무나 즐겁고 소중한 시간들이었고, 지금까지의 개발 인생에 있어서 가장 유의미한 협업의 한 사이클을 경험한 나날들이었기에 회고를 통해 글로 기록해두고자 한다.

 

 


 

프로젝트와 함께 시작된 협업

우아한테크코스 레벨 3 시작과 함께 함께 레벨 1,2를 거치며 학습한 내용을 바탕으로 프로젝트를 시작하게 되었다.

레벨 1을 통해 단련한 자바와 레벨 2를 통해 단련한 스프링을 기반으로 프로젝트의 백엔드를 개발하게 되었다.

 

 

팀원들과 첫 만남

지금은 누구보다도 터놓고 지내는 팀원들이지만, 그래도 첫 만남은 조금은 어색했던 것 같다.

백엔드 팀원은 3명 중 2명이 레벨 2에서 같은 조원이라 굉장히 가까웠지만, 프론트엔드 팀원들은 완전히 처음 보거나 한 번 정도 대화를 주고받은 사이였다.

하지만 누구 하나 빠짐없이 좋은 성격을 가진 덕분에 금방 친해지게 되었다.

 

 

프로젝트 기획 

팀 구성과 동시에 바로 프로젝트 기획에 들어가게 되었다.

거의 일 주 밖에 안 되는 너무나 짧은 시간이었지만, 금방 기획을 마무리할 수 있었다.

나는 정말로 사용되는 서비스를 개발하고 싶단 생각에 여태까지의 프로젝트 경험을 바탕으로 누구보다 열심히 기획에 임하려 노력했다.

다양한 아이디어를 제시하고, 팀원들을 설득하였다.

 

직전에 경험한 프로젝트 '라이온하트'는 운영과 출시까지에 필요한 준비기간과 리소스가 너무 크고 길어서 출시에 실패하였으며,

그 이전에 경험한 졸업작품 프로젝트 '코리', 걱정기록 서비스 '흐릿'은 우리 팀에서 필요하다고 생각했지만 사실은 유저가 필요로 하지 않았던 것이라 실패했다. 유저가 원하고 필요로 하는 것을 만들어내야 한다고 생각했다.

 

다수의 기획 회의 흔적..

그리고 이러한 과정을 거쳐 결론적으로 팀원들이 모두 함께 공감해 준 프로젝트 '땅콩'의 기획안을 도출해 내었다.

 

'땅콩'은 심심풀이 땅콩의 약자로 심심풀이로 사용할 수 있는 아이스브레이킹 & 친목 서비스이다.

다양한 주제로 밸런스 게임 문항을 제공하는데, 특이한 점은 '다 함께' 즐길 수 있다는 점이다.

 

실시간성을 보장하는 서비스로 다 같이 하나의 방에 접속해서 밸런스 게임을 진행하고 서로의 결과를 확인한다.

중간중간 대화를 이끌 수 있는 각종 지표들을 제시하며, 게임이 종료되면 투표 결과를 바탕으로 함께 게임한 팀원들과의 매칭도를 확인할 수 있는 재미있는 서비스이다.

 

자세한 내용은 프로젝트 Github에서 확인할 수 있다.

 

 

팀 문화, 코드컨벤션 확립하기

개발만큼이나 중요한 것은 바로 팀 문화와 컨벤션들이다.

초기에 이것들을 잡기 위해 최선을 다했다.

 

팀 문화 정의를 통해 전체적인 업무 문화와 분위기를 확립하고, 코드컨벤션 설정을 통해 통일성 있는 코드를 작성하기 위해 노력했다.

 

땅콩팀 문화 문서 (일부)

협업툴인 노션에 기록해 둔 팀문화 문서 중 일부이다.

이것들을 지키기 위해 정말 많이 노력했다.

매번 데모데이가 끝날 때마다 팀문화에 대한 진중한 회의를 거쳐가며 튼튼하고 세련된 팀문화를 만들어가기 위해 최선을 다했다고 자부한다.

덕분에 잘 정의된 안정적인 업무 문화 속에서 편안히 일할 수 있었다고 생각한다.

 

 

회고 문화

솔직히 우리 팀을 가장 하나로 이끌어줬던 것은 매번 데모데이날마다 진행했던 회고 문화였던 것 같다.

내가 개인적으로 열심히 주장해서 만들어낸 문화였는데, 'KPT 방식을 통한 팀문화 회고'와 '좋아요/서운해요 회고를 통한 익명 팀원 회고'가 있었다.

이 시간만큼은 팀원들이 어느 때보다 솔직해질 수 있었으며 팀과 팀원들끼리 서로의 보완을 위해 열심히 피드백을 주고받았던 순간들이 기억에 남는다.

 

 

땅콩팀 코드 컨벤션 (일부)

코드 컨벤션도 개행부터, 매개변수까지 굉장히 세부적으로 잡아서 지키려고 노력했다.

일관성 있는 코드에 가독성이 따른다는 점에 모두가 공감했기 때문이다.

 

조금 더 세부적인 기록을 보고싶다면 여기 클릭

 

 


 

다양한 문제 상황을 마주하다..!

본격적으로 프로젝트가 시작되고 나서는 정말 많은 크고 작은 사건들이 발생했었다.

문제를 마주하고 해결하는 과정에서도 정말 많이 성장했던 것 같은데 그 기록들도 남겨보려고 한다.

 

 

Github Rebase로 인한 깃 대폭발 사건

Rebase에 대해 자세히 모르고 사용해서 발생했던 깃 대폭발 사건이 있었다.

우리는 이 사건을 '썬데이의 스노우볼' 사건이라고 부른다.. (사건번호는 다행히 3에서 멈췄다..)

 

Rebase Merge를 하게 되면 동일한 커밋 내용이어도 Merge 되는 브랜치의 '커밋 해시'와 Merge 시킨 브랜치의 '커밋 해시'가 상이해진다.

 

때문에 특정 커밋이 Rebase Merge로 Merge된 Develop 브랜치에서 현재 작업이 진행 중인 Feature 브랜치로 Rebase를 수행했을 때

이미 Develop에 반영이 되어있는 커밋Feature에서 Rebase 받은 커밋은 동일한 커밋이지만 서로 다른 커밋 해시를 가진다.

그렇기에 이러한 작업 이후에 Feature 브랜치에서 Develop으로 PR을 보내게 되면 커밋 해시 관련 오류가 발생한다.

 

 

이해를 위해 이미지를 준비했다.

예를 들어 A -> B 라는 커밋이 이미 Develop 브랜치에 반영되어, 현재 상태가 'A'에서 'B'가 된 Dev 브랜치가 있다고 가정하자.

 

 

이때 A -> B 라는 내용을 가진 다른 커밋 해시의 커밋이 Dev 브랜치에 또 다시 올라가는 것이다.

이미 상태가 'B'인 코드에게 A -> B 요청을 보내면 당연히 상태는 'A'가 아니라 'B'이니 오류가 발생할 수 밖에 없다.

 

이러한 매커니즘으로 인해서 커밋 해시가 꼬여 깃 커밋 로그가 대폭발하는 사건이 발생하게 된다.

결국 어찌저찌 해결하고 Rebase에 대차게 당한 우리 팀은 Merge and Commit 방식을 반 강제로 애용하게 된다.

 

 

API Spec 변경 소통 미스로 인한 프론트엔드의 무한 디버깅 사건

백엔드 팀은 개발 환경에 배포된 내용에 대해서는 RestDocs를 활용해 테스트를 거쳐 문서화를 진행하기로 하였다.

하지만 문서가 변경될 때마다 프론트엔드가 알 방법이 없었고, 백엔드 팀에서 직접 프론트 팀원들에게 구두로 전달해주지 않으면 이를 인지할 수가 없다.

때문에 프론트엔드에서는 "이거 맞는데 왜 안되지 내 잘못인가ㅠㅠ" 해버리는 무한 디버깅 사태가 발생하는 문제가 이따금 있었다.

 

Discord Document Notificator

이러한 문제 해결을 위해서 Github Actions와 땅콩 팀의 협업툴 Discord를 활용하여 API 문서 변경 알림 시스템 구축을 수행하였다.

변경 사항을 빠르게 파악할 수 있도록 PR링크와 Docs 링크를 첨부하여 생산성 향상을 위해 노력했다.

(다만 알 수 없는 문제로 인해 PR 바로가기 링크가 안 만들어지고 있다. 이 문제는 최대한 빨리 해결해보려고 한다.)

 

 

Polling 과정에서 발생한 캐싱 관련 문제

버스정류장 디버깅

프론트엔드의 기술 스택인 React에서 Polling을 통해 흭득한 데이터를 어떠한 저장소에 캐싱해버려서 문제가 된 적도 있었다.

가볍게 설명하자면 API 요청에 대한 응답값과 React에서 어딘가에 캐싱해둔 값이 꼬여, 프론트에서 이상한 값을 가지고 비즈니스 로직을 수행하는 오류였다.

 

이 문제 때문에 게임 진행이 정상적으로 동작하지 않았고 다같이 우테코 문 닫는 시간인 11시까지 집에 가지 못했다..

밖에 나가서도 버스 정류장에 걸터앉아 문제 해결책을 찾아나섰던 추억도 있다..ㅎ

 

처음 문제가 발생한 시점에는 백엔드 문제인 줄 알았는데, 결국 프론트엔트 팀에서 문제가 캐싱 때문이라는 것을 알게 되어 캐싱을 끄는 방법을 찾아 문제를 해결하였다.

(데모데이 전날 밤이어서 심장이 너무 쫄깃했다...)

 

 

방 입장 로직에서 발생한 동시성 문제

게임 방에 입장하는 로직에서 동시성 문제도 발생했다.

 

땅콩 서비스를 QA하는 과정에서 방의 최대 인원 제한인 12명 중 11명이 방에 접속해 있는 경우, 동시에 입장 요청이 발생한다면 방의 최대 인원은 12명임에도 불구하고 13명 이상의 유저가 접속되는 동시성 문제를 발견하였다.

 

문제 해결을 위해서 synchronized, 낙관적 락 방식 등 다양한 동시성 처리 방법을 비교하며 문제해결을 시도하였고

결론적으로 '비관적 락(X-Lock)' 을 통해 문제를 해결할 수 있었다.

 

@Transactional
public RoomJoinResponse joinRoom(String nickname, String uuid) {
	Room room = roomService.getRoomWithLock(uuid);
	Member member = memberService.saveCommonMember(nickname, room);
	return new RoomJoinResponse(room.getId(), room.getUuid(), new MemberResponse(member));
}

방 입장 로직은 가장 먼저 요청을 통해 전달받은 roomId 를 통해 Room을 조회한다.

이때 roomId를 가진 Room 테이블의 레코드에 비관적 락(X-Lock)을 걸어 트랜잭션이 종료될 때까지 다른 트랜잭션에서 해당 roomId를 가진 레코드에 접근을 막았다.

이를 통해 방 입장 로직이 순차적으로 동작할 수 있게 되었고, 동시성 문제를 해결할 수 있었다.

 

@Test
void 최대_인원보다_많은_인원이_방에_접속할_수_없다() {
	// given
	Room room = roomRepository.save(Room.createNewRoom());
	memberRepository.save(PRIN.master(room));
	for (int i = 0; i < 10; i++) {
		memberRepository.save(EDEN.common(room, i));
	}

	// when
	Thread t1 = new Thread(() -> roomFacade.joinRoom("t1member", room.getUuid()));
	Thread t2 = new Thread(() -> roomFacade.joinRoom("t2member", room.getUuid()));
	t1.start();
	t2.start();

	try {
		t1.join();
		t2.join();
	} catch (InterruptedException ignored) {
	}

	Room foundRoom = roomRepository.findById(room.getId()).orElseThrow();
	long memberCountInRoom = memberRepository.countByRoom(foundRoom);

	// then
	assertThat(memberCountInRoom).isEqualTo(12);
}

문제 해결을 정확히 검증하기 위해 Thread 활용한 동시성 테스트를 작성하여 문제가 확실히 해결되었는지 검증하기도 했던 재미난 경험이었다.

 

 


 

팀원들과 스터디

 

레벨 인터뷰 스터디

저번 기수 우테코에서는 매 레벨마다 레벨 인터뷰라는 것이 존재했다.

레벨 인터뷰는 크루원들끼리 서로 돌아가며 인터뷰이, 인터뷰어가 되어 레벨동안 학습한 내용에 대해서 인터뷰 형식으로 설명하는 과정이다.

이 레벨 인터뷰가 메타인지에 큰 도움이 될 것이라는 생각에 꼭 경험하고 싶었지만, 이번 기수는 레벨 1,2에 레벨 인터뷰를 진행하지 않았기 때문에 개인적으로 아쉬웠다.

그래서 뜻이 맞는 크루원들을 모아 레벨 인터뷰 스터디를 진행하게 되었다.

 

Java, Spring에 대해서 깊이있게 공부하고 2주마다 학습한 내용을 바탕으로 서로 인터뷰이, 인터뷰어가 되어 면접을 진행하는 스터디였다.

해당 스터디를 바탕으로 면접에 대한 두려움을 없애고 메타인지를 기르는 것을 목표로 하였다.

(실제로 이 스터디 덕분에 면접 분위기를 즐길 줄 알게 되었으며 많은 메타인지를 기를 수 있어 너무나 유익한 스터디였다. 강추!)

 

자세한 내용과 진행 방식이 궁금한 사람은 이 Github Discussion을 확인하면 된다.

 

 

Real MySQL 8.0 스터디

프로젝트 팀원들과는 우리가 선택한 MySQL DB를 더욱 이해도있게 다루기 위해서 Real MySQL 8.0 탐구 스터디를 진행하였다.

줄여서 '리마탐(리얼마이에스큐엘 탐구)' 라고 불렀는데 이 스터디를 통해 MySQL의 동작원리를 이해하고 프로젝트에 효율적으로 녹여낼 수 있는 방법을 배우는 걸 목표로 하였다.

실제로 이 책을 통해 얻은 흰트로 User 설정, Index 설정, Lock에 대한 지식 습득 후 동시성 문제 처리 등 프로젝트에서 많은 도움을 받았다.

자세한 내용과 진행 방식이 궁금한 사람은 이 Github Repository를 확인하면 된다.

 

 


 

레벨 인터뷰

레벨인터뷰

레벨3에서는 우테코에 들어와서 너무나 원하던 레벨인터뷰를 진행하게 되었다.

 

레벨3 프로젝트에서 진행한 내용들을 PDF로 정리하여 배정된 팀원들에게 전달하고, 서로 인터뷰이/인터뷰어가 된 팀원들은 서로에 대한 질문과 응답을 준비하여 인터뷰를 진행할 수 있었다.

 

레벨 인터뷰 스터디와 더불어 매번 고민하고 문제를 해결하던 습관을 바탕으로 질문들에 대해서 조리있게 설명해나갔다.

 

 

내가 받은 피드백

레벨인터뷰 피드백

팀원들이 인터뷰 피드백도 너무 착실하게 작성해주어서 의미있는 시간을 보낼 수 있었다.

내가 생각하고 학습하고 적용했던 내용들을 최대한 녹여내보려고 했으나, 아쉽게 놓친 부분들도 있었지만 최선을 다했고 괜찮은 피드백들을 받을 수 있었다.

 

부정적인 피드백들은 따로 정리하여 더욱 깊이있게 채우고, 긍정적인 피드백도 정리하여 강점으로 만들기 위해 노력할 예정이다.

 

 


 

처음으로 사용자를 만나다

 

우테코의 데모데이

우테코는 데모데이라는 것이 존재하는데, 레벨3는 1차~4차 데모데이까지 존재한다.

1차~3차는 코치님들에게 프로젝트 진척 상황에 대해 발표하는 것이고 4차 데모데이는 우테코 크루원들끼리 서로 서비스를 사용해보고 피드백하는 시간이다.

 

우리가 만든 '땅콩'이 처음으로 사용자를 만나는 너무나 소중한 시간이라는 뜻이다.

 

 

데모데이 준비(1)

이 시간을 통해 잠재적 유저들인 크루원들에게 서비스를 '잘' 선보이기 위해 정말 열심히 준비했다.

밤 늦게까지 남아 회의하고 QA하던 기억이 새록새록 하다.

우리팀은 데모데이 전날마다 매번 야근을 했던 것 같다.

그땐 너무 힘들었는데 지나고보니 너무나 소중하고 따듯했던 기억들 뿐이다.

 

 

데모데이(2)

결론적으로 엄청난 호평을 받고 마무리된 땅콩의 4차 데모데이!

생각보다 훨씬 긍정적인 유저반응을 얻고 너무나 행복해던 하루였다.

회고를 적으며 되돌아보니 나와 우리팀에게는 이 날이 레벨3에서의 유종의 미를 거두는 가장 소중하고 행복한 순간이었던 것 같다.

 

 

땅콩 1차 MVP 개발 완료!

서비스 피드백

고심하여 개발한 서비스에 대해 좋은 피드백받고 하루종일 감정이 부풀어올랐던 것 같다.

이 날은 개발자로 진로를 결정한 이후 가장 의미있던 날 중 하나라고 자부한다.

피드백 정리하며 팀원들과 회고하는 과정에서도 서로 너무 벅차올라서 땅콩의 미래에 대해서 뜨거운 토론을 주고 받았다.

잠도 제대로 못자서 너무 피곤하고 힘들었는데, 그것도 잊고 엄청나게 떠들고 회식까지 즐겨버렸다..! (사실 이러다 회식때 잠들어서 사진찍혔다;)

 

 


 

사소한 행복들 🥜

우테코 후드티 수령..!

이젠 나도 정말 엄연한 우테코 사람.

우테코 근로에서 고생해서 만들어준 후드티를 드디어 수령했다..! 너무 맘에 들어서 자주 입고 있었다 ㅋㅋ

 

 

타칸의 코로나..

타칸의 코로나 대소동

우리의 소중한 팀원 타칸이 코로나에 걸려서 다같이 코찌른 날이다.

재미난 추억 중 하나다.

 

 

지각하면 커피 문화

팀원들의 7회 지각 적립으로 만들어진 커피 7잔..

우리 팀은 재미난 문화가 있다. 바로 '지각하면 커피' 문화인데

 

 

땅콩팀 커피 문화

이렇게 지각할 때마다 1개씩 적립해서 7번 지각자가 발생하면 커피 타임이 발생한다 ㅋㅋㅋ

 

 

나도 이 커피 타임의 대주주 중 하나였는데, 프린과 내가 모든 커피의 절반을 샀다고 해도 과언이 아니다..

정신 차리고 살아야겠다. (죄송합니다 우리팀 ㅎㅎ..)

 

 


 

마치며

레벨1,2가 각자의 개발적 가치관을 쌓아가는 시기라면 레벨3는 쌓아올린 것들을 바탕으로 팀원들을 설득하고 이를 통해 함께 성장해나가는 뜻깊은 시간으로 느껴졌다.

개발자로서의 성장뿐만 아니라 사람으로서, 팀원으로서의 성장도 팀원들과 시간을 보내며 정말 많이 이룰 수 있었다.

너무 좋은 우리 팀원들 프린,타칸,커찬,마루,썬데이,포메 와 함께한 덕분에 시간가는 줄 모르고 보냈던 레벨3였다.

 

또 개발자 인생 처음으로 만난 서비스의 유저들로부터 긍정적인 피드백을 받으며 마무리한 레벨3는 레벨4에 대한 기대감을 한껏 끌어올려주었던 것 같다.

이전엔 잘 짜여진 코드와 잘 동작하는 프로그램을 보며 재미를 느꼈다면, 요즘은 내가 만든 서비스를 통해 유저가 가치를 느꼈을 때가 가장 재미와 보람을 느끼게 되었다.

 

더운 여름 함께 고생한 우리 땅콩팀 수고 많았고, 레벨4,5 그리고 우테코 수료 이후에도 계속 즐겁게 달려나갔으면 좋겠다:)