Skip to content
295 changes: 295 additions & 0 deletions .docs/week10/design-notes.md

Large diffs are not rendered by default.

1,359 changes: 1,359 additions & 0 deletions .docs/week10/implementation_plan.md

Large diffs are not rendered by default.

237 changes: 237 additions & 0 deletions .docs/week10/learning-point.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
## 🧭 루프팩 BE L2 - Round 10

> 서비스에서 다양한 가치를 창출하기 위해 대량의 데이터를 모으고, 쌓고, 압착해야 합니다. 데이터의 규모가 커지면, 점점 이런 작업들을 웹 애플리케이션 내에서 처리하는 것에 대한 부하가 가파르게 높아집니다.

그래서 우리는 마지막으로 `spring-batch` 애플리케이션을 만들어 볼 거예요. 이를 기반으로 일간 랭킹 뿐 아닌 주간, 월간 랭킹 또한 집계를 활용해 만들어 봅시다.
>

<aside>
🎯

**Summary**

</aside>

지난 라운드에서 Kafka Consumer 와 Redis ZSET 을 활용해 메세지를 압착해 처리량을 높이는 테크닉, 특정 점수 기준의 정렬 SET 활용 방법을 학습하고 실시간으로 갱신되는 일단위 랭킹을 만들어보았습니다.

이번 라운드에서는 Spring Batch 를 이용해 주간, 월간 랭킹을 구현합니다. **Batch** 는 일간 집계를 기반으로 주간, 월간 집계를 만들어내고 **API** 는 일간 랭킹 뿐 아니라 주간, 월간 랭킹도 제공합니다.

<aside>
📌

**Keywords**

</aside>

- Spring Batch (Job / Step / Chunk / Tasklet)
- ItemReader / ItemProcessor / ItemWriter
- Materialized View (사전 집계)
- 실시간 처리 vs 배치 처리

<aside>
🧠

**Learning**

</aside>

## 🧮 Bacth System

<aside>
💡

**Batch Processing** 이 왜 필요할까요? 한번 예

- **대규모 집계**
- 수억 건 데이터에 대한 합산, 평균, 통계는 실시간으로 처리하기엔 비용이 너무 크다.
- e.g. "지난 한 달간 상품별 매출 TOP 100" → 매 요청마다 계산하면 DB/Redis 부하로 서비스 전체가 흔들림
- **운영 리포트/통계**
- 경영진 보고용, BI 툴, 월간 정산 등은 수 초 단위의 실시간성이 필요하지 않음
- 정확성과 대량처리가 더 중요 → 하루 한 번 배치로 계산해도 충분
- **데이터 정제 및 적재**
- 로그 수집 → 정제 → DW 적재 같은 과정은 실시간보다는 일정 주기 단위로 몰아서 처리하는 게 효율적
</aside>

### 🎞️ 실무에서 자주 보는 배치 시나리오

- **주문 정산**
- 주문/결제/환불 데이터를 모아 매일 새벽 3시 정산 테이블 생성.
- PG사 매출/정산 금액 검증도 함께.
- **랭킹/통계 적재**
- 일간/주간/월간 인기 상품 집계
- 카테고리별 판매량 통계
- **데이터 정리/청소**
- 만료된 쿠폰 삭제, 오래된 로그 제거, 캐시 초기화
- **데이터 웨어하우스(DW) 적재**
- 서비스 DB → DW(BigQuery, Redshift 등) 로 적재 후 분석

### ⚖️ 실시간 vs 배치 트레이드오프

| 항목 | 실시간 처리 | 배치 처리 |
| --- | --- | --- |
| 장점 | 즉각 반영 → UX 좋음 | 대규모 집계, 비용 효율적 |
| 단점 | 인프라 복잡, 멱등성 관리 필요 | 지연 발생, 실시간성 부족 |
| 적합 | 좋아요 수, 실시간 랭킹 | 월간 리포트, 대시보드, BI |
| 초점 | **신속성** | **정확성 & 효율성** |

---

## 🏗️ Spring Batch

### 💧 **기본 구성 요소**

