분류 전체보기 7

인덱스 설계부터 EXPLAIN 분석까지: 쿼리 성능 개선 기록

목차 1.1 인덱스란?데이터베이스에서 인덱스(Index)란 특정 컬럼의 값을 정렬된 순서로 별도 저장해 두는 자료구조입니다.책의 색인(목차)을 떠올려 보면 이해하기 쉽습니다. 두꺼운 책에서 특정 용어를 찾을 때, 처음 페이지부터 끝까지 훑는 대신 색인 페이지에서 해당 용어를 찾고 바로 해당 페이지로 이동하죠. 데이터베이스 인덱스도 동일한 원리입니다. 전체 테이블을 풀 스캔(Full Scan)하지 않고, 인덱스를 통해 원하는 데이터의 위치로 빠르게 이동할 수 있습니다.인덱스의 내부 구조인덱스는 실제 데이터를 복제해서 저장하지 않습니다. 대신, 인덱스의 끝에는 실제 데이터가 저장된 디스크 주소(포인터)만을 보관합니다.[인덱스 구조 예시 - 이름 컬럼 기준]인덱스 (정렬된 키 + 포인터) ..

Tech 2026.03.13

WIL - 4주차 [동시성 이슈 해결을 위한 락 설계와 테스트]

🧠 이번 주에 새로 배운 것- 낙관적 락(@Version) vs 비관적 락(SELECT FOR UPDATE) 선택 기준 - 동시성 윈도우(Race Condition Window) 개념과 이중 방어 패턴 - 원자적 UPDATE(@Modifying + WHERE 조건)로 쿠폰 사용 처리 - CountDownLatch로 실제 Race Condition을 재현하는 테스트 작성법 - Application Layer vs Domain Layer 책임 분리 (OrderApplicationService, LikeApplicationService) 💭 이런 고민이 있었어요- 쿠폰 발급에서 existsByUserIdAndCouponTemplateId() 체크 후 save() 사이 동시성 윈도우 문제 - 낙관적/비관적 ..

WIL 2026.03.08

장바구니 동시성 테스트에서 배운 것: 중요한 건 성공 횟수가 아니었다

목차 낙관적 락 테스트에서 잘못 세운 기대값장바구니에 동일 상품을 담을 때 수량을 누적시키는 기능을 구현하면서, 낙관적 락을 적용한 동시성 테스트를 작성했습니다.처음에는 “동시에 100번 요청하면 딱 1건만 성공해야 한다”고 생각했고, 그에 맞춰 assertion도 작성했습니다.그런데 실제 결과는 전혀 다르게 나왔습니다.성공 건수가 1이 아니라 여러 건으로 나타났고, 그 순간 제가 낙관적 락의 동작 방식과 테스트의 기대값을 서로 다르게 이해하고 있었다는 점을 깨달았습니다.이번 글에서는 그 시행착오를 정리해 보려고 합니다.특히 왜 아래와 같은 assertion이 낙관적 락 테스트에 자연스럽지 않았는지,// 동시에 100번 요청하면 1건만 성공해야 한다.assertThat(result.successCo..

Tech 2026.03.06

WIL - 2주차 [유연한 설계를 위한 덜어내기의 기술]

🧠 이번 주에 새로 배운 것시퀀스 다이어그램의 적정 수준: 설계 단계에서 API 명세나 SQL 쿼리 같은 세부 구현에 매몰되면 오히려 전체 흐름을 놓칠 수 있다는 걸 배웠습니다. 추상화 단계를 높여 "어떤 기능이 어떤 흐름으로 이어지는지"를 명확히 정의하는 것이 설계의 핵심임을 깨달았습니다.동시성 제어 전략의 트레이드 오프: 재고 차감처럼 데이터의 정확성이 생명인 도메인에서는 처리량(Throughput)을 조금 포기하더라도 비관적 락(Pessimistic Lock)이 더 안전한 선택지가 될 수 있음을 학습했습니다. 💭 이런 고민이 있었어요낙관적 락 vs 비관적 락: 충돌이 잦을 것으로 예상되는 주문 도메인에서 SELECT FOR UPDATE를 활용한 비관적 락을 선택했습니다.데드락(Deadlock) ..

WIL 2026.02.13

버스는 이미 떠났다: 지도 앱의 ‘실시간’은 진짜 실시간일까?

목차 TL;DR지도 앱의 실시간은 연동이 아니라 연출이다! 들어가며“1분 뒤 도착이라 했는데, 왜 안 오지”? 혹은 “곧 도착이라 했는데, 왜 이미 지나갔지?”지도 앱을 쓰며 누구나 한 번쯤 품어봤을 의문입니다.오늘도 어김없이 출근을 하기 위해 지도 앱을 켜고 대중교통을 기다리던 와중, 근본적인 궁금증이 들었습니다.지도 앱의 ‘실시간’은 정말 실시간일까?오늘은 이 간극 속에 숨겨진 데이터 파이프라인에 대해 얘기해보고자 합니다.1. ’실시간‘의 정의: 우리가 속고 있는 걸까?실제 흐르는 시간과 같은 시간. (표준국어대사전) 사전적 의미의 실시간은 '오차 없는 동시성'을 뜻하지만, 기술의 세계에선 조금 다릅니다. 물리적 지연(Latency)이 존재하는 한, 완벽한 실시간은 불가능하기 때문이죠. 따..

Tech 2026.02.13

WIL - 1주차 [Mock을 쓰는 법을 다시 생각하다]

🧠 이번 주에 새로 배운 것테스트를 Unit / Integration / E2E 세 단계로 나눠서 작성하니, 각 테스트가 검증하는 책임 범위가 훨씬 명확해진다는 걸 체감했습니다.UnitMockito를 사용해 UserService의 비즈니스 로직만을 독립적으로 검증IntegrationTestContainers(MySQL)를 활용해 Spring Context와 JPA Repository를 함께 띄우고, 실제 DB 연동까지 포함한 영속석 계층 통합 검증E2ETestRestTemplate으로 애플리케이션을 실제로 실행한 뒤, HTTP 요청부터 인증 필터/인터셉터를 거쳐 응답이 반환되기까지의 전체 흐름 검증PasswordPolicy처럼 검증 로직을 별도 객체로 분리하니, 정책 변경 시 서비스 코드를 건드리지 않..

WIL 2026.02.06

테스트 더블을 사용하면 테스트 성능도 더블로 올라갈까?

목차 들어가며: “테스트가 나를 괴롭히기 시작했다”처음 테스트 코드를 작성했을 때, 테스트의 개수가 늘어나는 것만으로도 마냥 뿌듯했습니다.초록색 체크 표시✅가 늘어날수록 제 코드가 안전하다고 말해주는 것 같았거든요.그런데 어느 순간부터 테스트가 저의 발목을 잡기 시작했습니다.로직은 그대로인데 리팩터링만 하면 테스트가 우수수 깨지고,verify()가 줄줄이 달린 테스트 코드는 읽기도, 고치기도 어려웠으며,무엇보다 “이 테스트로 무엇을 검증하고 싶은 거지?” 라는 의문이 계속 들었습니다.문제는 테스트 더블(Test Double)을 쓰는 방식에 있었습니다.특히 Mock을 너무 많이 쓴 것과 검증 포인트를 잘못 잡은 것이 가장 큰 원인이었습니다. 이 글은 제가 테스트 코드를 작성하면서 부딪힌 시행착오를 바탕으로..

Tech 2026.02.05