-
Notifications
You must be signed in to change notification settings - Fork 0
MySQL ‐ Operational‐Level System Design
1. Data Collection — 데이터가 발생하는 곳
- Web/App Server : 사용자가 앱에서 클릭·검색·결제 → 서버가 "클릭 이벤트" 발생한다.
- IoT Device: 센서가 온도·위치 값을 계속 측정해서 발생한다.
- Database CDC : DB에 주문이 INSERT되면 그 변경을 감지해 이벤트가 발생(CDC = Change Data Capture, "DB 바뀐 것 실시간 감지")한다.
2. Stream Storage — 일단 큐에 모임(Kafka)
- 발생한 이벤트를 곧바로 처리하지 않고 메시지 큐(Kafka)에 잠깐 쌓는다.
- 완충(버퍼) : 갑자기 트래픽이 폭주해도 큐가 받아내고, 뒷단은 자기 속도로 소비할 수 있다.
- 분리(디커플링) : 데이터 만드는 쪽과 처리하는 쪽이 서로 몰라도 됨 → 독립적으로 확장·교체 가능하다.
- 여러 소비자 : 같은 이벤트를 여러 시스템이 나눠 읽을 수 있다.
3. Stream Processing — 실시간으로 가공(Flink)
- 스트림 프로세서가 큐에서 이벤트를 도착하는 즉시 꺼내서 계산한다.
- 데이터가 오는 순간 바로 처리해서 지연이 초 단위이다.
4. Data Serving — 결과를 여러 곳에서 사용
- 가공한 결과를 필요한 곳으로 팬아웃(fan-out)한다.
즉, 여러 소스에서 끊임없이 발생한 데이터를 Kafka에 모아 완충하고 스트림 프로세서가 즉시 가공해서 대시보드·알림·ML·DW 등 여러 곳에 실시간으로 공급하는 구조를 만들 수 있다.
- 기존 배치는 스케줄러가 하나의
INSERT ... SELECT를 던지고, 스캔·그룹핑·집계·저장을 전부 운영 MySQL이 처리하는 구조다. - 데이터가 수천만 건일 때는 버티지만, 수억 ~ 수천억 건으로 늘면 세 갈래로 무너진다.
- 처리 시간 증가 : 단일 스레드·단일 노드로 전 구간을 순차 스캔·집계 → 데이터가 커질수록 배치 윈도우를 초과한다.
- DB 부하 → 서비스 영향 : 대량 스캔이 버퍼풀·I/O·CPU를 점유해 같은 DB를 쓰는 실서비스 응답이 함께 느려진다.
- 장애 대응의 어려움 : 한 트랜잭션으로 8시간 돌다 실패하면 처음부터. 재시작·부분복구·멱등성 보장이 어렵다.
해결 개념 - 연산을 DB 밖으로 위임한다
- DB에게 집계를 시키지 말고, 데이터만 병렬로 꺼내와 밖에서 나눠 계산한다.
- Spark가 이 문제에 주는 두 가지 실질 이점이 있다.
- 계산 위임 — GROUP BY·SUM 같은 무거운 연산을 MySQL이 아니라 Spark 클러스터가 수행한다.
- 병렬 데이터 로딩 — 하나의 큰 테이블을 order_id 범위로 쪼개 여러 Executor가 동시에 나눠 읽는다. 순차 스캔이 병렬 스캔으로 바뀐다.
1. 병렬 읽기용 뷰 정의
- MySQL의 orders를
partitionColumn기준으로 쪼개 여러 Executor가 동시에 읽도록 임시 뷰를 만든다. -
numPartitions만큼의 범위 쿼리가 병렬로 나간다.
CREATE OR REPLACE TEMPORARY VIEW orders_view
USING "jdbc" OPTIONS (
url "jdbc:mysql://mysql-server:3306/service_db",
dbtable "orders",
partitionColumn "order_id", -- 나눌 기준 (숫자·PK 권장)
lowerBound "1", -- 최소값
upperBound "100000000", -- 최대값
numPartitions "100" -- 100개로 분할 → 병렬 읽기
);
-- Executor 1 : WHERE order_id >= 1 AND order_id < 1000000
-- Executor 2 : WHERE order_id >= 1000000 AND order_id < 2000000
-- Executor 100: WHERE order_id >= 99000000 AND order_id <= 1000000002. 집계는 Spark 엔진이 수행한다.
- 이 쿼리는 더 이상 MySQL이 아니라 Spark 엔진이 인메모리로 실행한다.
-
WHERE created_at조건은Predicate Pushdown으로 읽기 단계에서 DB에 밀어넣어 스캔량을 줄이고,GROUP BY는 노드 간 셔플링을 거쳐 집계된다.
CREATE OR REPLACE TEMPORARY VIEW daily_summary AS
SELECT product_id,
SUM(sale_price * quantity) AS total_amount,
COUNT(*) AS total_count
FROM orders_view
WHERE created_at >= '2024-05-20 00:00:00'
AND created_at < '2024-05-21 00:00:00' -- ← Predicate Pushdown
GROUP BY product_id; -- ← Shuffle 발생3. 결과를 분석 DB에 저장한다.
- 집계 결과는 운영 DB가 아닌 별도의 분석용 DB에 적재해 서비스와 격리한다.
INSERT INTO analytics_db.daily_product_sales
SELECT * FROM daily_summary;1. 문제 : 하나의 변경, 여러 목적지
- Dual Write : 애플리케이션이 DB에 쓰고 또 Kafka에도 직접 쓴다. 두 쓰기는 한 트랜잭션이 아니라, 하나가 실패하면 시스템 간 데이터가 영구히 어긋난다.
- 주기적 배치 폴링 :
updated_at을 N분마다 훑기. 실시간이 아니고, 매 폴링이 운영 DB에 부하를 주며, 삭제(DELETE)는 감지조차 못 한다.
핵심 : 이미 정합성이 보장된 단 하나의 소스. DB의 트랜잭션 로그를 진실의 원천으로 삼는다.
1. Source — MySQL (Binlog)
- 모든 변경이 이미 binlog에 순서대로 기록된다.
- CDC의 전제 조건은 binlog_format=ROW 활성화이다.
2. CDC — Debezium Connector
- MySQL의 복제 슬레이브인 척
binlog를 구독해 변경을 표준 이벤트로 변환한다. - 애플리케이션은 이 존재를 모른다.
3. Streaming — Kafka Topic
- 변경 이벤트의 완충·보존·순서 보장 버퍼. 소비자가 잠시 죽어도 이벤트는 토픽에 남아 재생 가능하다.
4. Consumers
- 검색 · 분석 · 캐시 · 각자 독립적으로 같은 토픽을 구독한다.
- 소비자를 추가해도 생산 측은 전혀 바뀌지 않는다. 이것이 이벤트 브로커의 디커플링 이점이다.
왜 Kafka를 중간에 두나? - Debezium이 소비자에 직접 밀어주면, 소비자 하나가 느리면 전체가 막히고 재처리도 어렵다. Kafka가 이벤트를 보존하기에 소비자별 속도 차이·장애·나중 합류(replay)를 모두 흡수한다.
1. Debezium 동작 원리 — 스냅샷 → 스트리밍
- 커넥터가 처음 붙을 때 풀어야 하는 문제 : 지금까지 쌓인 데이터(과거)와 앞으로 바뀔 데이터(미래)를 빠짐도 중복도 없이 이어붙이는 것이다. 이 때, 순서가 핵심이다.
- 짧은 Lock으로 기준점 고정 : 아주 짧게
GLOBAL READ LOCK을 잡고 현재 binlog 위치를 저장한 뒤 즉시 해제한다. 이 시점이 과거와 미래의 경계선이 된다. - Lock 해제 후에도 변경은 안전 : 해제 순간부터의 변경은 그대로 binlog에 쌓이므로 유실되지 않는다. 그래서 Lock을 오래 잡을 필요가 없다(서비스 영향 최소).
- 초기 스냅샷 : 전건을 'c' 이벤트로 · 테이블 전체를 SELECT해 “현재 상태”를 Create 이벤트로 Kafka에 채운다. 소비자 입장에선 모든 행이 “새로 생성된” 것처럼 보인다.
- 저장한 위치부터 스트리밍 : 스냅샷이 끝나면 저장해둔 binlog 위치로 돌아가 'u'/'d' 이벤트를 순서대로 흘린다. 경계선 이후 것만 이어지므로 이중 반영이 없다.
최신 Debezium은 Lock을 더 줄인다. 위 흐름은 Lock 기반 스냅샷의 표준 모델이다. 실제로는 Incremental Snapshot(무Lock, 청크 단위 워터마크)으로 스냅샷과 스트리밍을 동시에 진행해 운영 부담을 더 낮추는 방식이 널리 쓰인다.
2. 변경 이벤트 메시지 구조
- Debezium의 이벤트는 “무엇이, 어떻게 바뀌었는지”를 담는 표준 envelope다. op는 연산 종류, before/after는 변경 전후 상태이다.
{
"op": "u", // c=create, u=update, d=delete, r=snapshot read
"ts_ms": 1721457600000,
"before": { "id": 42, "price": 1000, "status": "OPEN" },
"after": { "id": 42, "price": 1200, "status": "OPEN" },
"source": { "db": "service_db", "table": "orders",
"file": "binlog.000042", "pos": 15832 }
}- Kafka 메시지 Key = PK : 같은 레코드의 이벤트가 항상 같은 파티션으로 가도록 키를 PK로 둔다 → 그 레코드에 한해 순서가 보장된다.
- 삭제는 'd' + tombstone : Delete 이벤트 뒤에
value=null툼스톤을 보내, 키 기반 log compaction 토픽에서 실제로 지워지게 한다. - 'r' vs 'c' : 초기 스냅샷은 read(r), 실시간 생성은 create(c). 소비자는 대개 둘을 동일하게 “upsert”로 처리한다.
- 주의 1 : 순서 보장은 “파티션 단위”까지만. 전역 순서는 없다. PK를 파티션 키로 삼아 레코드별 순서를 확보하고, 전역 순서가 필요하면 파티션 1개(=처리량 희생)를 감수한다.
- 주의 2 : 멱등 소비자(Idempotent Consumer) : Kafka는 기본
at-least-once로 같은 이벤트가 재전송될 수 있다. 소비 측을 UPSERT·버전 비교로 멱등하게 만들어 중복을 무해화한다. - 주의 3 : Eventual Consistency 수용 : 소비자는 소스보다 항상 조금 뒤처진다. “강한 일관성”이 필요한 화면은 CDC 대상에서 제외하거나 소스를 직접 읽는다.
- 주의 4 : 스키마 진화 대비 · ALTER TABLE은 이벤트 스키마를 바꾼다. Schema Registry + 호환성 규칙(backward)으로 소비자가 깨지지 않게 한다.
- 주의 5 : 실패 격리 DLQ : 특정 이벤트가 소비 중 계속 실패하면 파이프라인 전체가 멈춘다. Dead Letter Queue로 밀어내 나머지를 계속 흐르게 하고 나중에 재처리한다.
- 주의 6 : Transaction Outbox로 Dual Write 봉쇄 : 애플리케이션이 이벤트를 발행해야 한다면, 비즈니스 데이터와 함께 outbox 테이블에 한 트랜잭션으로 넣고 그 테이블을 CDC로 흘린다.
- 주의 7 : 재적재(Backfill) 경로 확보 : 소비자 로직 변경·유실 시 스냅샷을 다시 태워 전량 재구성할 수 있어야 한다. Kafka 보존기간·compaction 정책을 이에 맞춰 설계한다.
1. 문제 : 동기 처리 안티패턴
- 회원가입이 부가 작업까지 전부 끝나야 응답한다. 사용자 저장은 빠르지만, 이메일·쿠폰은 외부 의존이라 느리고 불안정하다.
// Anti-pattern: Synchronous Processing
public void signUp(User user) {
userRepository.save(user); // 1. 빠름
emailService.sendWelcomeEmail(user.getEmail()); // 2. 느릴 수 있음
couponService.issueSignUpCoupon(user.getId()); // 3. 느릴 수 있음
// 4. 모든 작업이 끝나야 사용자에게 응답이 감
}핵심 : 핵심 로직만 즉시 처리하고, 나머지는 나중에 처리한다. 부가 작업을 Job으로 만들어 큐에 넣고, 응답은 바로 돌려준다.
DB를 큐로 쓴다.
- 메시지 브로커(Kafka·SQS) 없이 DB 테이블 하나로 큐를 구현하는 패턴으로 규모가 폭발하기 전까지 가장 실용적이다.
jobs 테이블 설계
- 테이블 하나가 큐이자 상태 저장소이자 감사 로그가 된다. 컬럼 하나하나가 특정 요구를 담당한다.
CREATE TABLE `jobs` (
`id` BIGINT AUTO_INCREMENT,
`job_type` VARCHAR(50) -- SEND_EMAIL, ISSUE_COUPON …
`payload` JSON, -- 작업에 필요한 데이터 (user_id 등)
`status` VARCHAR(20) DEFAULT 'PENDING', -- 생명주기
`priority` INT DEFAULT 100, -- 낮을수록 먼저
`retry_count` INT DEFAULT 0, -- 재시도 누적
`last_error_message` TEXT, -- 실패 진단
`run_at` DATETIME DEFAULT CURRENT_TIMESTAMP, -- 지연/백오프 예약
`created_at` DATETIME, `updated_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `idx_status_priority_runat` (`status`,`priority`,`run_at`)
);-
status: 잡의 생명주기를 한 컬럼에 압축한다. 워커 획득·재시도·완료 판단의 축이다. -
priority + run_at: 무엇을 먼저(우선순위), 언제부터(예약) 가져갈지 결정한다. 지연 작업과 백오프 재시도를 같은 메커니즘으로 처리한다. -
retry_count,last_error_message: 실패를 데이터로 남겨 백오프 계산과 사후 진단을 가능하게 한다. -
(status, priority, run_at)Multi Column Index : 워커 획득 쿼리의WHERE·ORDER BY를 그대로 커버 → 큐가 커져도 “다음 잡 찾기”가 인덱스로 빠르게 끝난다. 이 인덱스가 이 패턴의 심장이다.
등록 — 하나의 트랜잭션으로
- 핵심 데이터와 잡을 같은 트랜잭션에 넣는 것이 이 패턴의 정합성 보증이다. 커밋되면 둘 다, 롤백되면 둘 다 없다.
BEGIN;
-- 1. 핵심 비즈니스 로직
INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com');
SET @user_id = LAST_INSERT_ID();
-- 2. 비동기 작업 등록 (같은 트랜잭션)
INSERT INTO jobs (job_type, payload, priority)
VALUES ('SEND_WELCOME_EMAIL', JSON_OBJECT('user_id', @user_id), 100);
INSERT INTO jobs (job_type, payload, priority)
VALUES ('ISSUE_SIGNUP_COUPON', JSON_OBJECT('user_id', @user_id), 200);
COMMIT;획득 — 워커 경쟁을 SKIP LOCKED로
- 여러 워커가 같은 테이블을 동시에 노린다. 핵심은 한 잡을 정확히 한 워커만 집어가게 하는 것이다. MySQL 8.0의
FOR UPDATE SKIP LOCKED가 이를 락 대기 없이 해결한다.
BEGIN;
-- 처리할 잡을 찾아 배타적 락. 이미 잠긴 행은 건너뛴다.
SET @job_id = (
SELECT id FROM jobs
WHERE status = 'PENDING' AND run_at <= NOW()
ORDER BY priority ASC, id ASC
LIMIT 1
FOR UPDATE SKIP LOCKED -- ★ 다른 워커가 잡은 행은 스킵
);
IF @job_id IS NOT NULL THEN
UPDATE jobs SET status = 'RUNNING' WHERE id = @job_id;
END IF;
COMMIT; -- 락 해제. 이후 앱 코드가 실제 작업(이메일 발송 등)을 수행-
FOR UPDATE만 쓰면 : 뒤늦은 워커들이 잠긴 행을 기다리며 줄을 선다 → 사실상 직렬 처리, 병렬성 붕괴된다. 일반적인SELECT는 락을 보유하지 않지만SELECT ... FOR UPDATE는 락을 보유한다고 했다. -
SKIP LOCKED: 잠긴 행은 즉시 건너뛰고 다음 잡을 집는다 → 워커를 늘린 만큼 처리량이 선형에 가깝게 확장할 수 있다. -
run_at <= NOW(): 미래로 예약된 잡(지연·백오프)은 자동으로 제외된다. 예약과 큐잉이 한 쿼리에 집약된다.
핵심 : 중복 방지의 핵심은 원자성. “잡 선택 → RUNNING 표시”가 한 트랜잭션 안에서 락으로 보호되므로, 두 워커가 같은 잡을 RUNNING으로 만드는 경쟁이 불가능하다.
실패와 재시도 - 지수 백오프
- 일시적 실패(네트워크 순단 등)는 즉시 재시도하면 더 악화된다. 재시도 간격을 점점 벌리는 지수 백오프로 상대 시스템에 숨 쉴 틈을 준다.
-- 실패 처리 (의사 코드)
SET @new_retry_count = retry_count + 1;
SET @delay = POWER(10, @new_retry_count); -- 10, 100, 1000 … 초
UPDATE jobs
SET status = 'PENDING', -- 다시 큐로 (아직 죽이지 않음)
retry_count = @new_retry_count,
last_error_message = '...',
run_at = NOW() + INTERVAL @delay SECOND -- 다음 실행을 미래로
WHERE id = @job_id;-
status를PENDING으로 되돌린다 : 실패했다고 바로 버리지 않고 큐에 재투입한다. 단run_at을 미래로 밀어 바로 다시 잡히지 않게 한다. -
run_at이 백오프의 열쇠 : 워커 획득 쿼리의run_at <= NOW()덕분에, 지연이 끝나는 시점까지 이 잡은 자연히 무시된다. 별도 스케줄러가 필요 없다. - 한도를 넘으면
FAILED:retry_count가 상한을 넘으면FAILED로 확정하고 알림·수동 개입 대상(Dead Letter)으로 분리한다.
- 주의 1 : 멱등성은 필수. 이 큐는
at-least-once다. 워커가 작업 후DONE표시 직전에 죽으면 같은 잡이 재실행된다. 이메일 중복 발송을 막으려면 소비 로직 자체가 멱등해야 한다. - 주의 2 : 멈춘
RUNNING회수. 워커가RUNNING인 채로 크래시되면 그 잡은 영원히 갇힌다.updated_at이 오래된RUNNING을 주기적으로PENDING으로 되돌리는 리퍼(reaper)가 필요하다. - 주의 3 : 폴링 간격의 트레이드오프. 자주 폴링하면 지연이 발생하고 DB 부하가 증가한다. 지연에 민감하디면
SELECT ... SLEEP대신 알림(NOTIFY) 방식을 검토할 수 있다. - 주의 4 : 완료 잡 정리.
DONE이 쌓이면 테이블과 인덱스가 비대해진다. 아카이브 이관이나created_at기준 파티셔닝·주기 삭제로 관리하는 것을 권장한다. - 주의 5 : 우선순위 기아 주의. 높은 우선순위 잡이 계속 유입되면 낮은 잡이 영원히 밀린다. 대기 시간 가중치(aging) 등의 보정을 고려한다.
- 주의 6 : 처리량 상한을 알고 쓸 것. DB 큐는 초당 수백 ~ 수천 건 규모에 적합하다. 그 이상·다중 서비스 팬아웃이 필요해지면 Kafka·SQS로 이행하는 것이 자연스러운 다음 단계다.
1. 문제 — 하나의 DB로 모든 질의를 감당할 수 없다
- 관계형 DB는 트랜잭션과 정합성에 최적이다. 하지만 같은 데이터에 대한 요구는 제각각이다.
2. 해결 - 단일 진실 + 목적별 읽기 모델
- 두 개의 검증된 패턴을 결합한다.
- 각 NoSQL은 MySQL이 못하는 특정 질의를 대신한다. 선택 기준은 데이터 모델과 질의 형태가 된다.
- Code - Abstraction
- Code - Logic and the Flow of Thought
- [Code - The Object-Oriented Programming Paradigm]
- [Code - Applying Object-Oriented Programming]
- [Code - Refining Your Code]
- [Code - Refactoring Practice]
- [Code - Conditions for Better Memory]
- Java - Class
- Java - Java Memory
- Java ‐ Solving Concurrency Issues with Synchronized
- Java - synchronized
- Java ‐ Instance Variable & Local Variable vs final
- Java ‐ Object
- Java ‐ Immutable Object
- Java ‐ String
- Java ‐ Wrapper Class
- Java ‐ ENUM
- Java ‐ Nested Class & Inner Class & Local Class & Anonymous Class
- Java ‐ Generic
- Java ‐ ArrayList
- Java ‐ LinkedList
- Java ‐ List
- Java ‐ Set
- Java ‐ Hash
- Java ‐ HashSet
- Java ‐ Map & Stack & Queue
- Java ‐ Iterate & Sort
- Java - Process & Thread
- Java - Thread Creation & Execution
- Java - Thread Control & LifeCycle
- Java - Memory Visibility
- Java - Advanced Synchronization
- Java - Producer/Consumer Problem
- Java - Synchronization & Atomic Operation
- Java - Concurrent Collection
- Java - Thread Pool & Executor Framework
- Java - Character Encoding
- Java - I/O
- Java - File & Files
- Java - Reflection
- Java - Annotation
- Java - Lambda
- Java - Functional Interface
- Java - Lambda vs Anonymous Class
- Java - Method Reference
- Java - Stream API
- Java - Optional
- Java - Default Method
- Java - Parallel Stream
- Java - Functional Programming
- Java - JVM & GC & SOLID
- Java - Data Storage and Memory Allocation: Primitive vs. Reference
- Java ‐ Static Keyword: Efficient Resource Management at the Class Level
- Java ‐ OOP
- Java ‐ Collection Framework Selection Standard
- Java ‐ Multi Threading & Concurrent Programming
- Java ‐ Exception Handling & Advanced Java
- Java ‐ Java 8+
- Java ‐ Java Application Performance Tuning
- Java - CAS
- Java - Virtual Thread
- Java - Benchmark
- Kotlin - Variables, Types, and Operators in Kotlin
- Kotlin - Control Flow in Kotlin
- Kotlin - Object-Oriented Programming in Kotlin
- Kotlin - Functional Programming in Kotlin
- Kotlin - Key Features of Kotlin
- Kotlin - Generics in Kotlin
- Kotlin - Lazy Initialization and Delegation in Kotlin
- Kotlin - Advanced Functional Programming in Kotlin
- Kotlin - Operator Overloading and Kotlin DSL
- Kotlin - Annotations and Reflection in Kotlin
- Kotlin - Miscellaneous Topics in Kotlin
- Coroutine - Limitations of Thread-Based Work & the Emergence of Coroutines
- Coroutine - runBlocking
- Coroutine - CoroutineDispatcher
- Coroutine - Controlling Coroutines with Job
- Coroutine - Receiving Results from Coroutines
- Coroutine - Coroutine Context
- Coroutine - Structured Concurrency
- Coroutine - Exception Handling
- Coroutine - Suspended Functions
- Coroutine - Understanding Coroutines
- Coroutine - Advanced Coroutines
- Coroutine - Coroutine Testing
- Spring - OOP & Spring
- Spring - Spring Container & Spring Bean
- Spring - Singleton Container
- Spring - Dependency Injection
- Spring - Bean LifeCycle Callback
- Spring - Bean Scope
- Spring ‐ Web Server, Web Application server
- Spring ‐ Servlet
- Spring ‐ Servlet & JSP & MVC
- Spring ‐ MVC Framework
- Spring ‐ Spring MVC
- Spring - Thymeleaf
- Spring - Message & Internationalization
- Spring - Validation
- Spring - Bean Validation
- Spring - Cookie & Session
- Spring - Filter & Interceptor
- Spring - API Exception Handling
- Spring - Spring Type Converter
- Spring - File Upload
- Spring - Connection Pool & DataSource
- Spring - Transaction
- Spring ‐ Spring Exception Abstraction
- Spring - Database Access
- Spring ‐ Spring Transaction
- Spring ‐ Spring Transaction Propagation
- Spring ‐ Thread Local
- Spring ‐ Template Method Pattern & Callback Pattern
- Spring ‐ Dynamic Proxy
- Spring ‐ Spring Proxy
- Spring ‐ Bean Processor
- Spring ‐ @Aspect AOP
- Spring ‐ Spring AOP
- Spring ‐ Spring AOP Application
- Spring - MyBatis
- Spring ‐ URL Encoding
- Spring - Cache Annotation
- Spring - Retry
- Spring Security - Initialization
- Spring Security - Authentication Process
- Spring Security - Authentication Architecture
- Spring Security - Authentication Status Persistence Processing Mechanism
- Spring Security - Session Management
- Spring Security - Exception Handling
- Spring Security - Mechanisms for responding to Malicious Attacks
- Spring Security - Authorization Process
- Spring Security - Authorization Architecture
- Spring Security - Multiple Security Settings
- Spring Security - Redis Redundancy Settings
- Spring Security - Event
- Spring Security - Integration
- Spring Security - OAuth 2.0
- Spring Security - OAuth 2.0 Authorization Type
- Spring Security - Open ID Connect
- Spring Security - OAuth 2.0 Client
- Spring Security - OAuth 2.0 Client Fundamentals
- Spring Security - OAuth 2.0 oauth2Login
- Spring Security - OAuth 2.0 oauth2Client
- Spring Security - OAuth 2.0 Resource Server
- Spring Security - OAuth 2.0 Resource Server API
- Spring Security - OAuth 2.0 Verification
- Spring Security - OAuth 2.0 MAC & RSA Token Verification
- Spring Security - OAuth 2.0 Resource Server Permission Implementation
- Spring Security - OAuth 2.0 opaque()
- Spring Security - Authorization Server
- Spring Security - Authorization Server Main Domain Class
- Spring Security - Authorization Server Endpoint Protocol
- Spring Batch - Scheduler vs Batch
- Spring Batch - Batch Concept
- Spring Batch - Batch Domain
- Spring Batch - Job
- Spring Batch - Step
- Spring Batch - Flow
- Spring Batch - Chunk Process
- Spring Batch - ItemReader
- Spring Batch - ItemWriter
- Spring Batch - ItemProcessor
- Spring Batch - Retry & Error Handling
- Spring Batch - Multi Threads Processing
- [Spring Batch - Batch Event Listener]
- [Spring Batch - Batch Test]
- [Spring Batch - File Processing]
- [Spring Batch - Read and Write Operations in Relational Databases and NoSQL]
- [Spring Batch - FaultTolerant & ItemStream]
- [Spring Batch - Partitioning]
- Database - Database Introduction
- Database - Search & Sort
- Database - Data Processing
- Database - Aggregation & Grouping
- Database - Inner Join
- Database - Outer Join & Etc Join
- Database - Sub Query
- Database - UNION
- Database - CASE
- Database - Index
- Database - Data Integrity
- Database - Transaction
- Database - Why Database Design Matters
- Database - Concept Modeling
- Database - Logical Data Modeling
- Database - Identifying Relationship & Non-Identifying Relationship
- Database - Normalization
- Database - Physical Data Modeling
- Database - Common Code Design
- Database - Hierarchical Structure Design
- Database - Data Change History Design
- Database - SOFT DELETE
- Database - Statistics Table Design
- Database - Inheritance Relationship Design
- Database - Entity-Attribute-Value (EAV) Model
- Database - JSON Schema Design
- MySQL ‐ Solving Concurrency Problems using Database-Level Locking
- MySQL - Multi Column Index
- MySQL - Covering Index & RDB vs ElasticSearch Diff
- MySQL - ORDER BY
- MySQL - INSERT
- MySQL - AUTO_INCREMENT_LOCK
- MySQL - Index Dive Using In Query
- MySQL - Why don't use prefix index in default
- MySQL - MySQL LockType
- MySQL - DeadLock Case
- MySQL - NoOffset For Query Tuning
- MySQL ‐ Skip Locked for Session
- MySQL - Checking DB Metrics with SQL Queries
- MySQL - Data Modeling for Practical Service Development
- MySQL - Basic CRUD in MySQL
- MySQL ‐ MySQL Internal Architecture and Storage Engines
- MySQL - MySQL Horizontal Scaling
- MySQL ‐ Operational‐Level System Design
- MySQL - MySQL Fundamentals
- MySQL - Why You Should Use MySQL: JOIN
- MySQL - Must-Know SQL Anti-Patterns
- MySQL - Learning Data Modeling Through Practical Examples
- MySQL - Foreign Key & Strategic Patterns
- MySQL - Advanced Topics in MySQL
- Redis ‐ Redis
- Redis ‐ Redis Manual
- Redis ‐ Redis Cache Strategy
- Redis ‐ Redis Master-Slave
- Redis - Redis Cluster Mode
- Redis - Redis Cluster Example
- Redis - Redis Data Structure
- Redis - Redis pub/sub & streams
- Redis - Redis Server
- Redis - Reduce DB write load using Redis
- Redis - Solving Concurrency Issues (1)
- Redis ‐ Solving Concurrency Issues (2)
- Redis - Solving Concurrency Issues (3)
- Redis - Implementing Popular Searches
- Redis - API Rate Limiting
- Redis - Geospatial
- Redis - DAU Counting Application
- Redis - Session Management Application
- Redis - Redis Transaction ACID
- Redis - Redis Data Persistence
- Redis - Redis Keys Management
- Redis - Decoupling microservices with Redis Pub/Sub
- Redis - Redis Pipelining & RTT(Round Trip Time)
- Redis - Redis Streams
- Redis - Hash Slot Rebalancing
- JPA - Java Persistence API
- JPA - Entity Mapping & PK Strategy
- JPA ‐ JPA Association Mapping
- JPA - Proxy Association
- JPA - Value Type
- JPA - Dirty Checking vs. Merge: Understanding the Difference in JPA
- JPA - Cascading and Orphan Removal in JPA
- JPA - Introduction to Object-Oriented Query Languages in JPA
- JPA - Spring Data JPA
- JPA ‐ Solving Concurrency Issues with Pessimistic Locking
- JPA ‐ Solving Concurrency Issues with Optimistic Locking
- JPA - Lazy Loading and Performance Optimization in JPA
- JPA - ManyToOne Important Things
- JPA - OneToMany Important Things
- JPA - OSIV
- MicroService Architecture - Service Communications Patterns(RESTful API)
- MicroService Architecture - Service Communications Patterns(GraphQL)
- MicroService Architecture - Service Communications Patterns(gRPC)
- MicroService Architecture - API Gateway Patterns
- MicroService Architecture - Asynchronous Communications Patterns
- MicroService Architecture - Data Management Patterns
- MicroService Architecture - CQRS Patterns
- MicroService Architecture - Distributed Transactions
- [MicroService Architecture - Event-Driven Architecture]
- [MicroService Architecture - Resilience & Observability and Monitoring]
- [MicroService Architecture - Security Patterns]
- [MicroService Architecture - Testing Strategies]
- [MicroService Architecture - Scalability & Caching Patterns]
- [MicroService Architecture - Deployment Patterns]
- [MicroService Architecture - Serverless Architecture]
- [MicroService Architecture - GraphQL]
- [MicroService Architecture - Evolution of Distributed Systems and Their Drawbacks]
- [MicroService Architecture - Protocol Buffers]
- [MicroService Architecture - gRPC Communication Patterns]
- [MicroService Architecture - gRPC Optimization Strategies and Implementation]
- MicroService Architecture - 2PC
- MicroService Architecture - TCC
- MicroService Architecture - SAGA
- Apache Kafka - Kafka Introduction
- Apache Kafka - Kafka CLI
- Apache Kafka - Kafka Producer Application
- Apache Kafka - Kafka Consumer Application
- Apache Kafka - Idempotent Producer & Transactional Producer & Transactional Consumer
- Apache Kafka - Kafka Streams
- Apache Kafka - Kafka Topic/Producer/Consumer
- Apache Kafka - Producer Mechanism
- Apache Kafka - Consumer Mechanism
- Apache Kafka - Multi Node Kafka Cluster
- Apache Kafka - Producer & Consumer Serialization/DeSerialization
- Apache Kafka - Topic Segment Management
- Apache Kafka - KSQLDB Stream
- Apache Kafka - KSQLDB Table
- Apache Kafka - KSQLDB Application
- Apache Kafka - Group by & Mview
- [Apache Kafka - Join]
- [Apache Kafka - Time & Windows]
- [Apache Kafka - Connecting KSQLDB to Kafka Connect]
- [Apache Kafka - Kafka Connect]
- [Apache Kafka - JDBC Source Connector]
- [Apache Kafka - JDBC Sink Connector]
- [Apache Kafka - Debezium MySQL CDC Source Connector]
- [Apache Kafka - Schema Registry]
- Apache Kafka - Differences Between RocksDB and In-Memory KeyValueStore in GlobalKTable
- Apache Kafka - Kafka Streams
- [Apache Kafka - Kafka Connect]
- [Apache Kafka - Idempotent Producers and Transactional Producers & Consumers]
- [Apache Kafka - CDC(Change Data Capture)]
- [Apache Flink - Apache Flink Architecture]
- [Apache Flink - Stream Processing]
- [Apache Flink - Data Stream API & Window]
- [Apache Flink - State Management]
- HTTP - Internet Network
- HTTP - URI & Browser Request Flow
- HTTP - HTTP Basic
- HTTP - HTTP Method
- HTTP - HTTP Method Application
- HTTP - HTTP Status Code
- HTTP ‐ HTTP Default Header
- HTTP - HTTP Cache & Condition Request
- AWS - AWS CDK(Cloud Development Kit)
- AWS - Signed URL
- AWS - PreSigned URL
- AWS - Cognito
- AWS - Signed URL Logic
- Docker - Docker
- Docker ‐ Docker CLI
- Docker ‐ Docker Volume
- Docker - Dockerfile Image
- Docker ‐ Docker Compose Container Management
- Docker ‐ Deploy(feat. AWS ECR)
- Docker - Cloud Native Technology
- Docker - Docker Essentials(1)
- Docker - Docker Essentials(2)
- Docker - Docker Network and Storage
- Docker - Building and Managing Containerized Application
- Docker - Container Orchestration
- Docker - Docker Security
- Docker - Logging and Monitoring
- Docker - Advanced Docker Usage
- Docker - Container-to-Container Communication
- [Docker - Docker Image Layer를 활용한 Cache 패턴과 Dangling Image]
- [Docker - Dockerfile 최적화를 위한 빌드 캐싱 및 멀티 스테이지 빌드 패턴]
- [Docker - GitHub Container Registry(GHCR)]
- [Docker - Docker Network 3가지]
- Kubernetes - Probe
- Kubernetes - ConfigMap & Secret
- Kubernetes - PV/PVC & Deployment & Service & HPA
- Kubernetes - Helm & Kustomize
- Kubernetes - Pod 1
- [Kubernetes - Pod 2]
- Kubernetes - Controller 1
- [Kubernetes - Controller 2]
- [Kubernetes - Object]
- [Kubernetes - Ingress & Nginx Application]
- [Kubernetes - Node Scheduling]
- [Kubernetes - Monitoring]
- [Kubernetes - Logging]
- Kubernetes - Deployment using Amazon EKS
- Jenkins - Jenkins Fundamentals & Environment Setup
- Jenkins - Jenkins Jobs: Freestyle & Pipeline
- Jenkins - Jenkins Pipeline Project
- Jenkins - Implementing Continuous Integration(CI) with Jenkins
- Nginx ‐ Nginx Introduction
- Nginx ‐ Nginx Supplementary Summary
- Nginx ‐ Deploying Domain with Nginx
- Nginx ‐ Implementing HTTPS with Nginx
- Nginx ‐ Backend Deployment via Nginx Reverse Proxy
- Nginx ‐ Load Balancing with Nginx
- [Nginx - Advanced Concept]
- [Nginx - Advanced Reverse Proxy]
- Monitoring - Log Level & Filter
- Monitoring - Log Collection with ELK Stack
- Monitoring - Log Monitoring with Kibana
- Monitoring - Server Monitoring with Prometheus and Grafana with Discord Alerts
- [Test - Load Testing Fundamentals]
- [Test - Identifying Bottlenecks with Load Testing]
- [Test - Resolving Bottlenecks and Improving Performance]
- Test - JUnit5
- Test - Mockito
- Test - TestContainers
- Test - JMeter
- Test - Chaos Monkey
- Test - ArchUnit
- [Test - Testing with Spring & JPA]
- Test - A Guide to Effective Mocking
- Test - Appendix: Tips for Better Testing
- [gRPC - Writing .proto Files with Protocol Buffers]
- [gRPC - Various Communication Patterns in gRPC]
- [gRPC - gRPC Optimization Techniques and Advanced Features]
- TDD - Introduction to TDD
- TDD - Iterating with TDD
- TDD - Managing System Data
- TDD - Handling Unexpected Test Failures
- TDD - Abstraction & Reusability
- TDD - Building a Testing DSL
- TDD - Managing Test Context
- TDD - Driving Input Code with Output Tests
- TDD - Pagination Test
- [PostgreSQL - Docker만을 사용하는 경량화된 환경 구성 방법]
- [PostgreSQL - PostgreSQL에서 제공하는 데이터 타입]
- [PostgreSQL - PostgreSQI의 JSONB, 역인덱싱과 활용 방법]
- [PostgreSQL - 데이터베이스 성능을 위한 최적화 패턴 및 전략]
- [PostgreSQL - 트랜잭션과 ACID, Isolation 수준별 차이]
- [PostgreSQL - Database Lock 교착상태와 읽기/쓰기 성능을 보장하는 MVCC 모델]
- [PostgreSQL - pgvector와 벡터 저장, 유사도 검색 패턴 개념]
- [PostgreSQL - 벡터 인덱스 최적화와 벡터 검색과 전문 검색 결합 패턴]
- [PostgreSQL - PostgreSQL 플러그인]
- [PostgreSQL - PostGIS - 공간 쿼리와 GIST 인덱스, 지리 타입과 공간 쿼리를 위한 타입과 기본 함수]
- [PostgreSQL - pg_search - 검색 엔진 없이 텍스트 검색 구현과 주의사항]
- [PostgreSQL - 단일 인스턴스 한계를 극복하는 분산 패턴과 스케줄링, 분산 환경 구축 방법]
- [PostgreSQL - Citus - 분산 테이블과 분산 쿼리를 위한 Extension과 데이터 분산 처리]
- [PostgreSQL - pg_cron - PostgreSQL로 구성하는 CronJob]
- [PostgreSQL - 스케줄러 + 분산 처리를 동시에 도입하는 주기적 집계 쿼리 패턴]
- [Workflow-Driven Techniques for Large-Scale Traffic Processing - Kafka + Debezium을 활용한 CDC 패턴 설계]
- [Workflow-Driven Techniques for Large-Scale Traffic Processing - Temporal을 활용한 워크플로우 패턴]
- [Workflow-Driven Techniques for Large-Scale Traffic Processing - Docker와 경량 이미지를 활용한 환경 구축 방법]
- [Workflow-Driven Techniques for Large-Scale Traffic Processing - Kafka에서의 메시지 Delivery Guarantee]
- [Workflow-Driven Techniques for Large-Scale Traffic Processing - 실시간 동기화의 핵심 CDC]
- [Workflow-Driven Techniques for Large-Scale Traffic Processing - MySQL Binary Log 기반의 CDC]
- [Workflow-Driven Techniques for Large-Scale Traffic Processing - Binary Log 기반의 CDC 구현 플랫폼 Debezium이란?]
- [Workflow-Driven Techniques for Large-Scale Traffic Processing - Debezium Architecture]
- [Workflow-Driven Techniques for Large-Scale Traffic Processing - Debezium Architecture Best Practice와 주의사항]
- Reactive Programming - Everything About Reactive Programming & Core Concepts of Reactive Programming
- Reactive Programming - Mastering Reactor Operators in WebFlux & A Deep Dive into WebFlux Operators
- Reactive Programming - Best Practices and Optional Patterns in WebFlux & Key Practical Patterns for WebFlux Development
- Reactive Programming - Practical WebFlux Patterns with Spring Boot & Building Applications with Spring Boot and WebFlux
- [ElasticSearch - Search Fundamentals & How Search Works]
- [ElasticSearch - Korean-Optimized Search]
- [ElasticSearch - Mapping & Data Types]
- [ElasticSearch - Common Search Features]
- [ElasticSearch - Building a Product Search Engine with Elasticsearch]
- [ElasticSearch - Deploying Elasticsearch with Elastic Cloud]
- [ElasticSearch - Managing Documents]
- [ElasticSearch - Analysis & Mapping]
- [ElasticSearch - Search Fundamentals]
- [ElasticSearch - Query Joins]
- [ElasticSearch - Processing Search Results]
- [ElasticSearch - Aggregations]
- [ElasticSearch - Tips for Improving Search Results]
- [ElasticSearch - Elasticsearch Clients]
- [ElasticSearch - Understanding How Elasticsearch Works]
- [ElasticSearch - Monitoring Elasticsearch]
- [ElasticSearch - Elasticsearch Troubleshooting]
- (Effective Java Item 1) Java ‐ 생성자 대신 정적 팩토리 메서드를 고려하라
- (Effective Java Item 2) Java - 생성자에 매개변수가 많다면 빌더를 고려하라
- (Effective Java Item 3) Java - private 생성자나 열거 타입으로 싱글턴임을 보증하라
- (Effective Java Item 4) Java - 인스턴스화를 막으려거든 private 생성자를 사용하라
- (Effective Java Item 5) Java - 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라
- (Effective Java Item 6) Java ‐ 불필요한 객체 생성을 피하라
- (Effective Java Item 7) Java - 다 쓴 객체 참조를 해제하라
- (Effective Java Item 8) Java - finalizer와 cleaner 사용을 피하라
- (Effective Java Item 9) Java - try‐finally보다는 try‐with‐resources를 사용하라
- (Effective Java Item 10) Java ‐ equals는 일반 규약을 지켜 재정의하라
- (Effective Java Item 11) Java ‐ equals를 재정의하려거든 hashCode도 재정의하라
- (Effective Java Item 12) Java - toString을 항상 재정의하라
- (Effective Java Item 13) Java ‐ clone 재정의는 주의해서 진행하라
- (Effective Java Item 14) Java ‐ Comparable을 구현할지 고려하라
- (Effective Java Item 15) Java ‐ 클래스와 멤버의 접근 권한을 최소화하라
- (Effective Java Item 16) Java ‐ public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라
- (Effective Java Item 17) Java ‐ 변경 가능성을 최소화하라
- (Effective Java Item 18) Java ‐ 상속보다는 컴포지션을 사용하라
- (Effective Java Item 19) Java ‐ 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라
- (Effective Java Item 20) Java ‐ 추상 클래스보다는 인터페이스를 우선하라
- (Effective Java Item 21) Java ‐ 인터페이스는 구현하는 쪽을 생각해 설계하라
- (Effective Java Item 22) Java ‐ 인터페이스는 타입을 정의하는 용도로만 사용하라
- (Effective Java Item 23) Java ‐ 태그 달린 클래스보다는 클래스 계층구조를 활용하라
- (Effective Java Item 24) Java ‐ 멤버 클래스는 되도록 static으로 만들라
- (Effective Java Item 25) Java ‐ 톱레벨 클래스는 한 파일에 하나만 담으라
- (Effective Java Item 26) Java ‐ 로 타입은 사용하지 말라
- (Effective Java Item 27) Java ‐ 비검사 경고를 제거하라
- (Effective Java Item 28) Java ‐ 배열보다는 리스트를 사용하라
- (Effective Java Item 29) Java ‐ 이왕이면 제네릭 타입으로 만들라
- (Effective Java Item 30) Java ‐ 이왕이면 제네릭 메서드로 만들라
- (Effective Java Item 31) Java - 한정적 와일드카드를 사용해 API 유연성을 높이라
- (Effective Java Item 32) Java - 제네릭과 가변인수를 함께 쓸 때는 신중하라
- (Effective Java Item 33) Java ‐ 타입 안전 이종 컨테이너를 고려하라
- (Effective Java Item 34) Java - int 상수 대신 열거 타입을 사용하라
- (Effective Java Item 35) Java - ordinal 메서드 대신 인스턴스 필드를 사용하라
- (Effective Java Item 36) Java ‐ 비트 필드 대신 EnumSet을 사용하라
- (Effective Java Item 37) Java ‐ ordinal 인덱싱 대신 EnumMap을 사용하라
- (Effective Java Item 38) Java ‐ 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라
- (Effective Java Item 39) Java ‐ 명명 패턴보다 애너테이션을 사용하라[Effective Java Item 39]
- (Effective Java Item 40) Java ‐ @Override 어노테이션을 일괄되게 사용하라
- (Effective Java Item 41) Java ‐ 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라
- (Effective Java Item 42) Java ‐ 익명 클래스보다는 람다를 사용하라
- (Effective Java Item 43) Java ‐ 람다보다는 메서드 참조를 사용하라
- (Effective Java Item 44) Java - 표준 함수형 인터페이스를 사용하라
- (Effective Java Item 45) Java - 스트림은 주의해서 사용하라
- (Effective Java Item 46) Java - 스트림에서는 부작용 없는 함수를 사용하라
- (Effective Java Item 47) Java - 반환 타입으로는 스트림보다 컬렉션이 낫다
- (Effective Java Item 48) Java ‐ 스트림 병렬화는 주의해서 사용하라
- (Effective Java Item 49) Java ‐ 매개변수가 유효한지 검사하라
- (Effective Java Item 50) Java ‐ 적시에 방어적 복사본을 만들라
- (Effective Java Item 51) Java ‐ 메서드 시그니처를 신중히 설계하라
- (Effective Java Item 52) Java ‐ 다중정의는 신중히 사용하라
- (Effective Java Item 53) Java ‐ 가변인수는 신중히 사용하라
- (Effective Java Item 54) Java - null이 아닌, 빈 컬렉션이나 배열을 반환하라
- (Effective Java Item 55) Java ‐ 옵셔널 반환은 신중히 하라
- (Effective Java Item 56) Java ‐ 공개된 API 요소에는 항상 문서화 주석을 사용하라
- (Effective Java Item 57) Java ‐ 지역변수의 범위를 최소화하라
- (Effective Java Item 58) Java ‐ 전통적인 for문보다는 for‐each문을 사용하라
- (Effective Java Item 59) Java ‐ 라이브러리를 익히고 사용하라
- (Effective Java Item 60) Java ‐ 정확한 답이 필요하다면 float와 double은 피하라
- (Effective Java Item 61) Java ‐ 박싱된 기본 타입보다는 기본 타입을 사용하라
- (Effective Java Item 62) Java ‐ 다른 타입이 적절하다면 문자열 사용을 피하라
- (Effective Java Item 63) Java ‐ 문자열 연결은 느리니 주의하라
- (Effective Java Item 64) Java ‐ 객체는 인터페이스를 사용해 참조하라
- (Effective Java Item 65) Java ‐ 리플렉션보다는 인터페이스를 사용하라
- (Effective Java Item 66) Java ‐ 네이티브 메서드는 신중히 사용하라
- (Effective Java Item 67) Java ‐ 최적화는 신중히 하라
- (Effective Java Item 68) Java ‐ 일반적으로 통용되는 명명 규칙을 따르라
- (Effective Java Item 69) Java ‐ 예외는 진짜 예외 상황에만 사용하라
- (Effective Java Item 70) Java ‐ 복구할 수 있는 상황에는 검사 예외를, 프로그래밍 오류에는 런타임 예외를 사용하라
- (Effective Java Item 71) Java ‐ 필요 없는 검사 예외 사용은 피하라
- (Effective Java Item 72) Java ‐ 표준 예외를 사용하라
- (Effective Java Item 73) Java ‐ 추상화 수준에 맞는 예외를 던지라
- (Effective Java Item 74) Java ‐ 메서드가 던지는 모든 예외를 문서화하라
- (Effective Java Item 75) Java ‐ 예외의 상세 메시지에 실패 관련 정보를 담으라
- (Effective Java Item 76) Java ‐ 가능한 한 실패 원자적으로 만들라
- (Effective Java Item 77) Java ‐ 예외를 무시하지 말라
- (Effective Java Item 78) Java - 공유 중인 가변 데이터는 동기화해 사용하라
- (Effective Java Item 79) Java - 과도한 동기화는 피하라
- (Effective Java Item 80) Java - 쓰레드보다는 실행자, 태스크, 스트림을 애용하라
- (Effective Java Item 81) Java - wait와 notify는 동시성 유틸리티를 애용하라
- (Effective Java Item 82) Java - 쓰레드 안전성 수준을 문서화하라
- (Effective Java Item 83) Java - 지연 초기화는 신중히 사용하라
- (Effective Java Item 84) Java - 프로그램의 동작을 쓰레드 스케줄러에 기대지 말라
- (Effective Java Item 85) Java - 자바 직렬화의 대안을 찾으라
- (Effective Java Item 86) Java - Serializable을 구현할지는 신중히 결정하라
- (Effective Java Item 87) Java - 커스텀 직렬화 형태를 고려해보라
- (Effective Java Item 88) Java - readObject 메서드는 방어적으로 작성하라
- (Effective Java Item 89) Java - 인스턴스 수를 통제해야 한다면 readResolve보다는 열거 타입을 사용하라
- [(Effective Java Item 90) Java - 직렬화된 인스턴스 대신 직렬화 프록시 사용을 검토하라]
- (Effective Kotlin Item 1) Kotlin - 가변성을 제한하라
- (Effective Kotlin Item 2) Kotlin - 임계 영역을 제거하라
- (Effective Kotlin Item 3) Kotlin - 가능한 한 빨리 플랫폼 타입을 제거하라
- (Effective Kotlin Item 4) Kotlin - 변수의 스코프를 최소화하라
- (Effective Kotlin Item 5) Kotlin - 인수와 상태에 대한 기대치를 명시하라
- (Effective Kotlin Item 6) Kotlin - 사용자 정의 오류보다 표준 오류를 선호하라
- (Effective Kotlin Item 7) Kotlin - 결과가 없을 가능성이 있는 경우 널 가능 또는 Result 반환 타입을 선호하라
- (Effective Kotlin Item 8) Kotlin - use를 사용하여 리소스를 닫아라
- (Effective Kotlin Item 9) Kotlin - 단위 테스트를 작성하라
- (Effective Kotlin Item 10) Kotlin - 가독성을 목표로 설계하라
- (Effective Kotlin Item 11) Kotlin - 연산자의 의미는 함수의 이름과 일치해야 한다
- (Effective Kotlin Item 12) Kotlin - 가독성을 높이려면 연산자를 사용하라
- (Effective Kotlin Item 13) Kotlin - 타입 명시를 고려하라
- (Effective Kotlin Item 14) Kotlin - 리시버를 명시적으로 참조하라
- (Effective Kotlin Item 15) Kotlin - 프로퍼티는 동작이 아닌 상태를 나타내야 한다
- (Effective Kotlin Item 16) Kotlin - Unit?을 반환이나 연산에 사용하지 말라
- (Effective Kotlin Item 17) Kotlin - 이름 있는 인수 사용을 고려하라
- (Effective Kotlin Item 18) Kotlin - 코딩 컨벤션을 준수하라
- (Effective Kotlin Item 19) Kotlin - knowledge를 반복하지 말라
- (Effective Kotlin Item 20) Kotlin - 일반적인 알고리즘을 반복하지 말라
- (Effective Kotlin Item 21) Kotlin - 일반적인 알고리즘을 구현할 때 제네릭을 사용하라
- (Effective Kotlin Item 22) Kotlin - 타입 매개변수의 섀도잉을 피하라
- (Effective Kotlin Item 23) Kotlin - 제네릭 타입에 변성 한정자 사용을 고려하라
- (Effective Kotlin Item 24) Kotlin - 공통 모듈을 추출해서 여러 플랫폼에서 재사용하라
- (Effective Kotlin Item 25) Kotlin - 각각의 함수는 하나의 추상화 수준으로 작성하라
- (Effective Kotlin Item 26) Kotlin - 변경으로부터 코드를 보호하려면 추상화를 사용하라
- (Effective Kotlin Item 27) Kotlin - API 안정성을 명시하라
- (Effective Kotlin Item 28) Kotlin - 외부 API를 래핑하는 것을 고려하라
- (Effective Kotlin Item 29) Kotlin - 가시성을 최소화하라
- (Effective Kotlin Item 30) Kotlin - 문서로 규약을 정의하라
- (Effective Kotlin Item 31) Kotlin - 추상화 규약을 준수하라
- (Effective Kotlin Item 32) Kotlin - 보조 생성자 대신 팩토리 함수를 고려하라
- (Effective Kotlin Item 33) Kotlin - 이름 있는 선택적 인수를 갖는 기본 생성자 사용을 고려하라
- (Effective Kotlin Item 34) Kotlin - 복잡한 객체 생성을 위해 DSL 정의를 고려하라
- (Effective Kotlin Item 35) Kotlin - 의존성 주입을 고려하라
- (Effective Kotlin Item 36) Kotlin - 상속보다 합성을 선호하라
- (Effective Kotlin Item 37) Kotlin - 데이터 묶음을 표현할 때 data 한정자를 사용하라
- (Effective Kotlin Item 38) Kotlin - 연산과 행동을 전달하려면 함수 타입이나 함수형 인터페이스를 사용하라
- (Effective Kotlin Item 39) Kotlin - 제한된 계층구조를 표현하기 위해 sealed 클래스와 sealed 인터페이스를 사용하라
- [(Effective Kotlin Item 40) Kotlin - 태그 클래스 대신 클래스 계층구조를 선호하라]
- [(Effective Kotlin Item 41) Kotlin - 열거형 클래스를 사용해서 값 목록을 나타내라]
- [(Effective Kotlin Item 42) Kotlin - equals의 규약을 준수하라]
- [(Effective Kotlin Item 43) Kotlin - hashCode의 규약을 준수하라]
- [(Effective Kotlin Item 44) Kotlin - compareTo의 규약을 준수하라]
- [(Effective Kotlin Item 45) Kotlin - API의 필수적이지 않은 부분을 확장으로 추출하는 것을 고려하라]
- [(Effective Kotlin Item 46) Kotlin - 멤버 확장 함수를 피하라]
- (Effective Kotlin Item 3) Kotlin - variable
- (Effective Kotlin Item 4) Kotlin - primitive types, literals, and operations
- (Effective Kotlin Item 5) Kotlin - control Flow: if, when, try, and while
- (Effective Kotlin Item 6) Kotlin - function
- (Effective Kotlin Item 7) Kotlin - for
- (Effective Kotlin Item 8) Kotlin - Null Safety and Nullable Types
- (Effective Kotlin Item 9) Kotlin - Class
- (Effective Kotlin Item 10) Kotlin - Extend
- (Effective Kotlin Item 11) Kotlin - Data Class
- (Effective Kotlin Item 12) Kotlin - Object
- (Effective Kotlin Item 13) Kotlin ‐ Exception
- (Effective Kotlin Item 14) Kotlin - Enum Classes
- (Effective Kotlin Item 15) Kotlin - Sealed Classes and Interfaces
- (Effective Kotlin Item 16) Kotlin - Annotation Classes
- (Effective Kotlin Item 17) Kotlin - Extensions
- (Effective Kotlin Item 18) Kotlin - Collections
- (Effective Kotlin Item 19) Kotlin - Operator Overloading
- (Effective Kotlin Item 20) Kotlin - The Beauty of the Type System
- (Effective Kotlin Item 21) Kotlin - Generic
- Reactive Programming - Reactive Streams
- Reactive Programming - Blocking I/O & Non-Blocking I/O
- Reactive Programming - Reactor Outline
- Reactive Programming - Marble Diagram
- Reactive Programming - Cold Sequence & Hot Sequence
- [Reactive Programming - Backpressure]
- [Reactive Programming - Sinks]
- [Reactive Programming - Scheduler]
- [Reactive Programming - Context]
- [Reactive Programming - Debugging]
- [Reactive Programming - Testing]
- [Reactive Programming - Operators]
- [Reactive Programming - Spring Webflux]
- [Reactive Programming - Annotation Based Controller]
- [Reactive Programming - Functional Endpoint]
- [Reactive Programming - Spring Data R2DBC]
- [Reactive Programming - Exception Handling]
- [Reactive Programming - WebClient]
- [Reactive Programming - Reactive Streaming Data Processing]
- 가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - 사용자 수에 따른 규모 확장성
- 가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - 개략적인 규모 추정
- 가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - 처리율 제한 장치의 설계
- [가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - 안정 해시 설계]
- [가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - 키-값 저장소 설계]
- [가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - 분산 시스템을 위한 유일 ID 생성기 설계]
- [가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - URL 단축기 설계]
- [가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - 웹 크롤러 설계]
- [가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - 알림 시스템 설계]
- [가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - 뉴스 피드 시스템 설계]
- [가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - 채팅 시스템 설계]
- [가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - 검색어 자동완성 시스템 설계]
- [가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - 유튜브 설계]
- [가상 면접 사례로 배우는 대규모 시스템 설계 기초 1 - 구글 드라이브 설계]
- (Clean Code 2) Clean Code - 의미 있는 이름
- (Clean Code 3) Clean Code - 함수
- (Clean Code 4) Clean Code - 주석
- (Clean Code 5) Clean Code - 형식 맞추기
- (Clean Code 6) Clean Code - 객체와 자료구조
- (Clean Code 7) Clean Code - 오류 처리
- (Clean Code 8) Clean Code - 경계
- (Clean Code 9) Clean Code - 단위 테스트
- (Clean Code 10) Clean Code - 클래스
📖 리팩토링 2판
- 주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 - 느려진 서비스, 어디부터 봐야 할까
- 주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 - 성능을 좌우하는 DB 설계와 쿼리
- 주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 ‐ 외부 연동이 문제일 때 살펴봐야 할 것들
- 주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 ‐ 비동기 연동, 언제 어떻게 써야 할까
- 주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 ‐ 동시성, 데이터가 꼬이기 전에 잡아야 한다
- 주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 ‐ IO 병목, 어떻게 해결하지
- 주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 ‐ 실무에서 꼭 필요한 보안 지식
- 주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 ‐ 모르면 답답해지는 네트워크 기초
- 주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 ‐ 자주 쓰는 서버 구조와 설계 패턴
- 주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 ‐ 처음 해보는 성능 테스트를 위한 기본 정리
- 주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 ‐ NoSQL 이해하기
- 주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 ‐ DB로 분산 잠금 구현하기