학습
Scala 리액티브 프로그래밍
Scala 리액티브 프로그래밍 — 고급
리액티브 프로그래밍
1. 도입 (왜 배워야 하는가)
리액티브 프로그래밍은 현대 소프트웨어 개발의 중요한 패러다임 중 하나입니다. 특히 대규모 애플리케이션이 요구하는 높은 성능과 사용자 경험을 제공하기 위해 필요합니다. 전통적인 프로그래밍 방식은 요청-응답 패턴에 의존하여 동기적으로 작동하지만, 리액티브 프로그래밍은 비동기적이고 이벤트 기반으로 작동하여 리소스를 효율적으로 사용할 수 있게 해줍니다.
리액티브 프로그래밍을 모르면 다음과 같은 문제가 발생할 수 있습니다:
- 확장성 부족: 많은 사용자의 요청을 동시에 처리할 수 없어 시스템이 느려지거나 다운될 수 있습니다.
- 응답성 저하: UI가 멈추거나 반응이 느려져 사용자 경험이 떨어질 수 있습니다.
- 복잡한 에러 처리: 비동기 작업에서 발생하는 예외를 처리하기 어려워질 수 있습니다.
2. 핵심 개념 설명
리액티브 프로그래밍의 핵심 개념은 다음과 같습니다:
| 개념 | 설명 |
|---|---|
| Observable | 데이터의 스트림을 표현합니다. 데이터의 변화를 구독할 수 있습니다. |
| Observer | Observable에서 발생하는 이벤트를 수신합니다. |
| Subscription | Observable와 Observer의 연결을 나타냅니다. |
| Backpressure | 소비자가 생산자보다 느릴 때, 데이터 흐름을 조절하는 메커니즘입니다. |
비유하자면, Observable은 라디오 방송국, Observer는 그 방송을 듣는 청취자, Subscription은 방송을 듣기 위해 연결한 것과 같습니다. 청취자는 방송국에서 송출하는 내용을 실시간으로 듣고, 방송국은 청취자가 얼마나 많은 정보를 소화할 수 있는지를 고려해야 합니다.
3. 기본 코드 예제
리액티브 프로그래밍의 기본적인 사용법을 보여주는 코드입니다.
import rx.Observable
// Observable 생성
val observable = Observable.create[Int](subscriber => { for (i <- 1 to 5) {
subscriber.onNext(i) // 데이터 전송
}
subscriber.onCompleted() // 작업 완료 알림
})
// Observer 생성
val observer = new Observer[Int] {
override def onNext(value: Int): Unit = println(s"Received: $value")
override def onError(e: Throwable): Unit = println(s"Error: ${e.getMessage}")
override def onCompleted(): Unit = println("Completed!")
}
// Subscription
observable.subscribe(observer)
실행 결과
Received: 1
Received: 2
Received: 3
Received: 4
Received: 5
Completed!
코드 한 줄씩 동작 설명
Observable.create[Int]를 호출하여 Observable을 생성합니다. 이 Observable은Int값을 방출합니다.for (i <- 1 to 5)루프를 통해 1부터 5까지의 값을 생성합니다.subscriber.onNext(i)를 통해 각 값을 Observer에 전달합니다.- 모든 값이 전송된 후,
subscriber.onCompleted()로 작업이 완료되었음을 알립니다. observable.subscribe(observer)를 통해 Observer가 Observable을 구독합니다.- Observer를 구독하지 않음
- 생산과 소비의 불균형
- 리액티브 프로그래밍은 비동기적이고 이벤트 기반의 프로그래밍 모델입니다.
- Observable, Observer, Subscription 등이 핵심 개념입니다.
- 실시간 데이터 처리 및 UI 반영에 유용합니다.
- 다음에 학습하면 좋은 주제: Akka Streams 또는 Monix와 같은 리액티브 라이브러리.
4. 실전 활용 예제
1. 쇼핑몰 장바구니 구현
쇼핑몰에서 장바구니에 상품을 추가할 때, 사용자가 추가하는 즉시 UI에 반영되도록 할 수 있습니다.
import rx.subjects.PublishSubject
val cartSubject = PublishSubject.create[String]()
// 장바구니에 상품 추가
cartSubject.subscribe(item => println(s"Item added to cart: $item"))
// 상품 추가
cartSubject.onNext("Laptop")
cartSubject.onNext("Smartphone")
상황 설명 사용자가 상품을 장바구니에 추가하면, 해당 상품이 즉시 출력됩니다. 이로 인해 사용자에게 실시간 피드백을 제공할 수 있습니다.
2. 실시간 데이터 스트리밍
서버에서 실시간으로 데이터를 수신하고 이를 UI에 반영하는 예입니다.
import rx.Observable
val dataStream = Observable.interval(1.second).map(tick => s"Tick: $tick")
dataStream.subscribe(data => println(data))
상황 설명 이 코드는 1초마다 "Tick" 메시지를 출력합니다. 이러한 방식으로 실시간 데이터를 처리할 수 있습니다.
5. 흔한 실수와 주의사항
흔한 실수
- 잘못된 코드:
observable // 구독하지 않음
- 올바른 코드:
observable.subscribe(observer) // 구독 필요
- 잘못된 코드:
observable.map(x => / heavy computation /) // 느린 소비
- 올바른 코드:
observable.buffer(10) // 배치 처리하여 성능 개선