reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change.
"리액티브 프로그래밍은 데이터 흐름과 변화의 전파와 관련된 선언적 프로그래밍 패러다임이다."
명령형 프로그래밍 vs 선언형 프로그래밍
명령형 프로그래밍은 작업을 '어떻게' 할 것인가에 초점을 맞춰 실행할 동작을 구체적으로 명시하지만,
선언형 프로그래밍은은 '무엇을' 할 것인가에 초점을 맞춰 어떻게 그 목표를 달성할지는 추상화 된다.
여기서 알아둬야 할 점은, 선언형 방식을 사용하기 위해서는 명령형 방식으로 '어떻게' 할 것인지가 추상화 되어있어야 한다는 점이다.
List에 있는 숫자 중 짝수들의 합계 구하기
- 명령형 프로그래밍
sum+=number와 같이 구체적인 방식이 명시되어 있다.
public class 명령형프로그래밍 {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 5, 10, 14, 20);
int sum = 0;
for (Integer number : numbers) {
if (number % 2 == 0) {
sum += number;
}
}
System.out.println("명령형 프로그래밍: " + sum);
}
}
- 선언형 프로그래밍
단순히 filter, mapToInt, sum과 같이 단순히 목표만 전달했다. 실제 해당 작업이 어떻게 작업을 수행되는지는 추상화된 것이다.
public class 선언형프로그래밍 {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 5, 10, 14, 20);
int sum = numbers.stream()
.filter(num -> num % 2 == 0)
.mapToInt(num -> num)
.sum();
System.out.println("선언형 프로그래밍: " + sum);
}
}
리액티브 프로그래밍
데이터 흐름과 변화의 전파는 데이터가 변경될 때마다 이벤트를 발생시켜서 소비자에게 데이터를 계속 전달한다는 것이다. 이는 Push 방식으로 동작하고, 기존의 사용하던 명령형 프로그래밍 방식은 Pull 방식으로 소비자가 데이터를 요청하는 것과 차이가 있다.
리액티브 프로그래밍은 데이터의 흐름(스트림)을 정의하고, 데이터가 변경되면 스트림을 통해 소비자에게 전달하는 비동기 프로그래밍이라고 할 수 있을 것 같다.
기존의 비동기 프로그래밍
리액티브 프로그래밍이 등장하기 전 비동기 프로그래밍에서는 대부분 콜백 기반의 비동기 처리 방식을 사용했다. 간단한 콜백은 이해하기 쉽지만, 콜백이 깊게 중첩되는 경우 콜백 지옥(Callback Hell) 문제가 발생해 코드의 복잡도가 증가하고, 가독성과 유지보수성이 떨어지는 문제가 있었다.
그렇다면 리액티브 프로그래밍에서도 콜백 지옥(Callback Hell)이 발생하는걸까?
리액티브 프로그래밍을 위한 라이브러리(ex.자바의 Project Reactor나 RxJava)를 사용하면, 콜백 지옥 문제를 리액티브 연산자(map(), filter() ...)와 함수형 프로그래밍 관점에서 콜백 지옥 문제를 피할 수 있다.
예를 들어, RxJava나 Project Reactor를 사용했을 때 다음과 같은 코드를 작성할 수 있다.
Flux.fromIterable(Arrays.asList(1, 2, 3, 4))
.filter(x -> x % 2 == 0)
.map(x -> x * 2)
.subscribe(System.out::println);
이렇게 각 단계에서 콜백 함수를 사용하지 않고, 연산자를 체인으로 연결해서 비동기 코드를 쉽게 작성할 수 있다.
리액티브 프로그래밍의 장점
1) 콜백 지옥 해결
2) 비동기 및 병렬성으로 확장성이 높음
3) 실시간으로 데이터 변화에 반응하여 빠른 응답 시간 제공
4) 회복성, 탄력성: 시스템에 오류가 발생했을 때 오류를 격리시키고 시스템을 복구함