모든 TIL 문서는 다음 구조를 기본으로 따른다:
1. 핵심 개념 (What) - 필수
2. 존재 이유 (Why) - 필수
3. 동작 원리 (How) - 선택 (내부 메커니즘이 복잡한 경우)
4. 주의사항 (Pitfalls) - 선택 (실수하기 쉬운 경우)
5. 실전 적용 (Practice) - 선택 (코드나 실무 적용이 필요한 경우)
6. 참고 자료 (References) - 선택
유연성 원칙:
- 주제의 특성에 따라 섹션을 추가하거나 생략할 수 있다
- 간단한 개념은 "핵심 개념 + 존재 이유"만으로도 충분하다
- 복잡한 주제는 섹션을 세분화하거나 추가할 수 있다
모든 TIL 문서는 한글과 영어 버전을 모두 작성한다.
kr/ # 한글 버전
[Category]/
[Topic Name].md
en/ # 영어 버전
[Category]/
[Topic Name].en.md
kr/
Language/
Kotlin/
Coroutine.md # 한글 버전
JVM/
JVM.md
en/
Language/
Kotlin/
Coroutine.en.md # 영어 버전
JVM/
JVM.en.md
-
동일한 내용, 다른 언어
- 두 버전의 내용은 동일해야 한다
- 단순 번역이 아닌, 각 언어에 맞는 자연스러운 표현 사용
-
한글 먼저 작성
- 한글로 개념을 먼저 정리
- 영어 버전은 한글 버전을 기반으로 작성
-
코드는 공통
- 코드 예시는 두 버전에서 동일하게 유지
- 주석만 해당 언어로 작성
-
말투 통일
- 한글:
~이다/~하다단정적 문체 - 영어: 현재형 또는 단정적 표현 사용
- "X is Y" (not "X can be considered as Y")
- "This works by..." (not "This seems to work by...")
- 한글:
-
참고 자료는 분리
- 한글 버전: 한글 자료 우선
- 영어 버전: 영어 자료 우선 (필요시 한글 자료 포함)
- 한글 버전 작성 완료
- 영어 버전 작성 완료
- 두 버전의 내용이 동일한가?
- 코드 예시가 두 버전에서 동일한가?
- 각 언어에 맞는 자연스러운 표현을 사용했는가?
목적: 독자가 5초 안에 주제를 이해할 수 있도록
- 한 문장으로 정의부터 시작
- 필요시 비유나 예시로 보충 설명 (과한 비유는 하지 말 것)
# [주제]
## 개념
[주제]는 **[한 문장 정의]**이다.
[필요시 추가 설명이나 비유]
### 핵심 특징 (선택)
- 특징 1
- 특징 2
- 특징 3 (개수는 주제에 따라 조정)작성 팁:
- 핵심 특징은 2-5개 정도가 적당하다
- 특징이 명확하지 않은 주제는 이 부분을 생략할 수 있다
# Coroutine
## 개념
Coroutine은 **중단 가능한(suspendable) 경량 쓰레드**이다.
일반 함수는 시작하면 끝까지 실행되어야 하지만, Coroutine은 중간에 멈췄다가
나중에 다시 시작할 수 있다. 마치 책갈피를 꽂아두고 나중에 이어서 읽는 것과 같다.목적: 왜 이 기술/개념이 필요한지 맥락을 제공
- 어떤 문제를 해결하기 위해 등장했는가?
- 기존 방식의 한계는 무엇인가?
- 이것이 제공하는 가치는 무엇인가?
## 왜 필요한가?
### 해결하려는 문제
[기존에 존재하던 문제점 설명]
### 기존 방식의 한계
1. 한계점 1
2. 한계점 2
### 제공하는 가치
- 가치 1: [구체적 이점]
- 가치 2: [구체적 이점]
- 가치 3: [구체적 이점]## 왜 필요한가?
### 해결하려는 문제
비동기 작업을 처리할 때 콜백 지옥이나 복잡한 쓰레드 관리 문제가 발생한다.
### 기존 방식의 한계
1. **콜백**: 중첩이 깊어지면 가독성이 떨어짐
2. **Thread**: 생성 비용이 크고 컨텍스트 스위칭 오버헤드 발생
3. **Future/Promise**: 체이닝이 복잡하고 예외 처리가 어려움
### 제공하는 가치
- **가독성**: 동기 코드처럼 작성하면서 비동기 실행
- **경량성**: 수백만 개의 코루틴도 효율적으로 관리
- **구조화된 동시성**: 부모-자식 관계로 생명주기 관리목적: 내부적으로 어떻게 작동하는지 이해
언제 작성하는가?
- 내부 메커니즘이 복잡한 기술 (예: Coroutine, JVM GC, HTTP 통신)
- 이해를 위해 내부 동작을 알아야 하는 경우
- "왜?"를 설명하기 위해 "어떻게?"가 필요한 경우
생략 가능한 경우:
- 간단한 개념이나 패턴 (예: Singleton Pattern, DTO)
- 사용법이 핵심인 도구나 라이브러리
- 이미 "존재 이유"에서 충분히 설명된 경우
- 핵심 메커니즘 설명
- 단계별 처리 과정
- 중요한 내부 구조나 알고리즘
- 다이어그램이나 순서도 활용 (선택)
## 동작 원리
### 핵심 메커니즘
[가장 중요한 동작 방식 설명]
### 처리 과정
1. 단계 1: [설명]
2. 단계 2: [설명]
3. 단계 3: [설명]
### 내부 구조
[선택사항: 주요 컴포넌트나 아키텍처 설명]## 동작 원리
### 핵심 메커니즘
Coroutine은 CPS(Continuation-Passing Style) 변환을 통해 함수를 상태 머신으로 변환한다.
### 처리 과정
1. **suspend 함수 호출**: 현재 상태를 Continuation 객체에 저장
2. **중단**: 제어권을 반환하고 다른 작업 수행
3. **재개**: 저장된 상태에서 이어서 실행
### 내부 구조
- **Continuation**: 중단된 지점의 상태를 담는 객체
- **Dispatcher**: 코루틴이 실행될 쓰레드 결정
- **CoroutineScope**: 코루틴의 생명주기 관리목적: 실제로 어떻게 사용하는지 구체적인 예시 제공
언제 작성하는가?
- 코드로 설명할 수 있는 기술이나 프레임워크
- 실무 적용 예시가 이해를 돕는 경우
- 여러 사용 패턴이 존재하는 경우
- 실무에서 자주 사용되는 패턴
- 코드 예시는 주석으로 설명 추가
- Before/After 비교가 효과적
- 패턴 개수는 필요한 만큼 유연하게 작성 (1개~N개)
## 실전 적용
### 기본 사용법 (필수)
```kotlin
// 설명이 포함된 코드 예시[언제 사용하는가]
// 코드 예시[언제 사용하는가]
// 코드 예시// ❌ 개선 전
// 문제가 있는 코드
// ✅ 개선 후
// 개선된 코드
**작성 팁**:
- 기본 사용법만으로 충분하다면 패턴을 생략할 수 있다
- Before/After는 개선 효과가 명확할 때만 작성한다
### 예시
```markdown
## 실전 적용
### 기본 사용법
```kotlin
suspend fun fetchUserData(userId: String): User {
// suspend 함수는 다른 suspend 함수를 호출 가능
val userData = apiService.getUser(userId) // 네트워크 요청
return userData.toUser()
}
여러 API를 동시에 호출해야 할 때
suspend fun loadDashboard() = coroutineScope {
val user = async { fetchUser() }
val posts = async { fetchPosts() }
val notifications = async { fetchNotifications() }
Dashboard(
user = user.await(),
posts = posts.await(),
notifications = notifications.await()
)
}장시간 실행되는 작업에 제한 시간 설정
suspend fun fetchWithTimeout() {
withTimeout(5000) { // 5초 제한
fetchData()
}
}// ❌ 콜백 방식
fun fetchData(callback: (Result<Data>) -> Unit) {
api.getData(object : Callback {
override fun onSuccess(data: Data) {
callback(Result.success(data))
}
override fun onError(e: Exception) {
callback(Result.failure(e))
}
})
}
// ✅ 코루틴 방식
suspend fun fetchData(): Data {
return api.getData() // 간결하고 직관적
}
---
## 5. 실전 적용 (Practice) - 선택
**목적**: 흔히 하는 실수와 해결 방법 공유
**언제 작성하는가?**
- 실제로 겪었거나 흔히 발생하는 실수가 있는 경우
- 잘못 사용하면 심각한 문제가 발생할 수 있는 경우
- 초보자가 헷갈리기 쉬운 부분이 있는 경우
**생략 가능한 경우**:
- 특별한 주의사항이 없는 간단한 개념
- 실수할 여지가 거의 없는 경우
### 작성 가이드
- 실제로 겪었거나 흔히 발생하는 문제
- 왜 문제가 되는지 설명
- 올바른 해결 방법 제시
- ❌/✅ 아이콘으로 나쁜 예/좋은 예 구분
### 템플릿
```markdown
## 주의사항
### 1. [문제 상황]
[왜 문제가 되는가]
```kotlin
// ❌ 잘못된 예
[문제가 있는 코드]
// ✅ 올바른 예
[올바른 코드]
[왜 문제가 되는가]
// ❌ 잘못된 예
[문제가 있는 코드]
// ✅ 올바른 예
[올바른 코드]- 권장사항 1
- 권장사항 2
- 권장사항 3
### 예시
```markdown
## 주의사항
### 1. GlobalScope 사용 금지
생명주기 관리가 불가능하여 메모리 누수 발생
```kotlin
// ❌ 잘못된 예
GlobalScope.launch {
// 앱이 종료되어도 계속 실행될 수 있음
fetchData()
}
// ✅ 올바른 예
viewModelScope.launch {
// ViewModel 생명주기에 맞춰 자동 취소
fetchData()
}
UI가 멈추는 원인
// ❌ 잘못된 예
viewModelScope.launch {
val data = readFromFile() // blocking I/O
}
// ✅ 올바른 예
viewModelScope.launch {
val data = withContext(Dispatchers.IO) {
readFromFile() // I/O 쓰레드에서 실행
}
}- 항상 적절한 Scope 사용 (viewModelScope, lifecycleScope 등)
- I/O 작업은 Dispatchers.IO에서 실행
- 구조화된 동시성(Structured Concurrency) 원칙 준수
---
## 6. 참고 자료 (References)
**목적**: 더 깊이 학습할 수 있는 리소스 제공
### 템플릿
```markdown
## 참고 자료
### 공식 문서
- [제목](링크)
### 추천 아티클
- [제목](링크) - 간단한 설명
### 추천 도서
- 책 제목 - 저자
### 관련 TIL
- [관련 주제](링크)
글을 작성한 후 다음 항목을 확인한다:
- 명확성: 전문 용어 없이도 이해할 수 있는가?
- 논리성: 개념 → 이유 → 원리 → 적용 순서가 자연스러운가?
- 실용성: 실제 코드 예시가 포함되어 있는가? (해당 시)
- 완성도: 독자가 이 문서만 보고 핵심을 이해할 수 있는가?
- 간결성: 불필요한 설명은 없는가?
- 말투 일관성:
~이다/~하다단정적 문체를 사용했는가? - 구조 적절성: 주제에 맞게 필요한 섹션만 포함했는가?
- 영어 버전: 영어 버전(.en.md)도 작성했는가?
- 내용 동기화: 한글과 영어 버전의 내용이 일치하는가?
- 나를 위한 메모가 아닌, 3개월 후의 내가 읽을 문서
- "당연하다"고 생각하는 것도 명시적으로 작성
- 문법이나 API 나열보다 "왜", "어떻게"에 집중
- 공식 문서가 아니라 이해를 돕는 가이드
- 긴 설명보다 명확한 코드 한 줄이 낫다
- 주석은 "무엇"이 아닌 "왜"를 설명
~입니다/~합니다대신~이다/~하다의 단정적 표현 사용- 예시:
- ❌ "Coroutine은 경량 쓰레드입니다"
- ✅ "Coroutine은 경량 쓰레드이다"
- 본질을 명확히 드러내는 직설적 문체
- "이러한 특성으로 인해 X를 Y라고 볼 수 있다"
- "X의 본질은 Y이다"
- 불필요한 완곡 표현이나 장황한 수식 지양
- 내가 겪은 실수를 반드시 기록
- 주의사항은 실전 경험 기반으로 작성
- 새로운 인사이트가 생기면 업데이트
- 잘못된 내용을 발견하면 즉시 수정
- 한글과 영어 버전을 모두 작성한다
- 한글을 먼저 작성한 후 영어로 확장한다
- 두 버전의 품질을 동일하게 유지한다
실제로 사용할 수 있는 최대 템플릿 (필요한 섹션만 선택):
# [주제]
## 개념 (필수)
[주제]는 **[한 문장 정의]**이다.
[추가 설명이나 비유]
### 핵심 특징 (선택)
- 특징 1
- 특징 2
---
## 왜 필요한가? (필수)
### 해결하려는 문제
[문제 설명]
### 기존 방식의 한계
1. 한계점 1
2. 한계점 2
### 제공하는 가치
- **가치 1**: [구체적 이점]
- **가치 2**: [구체적 이점]
---
## 동작 원리 (선택 - 복잡한 메커니즘이 있을 때)
### 핵심 메커니즘
[핵심 동작 방식]
### 처리 과정
1. **단계 1**: [설명]
2. **단계 2**: [설명]
3. **단계 3**: [설명]
---
## 주의사항 (선택 - 실수하기 쉬운 부분이 있을 때)
### 기본 사용법
```kotlin
// 코드 예시[사용 시점]
// 코드 예시// ❌ 개선 전
// 문제가 있는 코드
// ✅ 개선 후
// 개선된 코드[왜 문제가 되는가]
// ❌ 잘못된 예
[잘못된 코드]
// ✅ 올바른 예
[올바른 코드][왜 문제가 되는가]
// ❌ 잘못된 예
[잘못된 코드]
// ✅ 올바른 예
[올바른 코드]- 권장사항 1
- 권장사항 2
- 권장사항 3
// 코드 예시[사용 시점]
// 코드 예시// ❌ 개선 전
// 문제가 있는 코드
// ✅ 개선 후
// 개선된 코드- 제목 - 설명
---
## 마무리
이 프레임워크는 가이드일 뿐 절대적인 규칙이 아니다. 주제의 특성에 따라 유연하게 조정하되, **논리적 흐름**과 **본질에 대한 이해**라는 핵심 원칙은 지킨다.
### 주제별 권장 구조
**간단한 개념** (예: DTO, Singleton Pattern):
- 핵심 개념 + 존재 이유 + (실전 적용)
**복잡한 기술** (예: Coroutine, JVM GC):
- 핵심 개념 + 존재 이유 + 동작 원리 + 주의사항 + 실전 적용
**도구/라이브러리** (예: MockK, H2):
- 핵심 개념 + 존재 이유 + 주의사항 + 실전 적용
**이론/원칙** (예: SOLID, DRY):
- 핵심 개념 + 존재 이유 + 주의사항 + 실전 적용
### 작성 시작 팁
1. **한 문장 정의부터 시작**: "X는 Y이다" 형태로 시작
2. **왜 배우는가?**: 이 개념이 해결하는 문제가 무엇인지
3. **필수 섹션만**: 처음엔 개념+이유만 작성, 필요시 확장
4. **완벽보다 완성**: 80% 완성도로 먼저 작성 후 점진적 개선