- **Job** : 배치 실행 단위 (예: “일간 주문 통계 Job”)
- **Step** : Job 을 구성하는 세부 단계

### 📌 배치 처리 모델

**Chunk-Oriented Processing**

- 데이터 읽기 (Reader) → 가공 (Processor) → 저장 (Writer)
- 청크 단위로 트랜잭션이 관리됨 → 안정적 대량 처리

```java
@Bean
public Step orderStatsStep(
JobRepository jobRepository,
PlatformTransactionManager txManager,
ItemReader<Order> reader,
ItemProcessor<Order, OrderStat> processor,
ItemWriter<OrderStat> writer
) {
return new StepBuilder("orderStatsStep", jobRepository)
.<Order, OrderStat>chunk(1000, txManager)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
}
```

**장점**

- 대규모 집계/정산/데이터 변환에 적합
- 트랜잭션 단위 조절 가능

---

**Tasklet**

- Step = 하나의 작업(Task) 실행
- 반복 구조 없음, 단발성 작업에 적합

```java
@Bean
public Step cleanupStep(
JobRepository jobRepository,
PlatformTransactionManager txManager
) {
return new StepBuilder("cleanupStep", jobRepository)
.tasklet((contribution, chunkContext) -> {
orderRepository.deleteOldOrders(); // 만료 주문 삭제
return RepeatStatus.FINISHED;
}, txManager)
.build();
}
```

**장점**

- 간단한 SQL 실행, 파일 이동, 캐시 초기화 등에 적합
- Reader/Processor/Writer 필요 없는 작업에 깔끔

> *일반적으로 **구현의 용이성** 등을 이유로 Tasklet 내에서 로직 상으로 Chunk Oriented Processing 을 구현하기도 합니다.*
>

---

### 🗼 Materialized View

<aside>
💡

**다시 돌아왔다, Materialized View**

이전에 **Join 한계를 극복하기 위한 조회 전용 구조**로서 `Materialized View` 에 대해 언급되었던 적이 있었습니다.

이번엔 **복잡한 집계 쿼리를 극복하기 위한 조회 전용 구조**로서 `Materialized View` 를 만나볼 거예요.

</aside>

- **복잡한 집계 쿼리를 미리 계산해둔 조회 전용 구조**
- MySQL 은 MV 기능이 별도로 없으므로 보통 **별도 테이블 + 배치 적재** 방식 사용
- 주기적으로 대규모 데이터 (각 상품의 일별 일간 집계) 를 주기적으로 집계해 활용

```sql
CREATE TABLE product_metrics_weekly ( // 주간 상품 이벤트 집계
product_id BIGINT PRIMARY KEY,
like_count INT,
order_count INT,
view_count INT,
yearMonthWeek VARCHAR, // 예시입니다.
updated_at DATETIME
);

CREATE TABLE product_metrics_monthly ( // 주간 상품 이벤트 집계
product_id BIGINT PRIMARY KEY,
like_count INT,
order_count INT,
view_count INT,
yearMonth VARCHAR, // 예시입니다.
updated_at DATETIME
);
```

---

### 🎯 운영 관점에서의 배치 전략

- **스케줄링** : Spring Scheduler, Quartz 혹은 인프라 (Cron + K8s)
- **재실행 전략** : 실패 시 부분 롤백 vs 전체 재실행
- **병렬 Step** : 여러 Step 을 동시에 실행해 성능 향상
- **모니터링** : 실행 로그, 실패 알림, 처리 건수 추적

---

<aside>
📚

**References**

</aside>

