1월 31일부터 10주간 달렸던 루프팩 백엔드 3기가 끝난 지 일주일이 됐다.
지인 추천으로 들어갔다. 패X 재직자 부트캠프도 들어봤던 4년차 개발자가 왜 또 부트캠프냐는 질문을 몇 번 받았는데, 다 듣고 난 지금은 짧게 답할 수 있다. 1도 후회하지 않는다.
리뷰를 쓰려니 한 가지가 걸렸다. 루퍼스 후기를 찾아본 사람이라면 알겠지만 칭찬이 많다. 나도 처음엔 좀 의심했다. 그래서 이 글은 감상보다 기록에 가깝게, 주차별로 내 코드와 생각이 어떻게 바뀌었는지 남기려고 한다.

수강 전과 수강 후, 내 머릿속이 바뀐 자리들


트랜잭션 경계: "묶는 게 안전"에서 "나누는 게 안전"으로
수강 전의 나는 주문 취소 로직을 한 트랜잭션에 다 묶어 놓고 있었다. 재고 복구, 쿠폰 복원, PG 환불까지. 그래야 안전하다고 생각했다.
문제는 PG가 5초 타임아웃을 내는 순간이었다. 재고와 쿠폰 복구까지 같이 롤백된다. 외부 시스템 하나가 내 비즈니스 로직 전체를 인질로 잡는 구조였다.

수강 후에는 코드를 짜기 전에 먼저 나눈다. 실패해도 되는 것과, 반드시 같이 성공해야 하는 것을.

@EventListener
public void handle(OrderCancelledEvent event) {
    restoreStock(event);
    restoreCoupon(event);
}

@TransactionalEventListener(phase = AFTER_COMMIT)
public void handle(OrderCancelledEvent event) {
    refundPaymentUseCase.refundPayment(event.orderId());
}



이렇게 나누고 나니 PG가 10초간 먹통이어도 주문 취소는 정상적으로 끝난다. 재고와 쿠폰은 정확히 돌아오고, 환불은 나중에 재시도하면 된다. 자세한 과정은 

[7주차 글]에 적어뒀다.


성능 개선에도 순서가 있다


조회가 느리다는 얘기를 들으면 나는 늘 캐시부터 떠올렸다. 그게 제일 빠른 카드인 줄 알았다.

5주차 과제에서 10만 건 상품 데이터를 실제로 만져보며 생각이 바뀌었다. 길부터 닦고, 짐을 줄이고, 그 다음에 지름길을 뚫는다. 먼저 인덱스, 쿼리 플랜부터 본다. 그 다음이 비정규화, 정말 매 요청마다 조인이 필요한지 다시 본다. 캐시는 마지막이다.

지금은 캐시를 꺼내기 전에 먼저 의심부터 한다. 자세한 수치는 [5주차 글]에 있다.

"실시간으로 할 수 있다"와 "실시간으로 해야 한다"는 다르다



9주차에 Redis ZSET으로 일간 랭킹을 만들었다. 10주차에 주간, 월간 랭킹이 과제로 나왔을 때 처음 든 생각은 단순했다. `ZUNIONSTORE`로 7일치, 30일치 합치면 되는 거 아닌가.


하지만 "이번 주 인기 상품"에 3초 전 좋아요가 반영되지 않아도 아무도 모른다.

경영진 리포트에 초 단위 실시간성이 필요한 경우는 드물다.

 

일간은 Redis 실시간으로, 주간·월간은 Spring Batch와 Materialized View로 분리하면서 배운 가장 큰 감각이 이거였다.
이 주차가 수강 전과 수강 후를 가장 크게 가른 지점이라, 다음 섹션에서 따로 적는다.


가장 인상 깊었던 프로젝트 — 랭킹 시스템 설계 (9~10주차)

여러 주차가 좋았지만 9~10주차의 랭킹 시스템 설계를 꼽고 싶다. 이유는 세 가지다.

