개요
TDD에서 시작해 설계, 도메인 모델링, 동시성 이슈, 조회 성능, 장애 내성, 이벤트 분리, 메시지 큐까지.
10주 동안 백엔드 개발 전반을 관통하는 흐름을 경험했다. 이 글을 쓰는 지금, 루프백 첫 수업을 들었던 나와 비교해보면 분명히 성장했다고 말할 수 있다.
단순히 코드를 잘 작성하는 사람이 아니라, 문제를 구조적으로 바라보고 선택의 이유를 설명할 수 있는 엔지니어로 나아가기 위한 출발점이 된 시간이었다.
전체 여정 요약
1~2주차: 기본기 다지기
1주차에는 TDD와 테스트 코드의 역할을 배웠다.
테스트 코드를 작성하는 것 자체는 어렵지 않지만, 좋은 테스트를 작성하는 일은 전혀 다른 문제라는 점을 체감했다.
좋은 테스트는 두 가지 기준을 만족해야 한다.
- 코드가 변경되었을 때, 의미 있는 실패를 하는 테스트
- 불필요한 구현 세부를 검증하지 않는 테스트
2주차에는 설계 문서를 작성하는 시간을 가졌다. 클래스 다이어그램, 시퀀스 다이어그램 등 다양한 문서를 통해 생각을 구조화하는 방법을 배웠다.
이제는 코드를 바로 작성하기보다 문서부터 만든다.
내 기억력을 신뢰하지 않기 위함이고, 무엇보다 동료와의 컨텍스트를 공유하기 위한 가장 확실한 방법이기 때문이다.
1~2주차는 본격적인 이커머스 프로젝트에 앞서 반드시 갖춰야 할 기초 역량을 다지는 시간이었다. 실무에서도 중요도가 매우 높은 영역이라는 점을 분명히 느꼈다.
3~5주차: 이커머스 도메인과 본격적인 고민
3주차부터 이커머스 프로젝트 구현이 시작됐다.
멘토님께서 “5주차까지의 내용을 잘 체화하면 주니어 백엔드 면접은 충분히 통과할 수 있다”고 하셨는데, 과제를 수행하며 그 말에 깊이 공감했다.
이 시점부터는 정답이 없는 문제를 다루는 시간이 많아졌다.
요구사항을 어떻게 해석할 것인지, 현재 서비스 규모에 적절한 도메인 모델은 무엇인지 스스로 결정해야 했다.
특히 도메인 모델링이 가장 어려웠다.
정답을 맞히는 것이 아니라, 선택의 근거를 설명할 수 있어야 한다는 점이 인상 깊었다. 그래서 생각을 정리하고, 다른 사람이 들어도 납득할 수 있는 논리를 만드는 데 집중했다.
동시성 문제 역시 항상 어려운 주제였다.
락 없이 해결하는 방법, read-modify-write 패턴을 피하는 방법, 피할 수 없다면 현재 상황에서 가장 합리적인 선택은 무엇인지 고민했다.
동시성 문제는 결국 트래픽 증가와 연결된다.
자연스럽게 조회 성능으로 이어졌고, 인덱스, 쿼리 튜닝, 테이블 설계, Materialized View, 캐싱이라는 여러 재료를 상황에 맞게 조합하는 법을 배웠다.
이때부터 트레이드오프를 의식하게 됐다.
대용량 트래픽 환경이라면 어떤 선택이 맞을지, 반대로 트래픽이 적은 환경에서 이것이 과한 설계는 아닐지 스스로 질문하는 시간이 많아졌다.
6~8주차: 확장성과 장애를 고려한 설계
주차가 지날수록, 회사와 서비스가 점진적으로 성장하며 트래픽이 늘어나는 상황을 가정한 기술들을 다뤘다.
멘토님의 말이 특히 기억에 남는다.
“대용량 트래픽 환경에서는 생존을 위해 MSA를 선택할 수밖에 없다.”
MSA 환경에서는 하나의 요청이 여러 서비스와의 협력을 통해 완성된다.
이 과정에서 장애는 반드시 발생한다는 전제를 가져야 했다.
외부 서비스에 장애가 발생했다고 해서 나까지 함께 죽을 필요는 없다.
서킷 브레이커를 통해 나는 살아남고, 상대 서비스가 회복할 시간을 벌어주는 것이 핵심이었다.
내부 이벤트 분리는 복잡한 도메인을 단순화하고 책임을 분리하는 데 큰 도움이 된다.
다만, 코드가 분산되며 가시성이 떨어질 수 있기 때문에 신중한 적용이 필요하다는 점도 함께 배웠다.
외부 API 호출이나 메시지 큐를 통한 이벤트 발행은 또 다른 고민을 만든다.
- 이벤트 유실이 허용되는가
- 허용되지 않는다면 어떻게 보장할 것인가
프로듀서는 최소 한 번 발행을 보장해야 하고, 컨슈머는 반드시 한 번만 처리되도록 멱등성을 보장해야 한다.
이벤트를 통해 한 서버가 담당하던 기능을 다른 서버로 위임할 수 있다.
“이 정보는 줄 테니, 필요한 곳에서 가져다 써. 그 이상은 관여하지 않을게.”
이런 느낌의 설계가 인상 깊었다.
9~10주차: 실전 수준의 요구사항
마지막 주차에서는 보다 심화된 요구사항을 다뤘다.
Redis ZSET을 활용한 실시간 랭킹 구현, Spring Batch를 이용한 주간·월간 랭킹 집계 배치 프로그램을 학습했다.
ZSET을 사용하면 랭킹을 비교적 간단하게 구현할 수 있다는 점이 흥미로웠고, 내부 동작 원리까지 살펴보며 이해를 넓혔다.
배치 프로그램은 멱등성이 필수이며, Spring Batch가 이를 위해 많은 편의 기능을 제공한다는 점도 체감했다.
이커머스에서 랭킹은 생각보다 복잡도가 높고, 고려해야 할 요소가 많다는 사실을 실감했다.
마침 실무에서도 Spring Batch를 활용한 마이그레이션 업무를 맡고 있었는데, 현실에서 고민하던 문제를 멘토링을 통해 학습할 수 있었다는 점이 특히 의미 있었다.
가장 큰 전환점이 되었던 주차들
2주차: 문서화에 대한 인식의 변화
그동안 문서를 만들지 않고 개발을 해왔다.
기능 동작에 대한 문의가 들어오면 과거에 작성한 코드를 다시 훑어보며 설명해야 했고, 주석조차 남기지 않았던 스스로를 후회한 적도 많았다. 이런 일이 반복됐지만, 문서를 만들지 않았던 이유는 단순했다. 귀찮았기 때문이다.
2주차 수업을 통해 문서의 중요성을 여실히 깨닫게 되었다.
멘토님들은 개발 과정에서 문서 작성에 80%, 구현에 20%의 시간을 쓴다고 말씀하셨다. 협업 인원이 많아질수록 문서의 가치는 기하급수적으로 커진다는 의미로 받아들였다.
과제에서는 유저 시나리오 기반 기능 정의서, 클래스 다이어그램, 시퀀스 다이어그램, ERD를 작성했다. 이 과정에서 자연스럽게 이런 고민이 생겼다.
“지금 실무에서 팀을 진짜로 뒷받침해 줄 문서는 무엇일까?”
궁금증을 더 해소하기 위해 존경하는 개발자 유튜브에 질문을 남겼다.
https://www.youtube.com/watch?v=4k84WWFhly0
강조하신 핵심은 명확했다.
문서는 많을수록 좋은 것이 아니라, 관리 비용을 고려해 수를 제한하고 항상 최신 상태를 유지하는 것이 중요하다는 점이었다. 또한 실무에서 필요한 문서로 다음을 언급하셨다.
- 요구사항 정의서 및 정책서
- 개념도
- 시스템 다이어그램
- API 문서
결국 어떤 문서를 만들 것인지는 팀 내 논의를 통해 합의하는 과정 자체가 중요하다는 결론에 이르렀다.
개인적으로 정리한 기준은 다음과 같다.
- 항상 필수로 작성할 문서
- 요구사항 정의서 및 정책서
- 클래스 다이어그램
- ERD
- API 문서
- 상황에 따라 선택적으로 작성할 문서
- 상태 다이어그램
- 배치 다이어그램
- 인프라를 포함한 시스템 아키텍처 다이어그램
이후로는 개발을 시작할 때 구현부터 서두르지 않는다.
먼저 문서 초안을 만들고, 구현 과정에서 변경되는 내용을 실시간으로 반영한다. 당장은 번거롭지만, 미루지 않은 문서는 결국 미래의 나와 팀을 위한 자산이 된다는 것을 체감하고 있기 때문이다.
4주차: 동시성과 성능, 선택의 기준을 세우다
4주차에는 트랜잭션과 동시성 문제를 집중적으로 다뤘다. 연차가 쌓였음에도 이 주제를 다시 마주하며 “아직도 이걸 제대로 모르고 있었구나”라는 생각이 들었다. 하지만 스스로를 책망하기보다, 이번 기회에 애매하게 알고 있던 개념들을 확실히 정리하자는 태도로 접근했다.
동시성 문제는 ‘발생 지점’을 찾는 것부터 시작한다
동시성 문제는 코드 전체에서 발생하는 것이 아니라, read → modify → write가 일어나는 특정 지점에서 집중적으로 발생한다는 점을 명확히 인식하게 되었다.
그래서 가장 먼저 한 일은 다음 질문에 답하는 것이었다.
- 동시에 실행되면 문제가 되는 지점은 어디인가
- 이 충돌이 실제로 얼마나 자주 발생할 수 있는가
- 실패했을 때 비즈니스에 미치는 영향은 어느 정도인가
모든 위험 구간을 동일하게 다루는 것은 비효율적이다. 복잡한 로직에서 동시성 위험 구간이 여러 곳이라면, 비즈니스 중요도 · 충돌 빈도 · 실패 비용을 기준으로 우선순위를 나눠야 한다.
락 선택은 기술 문제가 아니라 관점의 문제
낙관적 락과 비관적 락은 서로 대체 관계가 아니라, 서로 다른 전제를 가진 도구라는 점이 인상 깊었다.
- 비관적 락: 실패를 원천적으로 막는 대신, 성능 비용을 감수
- 낙관적 락: 충돌이 드물다는 가정하에 성능을 우선
예를 들어, 금전과 직결된 영역이라면 비즈니스 관점에서 정합성 보장이 최우선이 되기 때문에 비관적 락이 더 적절할 수 있다.
반대로 충돌 가능성이 낮고 재시도가 가능한 영역이라면, 기술적 관점에서 낙관적 락이 충분히 합리적인 선택이 된다.
또한 하나의 트랜잭션 안에서도 락 전략을 혼재해서 사용할 수 있다는 점도 배웠다. 실패 가능성이 높은 구간을 먼저 실행해 불필요한 후속 작업을 줄이는 방식 역시 중요한 최적화 포인트였다.
락 없이 해결하는 선택지들
동시성 문제를 해결하는 방법이 반드시 락에 국한되지는 않았다.
DB 레벨의 UNIQUE 제약을 활용하면, 명시적인 락 없이도 중복 삽입을 효과적으로 방지할 수 있다. 이는 의도를 가장 명확하게 드러내는 동시성 제어 방법이기도 하다.
또한 MySQL의 INSERT IGNORE, SKIP LOCKED 같은 기능을 활용하면 전체 락이 아닌 최소한의 락으로 문제를 해결하는 전략도 가능하다.
멘토님들은 전반적으로 lock-free한 접근을 선호하셨고, 메시지 큐 기반 이벤트 처리로 동시성 문제를 구조적으로 분리하는 방식을 자주 강조하셨다.
현실적인 선택과 기준
현재 팀의 상황을 돌아보면, 메시지 큐를 도입할 만큼 트래픽이 높거나 도메인이 복잡하지는 않다. 그래서 현시점에서 고려 가능한 선택지는 다음과 같다고 정리했다.
- 비관적 락
- 낙관적 락
- 분산 락
- read-modify-write 패턴을 제거하는 테이블 설계
- DB 기능을 활용한 최소화된 락 전략
중요한 것은 어떤 방법을 쓰느냐가 아니라, 왜 이 방법을 선택했는지를 명확하게 설명할 수 있는가였다.
4주차를 통해 동시성 문제를 “무서운 예외 상황”이 아니라, 전제와 트레이드오프를 인식하고 다루는 설계 문제로 바라보게 되었다.
5주차: 조회 성능, 빠르게 만드는 것보다 ‘덜 읽게 만드는 것’
5주차에는 인덱스와 캐싱을 중심으로 조회 성능을 학습했다.
단순히 쿼리를 빠르게 만드는 것이 아니라, DB가 일을 덜 하게 만드는 관점으로 사고가 전환되는 계기였다.
인덱스: 존재 여부보다 ‘효율’
인덱스는 무조건 많을수록 좋은 것이 아니었다.
특히 데이터 편향도가 높은 컬럼은 인덱스를 걸어도 기대한 효과를 얻지 못할 수 있다.
예를 들어 like_count처럼 대부분의 값이 0, 1, 2에 몰려 있는 컬럼에 단일 인덱스를 생성하면, 읽기 성능 개선 효과는 거의 없고 쓰기 시 인덱스 유지 비용만 증가할 수 있다. 이 경우 운영 중 인덱스를 제거하는 판단 또한 충분히 합리적인 선택이 된다.
또한 인덱스를 볼 때 컬럼 단위가 아니라 쿼리 단위로 사고해야 한다는 점을 배웠다.
- 정렬(ORDER BY)과 조건(WHERE)을 함께 만족하는 인덱스인가
- 드라이빙 테이블과 드리븐 테이블이 의도대로 선택되었는가
- 실행 계획에서 Using filesort, Using temporary가 발생하지는 않는가
이를 확인하기 위해 실행 계획을 해석하는 연습이 필수적이라는 점을 체감했다. 필요하다면 쿼리 힌트를 통해 옵티마이저의 선택을 유도하는 것도 하나의 도구임을 알게 되었다.
쿼리 튜닝: SQL 한 줄이 아니라 접근 방식의 문제
조회 성능 문제는 단순히 SQL을 예쁘게 고치는 것으로 해결되지 않았다.
JOIN 순서, 서브쿼리 분해 여부, 불필요한 컬럼 조회 제거 등 접근 방식 자체를 바꾸는 것이 더 큰 효과를 주는 경우가 많았다.
특히 “정말 이 데이터를 실시간으로 계산해야 하는가?”라는 질문이 중요했다.
자주 조회되지만 변경 빈도가 낮은 데이터라면, 실시간 계산보다 사전 집계 테이블이나 통계 테이블이 더 적합할 수 있다.
이 과정에서 Materialized View 개념을 자연스럽게 이해하게 되었고, 조회 성능은 결국 쓰기 비용과의 트레이드오프라는 점도 명확해졌다.
캐싱: 어디에, 무엇을, 얼마나
캐싱 역시 처음에는 막연했다. 하지만 애플리케이션 내부 캐시와 외부 캐시를 혼합해서 사용하는 구조를 학습하며 관점이 달라졌다.
- JVM 내부 캐시는 빠르지만 인스턴스 간 정합성 문제가 있다
- 외부 캐시는 네트워크를 타지만 공유가 가능하고 확장성이 있다
이 특성을 이해한 뒤, 데이터 성격에 따라 캐시 위치를 다르게 가져가는 전략이 가능해졌다.
또한 멘토님이 소개해주신 캐시를 쪼개는 전략도 인상 깊었다. 하나의 거대한 캐시 키가 아니라, 목적과 변경 주기에 따라 캐시를 분리하면
부분 무효화가 가능해지고 운영 리스크도 줄일 수 있다.
캐싱을 적용할 때는 항상 다음 질문을 함께 해야 했다.
- 이 데이터는 언제 변경되는가
- 변경 시 즉시 반영되어야 하는가, 지연되어도 괜찮은가
- Evict는 언제, 어떤 트리거로 발생시키는가
- 캐시 키 변경 시 버저닝은 어떻게 가져갈 것인가
이 질문들에 대한 답 없이 캐시를 도입하면, 성능 개선보다 장애를 만드는 지름길이 될 수 있다는 점을 배웠다.
조회 성능의 본질
5주차를 통해 얻은 가장 큰 깨달음은 이것이다. 조회 성능은 특정 기술 하나로 해결되지 않는다.
인덱스, 쿼리, 캐싱, 테이블 설계는 모두 연결되어 있고, 현재 트래픽 규모와 서비스 특성에 맞는 조합을 선택하는 문제다.
앞으로 조회 성능 문제가 발생했을 때, “일단 캐시부터 넣자”가 아니라 어디에서 비용이 발생하고 있는지를 구조적으로 파악하는 개발자가 되고자 한다.
실전과의 연결
루퍼스에서 배운 내용을 실무에 적용하기 위한 계획은 다음과 같다.
- 6주차에 학습한 Failure-Ready 시스템을 기반으로 BFF에 서킷 브레이커 적용
- API 처리 시간이 300ms 이상인 요청을 분석하고, 인덱스·캐싱·테이블 설계 개선
- 상황에 맞는 캐시 적재 및 무효화 전략 설계·적용
- 설계 문서가 없거나 미비한 영역에 대한 문서 보완 및 신규 작성
- Spring Batch를 활용한 DB 마이그레이션에서 정합성·속도·안전성 확보
- 유연한 도메인 모델링과 이벤트 분리를 통한 점진적 리팩터링
단순히 “알고 있다”에서 끝내지 않고, 실제 코드와 시스템에 반영하는 것을 목표로 한다.
마치며
10주 동안 정말 많은 것을 배웠다. 하지만 배운 지식이 아직 완전히 내 것이 되었다고 생각하지는 않는다.
복습하고, 실무에 적용하고, 누구에게나 설명할 수 있을 정도로 체화되었을 때 비로소 내 것이 된다고 믿는다.
이번 과정을 통해 스스로 가장 크게 성장했다고 느낀 지점은 다음과 같다.
첫째, 생각하는 힘이 자라났다.
단순히 구현만 하는 개발자에서 벗어나, 앞뒤 맥락과 팀의 상황을 고려하며 최선의 선택을 고민하는 사람으로 바뀌었다. 무엇을 만들 것인가보다, 왜 이렇게 만들어야 하는가를 끊임없이 질문하게 되었다.
둘째, 학습의 방향성과 태도를 알게 되었다.
단순한 input 위주의 학습이 아니라, output을 통해 내 것으로 만드는 과정이 중요하다는 것을 체감했다. 특히 이번 과정에서 블로그에 글을 작성하고 AI를 적극적으로 활용하며, 이론 학습과 코드 작성 모두에서 사고의 폭이 넓어지는 경험을 했다. 잘 활용한다면 강력한 학습 도구가 될 수 있다는 확신도 생겼다.
셋째, 개발이 재미있어졌고, 할 수 있다는 자신감을 얻었다.
과제를 수행하며 RT(Rising Talent)를 받았을 때의 희열은 쉽게 잊히지 않는다. “나도 하면 된다”는 감각과 함께, 개발의 재미를 한층 더 깊이 느낄 수 있었다.
마지막으로, 혼자서 공부하는 데에는 분명한 한계가 있다는 점도 깨닫게 되었다.
다른 사람들이 먼저 고민한 내용을 듣고, 나와 다른 관점의 생각을 접하며 부족함을 느끼는 동시에 그것을 내 것으로 만들기 위해 노력했다. 과정은 끝났지만, 이 인연을 계속 이어가며 서로 긍정적인 자극을 주고 함께 성장하고 싶다는 바람이 생겼다.
과정이 끝나기 직전, 멘토님의 말이 오래 남는다.
“루프백 10주 과정은 끝났지만, 루퍼스를 신청했던 목표를 위해 다시 10주차를 시작한다는 마음가짐으로 임해라.”
큰 목표를 조급하게 세우기보다는, 하루하루 성실하게 쌓아가다 보면 언젠가는 빛을 발할 것이라 믿는다.
그래서 오늘도, 다시 한 주차를 시작하는 마음으로 개발을 이어가려 한다.
루프백 3기 오픈
https://www.loopers.im/education
교육 과정 | Loop:Pak
Loop:Pak 부트캠프 교육 과정 상세 정보. NextNode Backend Edition을 포함한 전문 개발자 양성 커리큘럼과 현업 멘토링 프로그램을 만나보세요.
www.loopers.im
루퍼스 3기가 오픈되었습니다.
추천인 코드를 입력하면 할인가로 수강할 수 있습니다. 다만 결코 작은 금액은 아니기에, 신청 전 적지 않은 고민을 했는데요. AI 기술의 빠른 발전과 함께 연차가 쌓이면서, 스스로의 실력에 대한 의구심이 들던 시기였습니다.
며칠간 고민한 끝에 이번 기회를 마지막이라 생각하고 수강을 결정했습니다. 지금 돌이켜보면, 후회 없는 선택이었다고 자신 있게 말할 수 있습니다.
만약 저와 비슷한 고민을 하고 있거나, 루퍼스 과정에 대해 궁금한 점이 있다면 언제든지 편하게 연락 주셔도 좋습니다.
LinkedIn 또는 jikimee64@gmail.com으로 언제든 문의 부탁 드립니다. 감사합니다.
추천인 코드
TZFI0
'외부활동 > 루퍼스 2기' 카테고리의 다른 글
| 루퍼스 부트캠프 2기 수료 후기 (0) | 2026.01.17 |
|---|---|
| [Loop:PAK] 10주차 WIL (0) | 2025.12.29 |
| [Loop:PAK] 9주차 WIL (0) | 2025.12.21 |
| [루퍼스/루프백 2기] 이커머스 실시간 랭킹 구현기 - Redis ZSET부터 윈도우 설계 관점에서 콜드 스타트 해결까지 (0) | 2025.12.21 |
| [Loop:PAK] 8주차 WIL (0) | 2025.12.16 |