[개요]
2년전 여름, 개발자라는 직업에 대한 열정으로 5년간 일해오던 직장에서 퇴사를하고 비전공자들도 개발자가 될 수 있다는 여러 부트 캠프들을 알아보다가 항해99에서 운영하는 이노베이션 캠프에 참여하였다.
그냥 부트캠프여서 참여했다기 보다는, 일단 사전 과제를 내어 주고는, 해당 과제를 통과한 사람들에게 수강할 수 있는 기회를 준다는 점과 내가 몰입할 시간을 99일 준다는 점이 깔끔해서 마음에 들었다.
그렇게 새벽까지 (거의 울면서) 몰입하던 99일이 지나고, 그 이전에는 상상도 해보지도 못했던 개발자라는 직업을 가지게 되었다
어느덧 2년이라는 시간이 흐르고 백엔드 개발자로서 더 나은 역량 강화와 더 나은 개발자 공부라는 것은 무엇일까라는 고민이 쌓여가던 차에 항해99에서 이번에는 재직자를 대상으로 하는 성장 캠프를 운영한다고 해서 참여하게 되었다
나라는 사람은 역시 어느 정도의 강제성이 있어야 성장하기에, 나를 개발자로 이끌어준 항해99를 다시한번 믿어보기로 하였다
운명적이게도 마침 백엔드 기수가 마감하려던 시기였기에, 운좋게도 합류 하자마자 바로 주차를 시작하게되었다
[과제]
1주차의 과제는 이러했다.
* 어떤 사용자의 포인트 조회, 포인트 충전 및 사용, 포인트 충전 및 사용에 대한 목록 내역 조회 기능을 구현한다.
* 각 기능에 대한 단위 테스트를 작성한다.
* 포인트 충전과 사용에 대해 동시에 요청이 오더라도 순서대로 혹은 한 번에 하나의 요청씩만 제어될 수 있도록 구현한다.
* 동시성 제어에 대한 통합 테스트를 작성한다.
주제가 TDD였기 때문에, 스켈레톤 코드도 있겠다, 1주차니까 테스트 코드만 잘 구현하면 되는 거겠지? 라고 안일한 생각으로 과제를 열었으나... 문제는 동시성이었다.
[요구사항분석]
1. 단순하게도 동시성은 실무에서도 사용되는 Transaction으로 격리레벨을 조정하면 되지 않을까 생각했었지만,
해당 과제는 db단은 최대한 손대지 않고 서비스단에서 동시성 제어를 하는 것이 관건이었다
2. 동시에 여러 요청이 들어와도 순차적으로 처리되어야 한다는 데에만 집중해서 모든 요청이 들어와도 무조건 순차적으로 처리해야한다고 생각 으로 synchronized 를 사용하고자 하였다
3. 하지만 포인트 충전/사용 특성상 사용자A의 조회 요청이 사용자B가 먼저 충전중이라고 해서 대기상태에 들어가 있으면 안된다.
즉 유저 별 각각의 요청은 병렬로 처리되어야 하며, 동일한 유저의 요청은 순서대로 처리되어야 한다.
[과제 해결 과정]
시도1. `synchronized` 키워드 사용
- `synchronized`를 사용하여 동기화 처리하려고함.
- 문제 : 모든 요청이 직렬화되어, 다른 유저의 요청도 대기상태가 되어버림.
시도2. `ConcurrentHashMap`과 `ReentrantLock` 사용
- 유저별로 독립적인 락을 관리하여, 동일한 유저의 요청만 직렬화하고 다른 유저의 요청은 병렬로 처리.
- `ConcurrentHashMap`을 사용하여 유저 ID를 키로 하는 락을 관리.
최종 구현.
- `PointService` 클래스에서 `ConcurrentHashMap`을 통해 유저ID별 락을 관리.
- 포인트 충전 및 사용 요청에서 동일 유저ID의 요청은 락을 획득하여 처리. - 다른 유저의 요청은 락을 공유하지 않으므로 병렬로 처리 가능.
[알게된 것]
- Test Code의 중요성
> 쫄지말고 유닛테스트부터 쓰면 된다. 테스트를 거친 나의 작고 소중한 코드는 어디가서 맞고 돌아오진 않겠지 ..
- 동시성 제어에 대한 개념
> 아예 동시성이란 무엇인가에 대한 생각을 해볼 수 있어 좋았다. 실무에서 나를 괴롭히던 카프카 메세징 동시성 처리 이슈를 트러블 슈팅하기 전에도 이 부분에 대해서 더 생각해 보았으면 좋았을 걸이란 생각이 든다 .
- ConcurrentHashMap , ReentrantLock
> 사실 실무에서 Jvm 애플리케이션의 Lock에 대해 다루는 경우가 잘 없다보니, 이번에 처음 사용하면서 사용 방법이나 Lock의 종류들에 대해 배우게 되었다.
- 동시성 제어 테스트 CompletableFuture , CountDownLatch
> 앞으로 멀티스레딩 병렬 수행에 대해 기능을 구현해야 한다거나 테스트를 작성할 때 이 기능들을 활용해서 작성하면 되겠구나하는 부분들도 배우게 되었다.
이번주 KPT 회고
Keep : [유지해야 할 좋은 점]
- 상세한 주석 처리. 실무를 하면서도 느끼지만 이건 협업하는 다른 개발자를 위한 것이기도 하지만 미래의 나를 위해서도 좋은 습관이라고 생각한다.
Problem : [개선이 필요한 점]
- 아키텍처 구조에 대한 좀더 깊은 고민이 필요할 것 같다. 마침 다음 주차는 클린 아키텍처니까 좀더 생각해 볼 수 있는 계기가 될 것 같다.
- 과제 구현에만 급급해서 클린 코드와는 거리가 멀었다는 생각이 든다. 객체 지향, 클린코드를 좀더 생각하면서 짜야겠다
Try : [새롭게 시도할 점]
- 앞으로도 테스트 코드를 짜는 습관을 더 들여야겠다.
- 요구사항에 대한 개념정리를 조금더 빠르게 분석하는 습관을 들여야겠다
무사히 과제 2개 모두 PASS 하였다
혹시라도 완성했지만 FAIL이 날까봐서 조금은 전전긍긍했었는데, 그래도 내가 한 방향성이 틀리지 않았구나 싶어서 한숨 놓인다.
앞으로도 더 열심히 더 버텨보자 !
'🔔[항해99] > WIL' 카테고리의 다른 글
[항해플러스 백엔드후기] 2주차 회고 - 비관적 Lock도 락이다 (5) | 2024.12.28 |
---|---|
6주차 9/5~9/11 WIL (0) | 2022.09.11 |
5주차 8/29~9/4 WIL (0) | 2022.09.04 |
5주차 개인과제 - API / Client & Server / WAS , Web Server / HTTP 프로토콜 / Restful API (0) | 2022.08.27 |
4주차 8/21~8/28 WIL (0) | 2022.08.27 |