첫째, 과제가 "기능 구현"이 아니라 "설계 판단"이었다. 랭킹의 본질은 정렬이 아니라 "어떤 시간 범위의 이벤트를 어떤 가중치로 합산할 것인가"라는 정책이었다. 같은 도메인인데 일간과 주간·월간의 요구사항이 다르다는 걸, 실제로 구현하면서 체감했다.

둘째, 한 번 잘못된 인터페이스를 잡았다가 되돌리는 경험을 했다. 처음엔 "랭킹"이라는 이름 하나로 모든 걸 풀려고 했는데, 실시간 로직과 배치 로직이 같이 들어가면서 인터페이스가 뚱뚱해졌다. ISP(Interface Segregation Principle)를 교과서가 아니라 내 손으로 확인한 순간이었다.

셋째, 우아한형제들 기술블로그의 한 문장이 과제 한복판에서 떠올랐다. *"실시간으로 처리할 수 있다고 해서 실시간으로 처리해야 하는 것은 아니다."* 이 문장을 이해하는 것과, 이 문장대로 코드를 짜고 시스템을 분리하는 건 완전히 다른 일이었다. 루퍼스는 이 간극을 직접 좁혀보게 해줬다.

4기를 고민 중이시라면, 이런 "기술을 쓸지 말지 판단하는 훈련"을 한다는 점에서 추천하고 싶다. 전체 과정은 [9주차][10주차] 글에 있다.


강의와 멘토링에서 좋았던 점

솔직히 커리큘럼 그 자체보다 멘토링 시간이 더 컸다.

멘토님들이 여러 관점에서 적극적으로 질문을 던져주시는데, 그때마다 놀랐다. 내가 이만큼 생각할 때 누군가는 완전히 다른 시야에서 이런 질문을 할 수 있구나. 답을 얻은 것보다 질문을 받아본 경험 자체가 더 오래 남는다.
그러고 나니 코드를 짤 때 두 가지가 자동으로 돌아가기 시작했다. 하나는 "이 선택의 반대편엔 뭘 포기한 거지"라는 trade-off. 다른 하나는 "이 비즈니스가 뭘 원하는지"부터 다시 보는 도메인 감각. 위에 적은 Before/After 세 가지도 실은 이 두 습관의 결과물이다.

강의는 강의대로 좋았다. 6주차 PG 장애 복구, 8주차 선착순 주문 10만 명 — 이런 주제를 교재 수준이 아니라 진짜 장애 상황에서 돈이 맞는 코드를 목표로 다룬다.

[6주차]와 [8주차] 글에 기록해뒀다.

그래도 단점은 있다

후기 글에 단점이 없으면 광고가 되어버리니까, 몇 가지 적어둔다.
회사가 바쁠 때는 잠을 줄여야 한다. 업무 바쁜 주와 과제 마감이 겹치면 수면 시간이 연료가 된다. 재직자로 들어오시는 분은 이 각오가 필요하다.
멘토링 시간이 겹치면 다른 멘토님 세션을 놓친다. 멘토마다 보는 시야가 다른데, 내 시간대와 겹친 분의 관점은 그대로 못 챙기게 된다. 이 부분이 개인적으로 제일 아쉬웠다.
그래도 남는다. 위에 적은 Before/After 세 가지와 질문하는 습관이 내 것으로 남았으니까.

마지막으로

AI로 코드를 생성하는 시대라고 개발자 사이의 간격이 좁혀지진 않는다. AI는 답은 잘 하지만 질문은 잘 하지 못한다. 어느 트랜잭션 경계에서 끊을지, 언제 실시간을 포기할지, 어느 순서로 성능을 풀지 — 결국 질문은 사람의 몫이다.
루퍼스 10주는 그 질문을 조금 더 정확히 던질 수 있게 된 시간이었다. 시작할 때 있던 동기 중 약 96%가 끝까지 남았다. 그 이유가 이 글 어딘가에 있었으면 좋겠다.
3기 여러분 고생하셨고, 4기를 고민 중이신 분들께 이 글이 참고가 되었으면 한다.




복사했습니다!