| 구분 | 링크 |
| --- | --- |
| 🔍 Spring Batch | [Spring Docs - Spring Batch](https://docs.spring.io/spring-batch/reference/) |
| ⚙ Spring Boot with Spring Batch | [Baeldung - Spring Boot with Spring Batch](https://www.baeldung.com/spring-boot-spring-batch) |
| 📖 Materialized View | [AWS - What is Materialized View](https://aws.amazon.com/ko/what-is/materialized-view/) |

<aside>
🌟

**Mentor’s Message**

</aside>

이번 10주 동안 우리는 **단순한 CRUD를 넘어서, 실제 서비스에서 마주치는 문제들을 단계적으로 풀어왔습니다**. 현업에서 여러분들이 활약하기 위해 어떤 것들을 알면 좋을지, 문제를 접근하고 해석하는 방법, 문제에 맞는 적절한 해답을 도출하는 방법 등을 전달하려고 노력했어요.

- **1~3주차** : 도메인 모델링, 계층 분리, 객체 협력 설계
- **4~6주차** : 트랜잭션과 동시성, 읽기 최적화, 외부 시스템(결제 PG) 연동과 회복 탄력성
- **7주차** : 이벤트 와 Kafka, 유량제어
- **8주차** : 대기열 큐
- **9주차** : 실시간 집계, 랭킹 시스템 구축
- **10주차** : 배치와 Materialized View를 통한 대규모 집계와 조회 최적화

즉, **이커머스라는 시나리오를 통해 → 설계 → 동시성 → 성능 → 회복력 → 이벤트 → 확장성 → 데이터 파이프라인 → 집계** 까지, 실무에서 다루는 거의 모든 챕터를 작은 스케일로 경험해 본 셈입니다.

하지만 여기서 끝이 아닙니다.

- 실제 서비스는 **더 많은 데이터와 트래픽, 더 복잡한 요구사항** 속에서 움직입니다.
- 새로운 기능을 추가할 때마다, 이번 과정에서 배운 **Trade-off와 선택의 기준**이 반복해서 필요합니다.
- 이직, 프로젝트, 사이드 개발 등 어떤 길을 가더라도, 지금 경험한 **문제 정의 → 분석 → 해결** 과정은 계속해서 쓰이게 될 것이고 힘이 되어줄 겁니다.



이제는 여러분이 스스로 문제를 정의하고, 배운 도구와 방법을 적용하며, 더 깊은 학습으로 나아갈 차례입니다.

루프팩 BE L2는 끝났지만, **여러분의 성장 여정은 여기서부터가 시작**입니다.
120 changes: 120 additions & 0 deletions .docs/week10/quests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# 📝 Round 10 Quests

---

## 💻 Implementation Quest

> 이번에는 Spring Batch 를 활용해 주간, 월간 랭킹을 제공해 볼 거예요.
이전에 적재했던 `product_metrics` 와 같은 일간 집계정보를 기반으로 **주간, 월간 랭킹 시스템을 구축**해봅니다.
>

<aside>
🎯

**Must-Have (이번 주에 무조건 가져가야 좋을 것-**무조건 ****하세요**)**

- Spring Batch
- Batch Processing
- Materialized View (Statistics)
</aside>

### 📋 과제 정보

이번 주는 대규모 데이터 집계 및 조회 전용 구조에 대한 설계를 진행해 봅니다.

### (1) Spring Batch Job 구현

- 하루치 메트릭 테이블을 읽어 데이터를 집계하고 처리해봅니다.
- 대상 테이블 : `product_metrics`
- Chunk-Oriented 방식을 통해 대량의 데이터를 읽고 처리할 수 있도록 구성해 보세요.

### (2) Materialized View 설계

- 집계 결과를 조회 전용 테이블 (MV) 로 저장합니다.
- `mv_product_rank_weekly` : 주간 TOP 100 랭킹
- `mv_product_rank_monthly` : 월간 TOP 100 랭킹

### (3) Ranking API 확장

- 기존 Ranking 을 제공하는 GET `/api/v1/rankings?date=yyyyMMdd&size=20&page=1` 에서 기간 정보를 전달받아 API 로 일간, 주간, 월간 랭킹을 제공할 수 있도록 개선합니다.

---

## ✅ Checklist

### 🧱 Spring Batch

- [ ] Spring Batch Job 을 작성하고, 파라미터 기반으로 동작시킬 수 있다.
- [ ] Chunk Oriented Processing (Reader/Processor/Writer or Tasklet) 기반의 배치 처리를 구현했다.
- [ ] 집계 결과를 저장할 Materialized View 의 구조를 설계하고 올바르게 적재했다.

### 🧩 Ranking API

- [ ] API 가 일간, 주간, 월간 랭킹을 제공하며 조회해야 하는 형태에 따라 적절한 데이터를 기반으로 랭킹을 제공한다.

---

## ✍️ Technical Writing Quest

> 이번 주에 학습한 내용, 과제 진행을 되돌아보며
**"내가 어떤 판단을 하고 왜 그렇게 구현했는지"** 를 글로 정리해봅니다.
>
>
> **좋은 블로그 글은 내가 겪은 문제를, 타인도 공감할 수 있게 정리한 글입니다.**
>
> 이 글은 단순 과제가 아니라, **향후 이직에 도움이 될 수 있는 포트폴리오** 가 될 수 있어요.
>

### 📚 Technical Writing Guide

### ✅ 작성 기준

| 항목 | 설명 |
| --- | --- |
| **형식** | 블로그 |
| **길이** | 제한 없음, 단 꼭 **1줄 요약 (TL;DR)** 을 포함해 주세요 |
| **포인트** | “무엇을 했다” 보다 **“왜 그렇게 판단했는가”** 중심 |
| **예시 포함** | 코드 비교, 흐름도, 리팩토링 전후 예시 등 자유롭게 |
| **톤** | 실력은 보이지만, 자만하지 않고, **고민이 읽히는 글**예: “처음엔 mock으로 충분하다고 생각했지만, 나중에 fake로 교체하게 된 이유는…” |

---

### ✨ 좋은 톤은 이런 느낌이에요

> 내가 겪은 실전적 고민을 다른 개발자도 공감할 수 있게 풀어내자
>

| 특징 | 예시 |
| --- | --- |
| 🤔 내 언어로 설명한 개념 | Stub과 Mock의 차이를 이번 주문 테스트에서 처음 실감했다 |
| 💭 판단 흐름이 드러나는 글 | 처음엔 도메인을 나누지 않았는데, 테스트가 어려워지며 분리했다 |
| 📐 정보 나열보다 인사이트 중심 | 테스트는 작성했지만, 구조는 만족스럽지 않다. 다음엔… |

### ❌ 피해야 할 스타일

| 예시 | 이유 |
| --- | --- |
| 많이 부족했고, 반성합니다… | 회고가 아니라 일기처럼 보입니다 |
| Stub은 응답을 지정하고… | 내 생각이 아닌 요약문처럼 보입니다 |
| 테스트가 진리다 | 너무 단정적이거나 오만해 보입니다 |

### 🎯 Retrospective

- 단순히 “무엇을 했다”가 아니라, **10주 동안 어떻게 성장했는지**를 돌아본다.
- “기능 구현” 중심이 아니라, **사고방식/문제 해결/설계 선택 과정** 중심으로 기록한다.
- 이 글은 **개인 포트폴리오**이자, 앞으로 학습 방향을 스스로 점검하는 기준점이 된다.

### 담으면 좋은 내용

1. **전체 여정 요약**
- 1~10주차 동안 다뤘던 주요 테마 및 문제점들을 간단히 돌아보기
- 단순 나열이 아니라, **흐름이 어떻게 연결되었는지** 를 강조
2. **가장 큰 전환점**
- **내 기존의 사고방식이 바뀌었다** 싶은 순간
- *예: 4주차 트랜잭션/락을 통해 단순 @Transactional 이상의 고민을 알게 된 점, 7주차 이벤트 분리를 통해 ‘확장성’에 눈을 뜬 경험*
3. **나의 Trade-off 판단**
- 실습 중 내가 내린 중요한 선택 1~2개
- 왜 그 선택을 했고, 대안은 뭐였는지, 지금 다시 한다면 어떻게 할 건지
4. **실전과의 연결**
- “이건 실제 회사/서비스에서 써먹을 수 있겠다” 싶은 포인트
- *예: 캐시 무효화 전략, Kafka 기반 집계, Resilience4j 설정 등*
Loading