이번 포스팅에서는 리액티브 프로그래밍의 개념과 자바 언어로 구현한 RxJava 라이브러리를 소개할 예정이다.
리액티브 프로그래밍은 데이터 흐름과 변화의 전달에 관한 프로그래밍 패러다임이다.
기존의 명령형 프로그래밍
은 주로 컴퓨터 하드웨어를 대상으로 프로그래머가 작성한 코드가 정해진 절차에 따라 순서대로 진행된다.
명령형 프로그래밍 : 프로그램의 상태와 상태를 변경시키는 구문의 관점에서 연산을 설명하는 프로그래밍 패러다임의 일종이다.
리액티브 프로그래밍
은 데이터 흐름을 먼저 정의하고 데이터가 변경되었을 때 연관되는 함수나 수식이 업데이트되는 방식이다.
자바 언어와 리액티브 프로그래밍은 대략 두 가지 관계가 있다고 정리할 수 있다.
1) 기존 pull 방식의 프로그래밍 개념을 push 방식의 프로그래밍 개념으로 바꾼다.
먼저, 자바 언어는 객체지향 프로그래밍 언어이다. 예를 들어 매장의 연간 매출액을 계산하는 프로그램을 자바로 작성한다 가정하자.
만약 1월과 2월의 매출액이 줄어들었다면, 데이터베이스에서 월간 매출액의 합계를 가져온 다음 결과를 다시 계산한다. -> pull 방식
즉, 별도의 이벤트를 받아서 다시 계산하는 방식으로 개발하지 않는다는 뜻이기도 하다.
단순히 위의 예를 구현하는 수준이라면 리액티브 프로그래밍을 하지 않아도 된다.
하지만, 전국에 있는 매장의 매출액을 실시간으로 집계한다고 가정해보자. 기존의 프로그래밍으로는 각 매장의 변화 상황을 데이터베이스에서 가져와야 한다. 혹은 전국에 있는 매장에 분석 데이터를 통지하려면 전체 매장 리스트를 기반으로 순차적으로 변화 상황을 전달해야 한다.
여기서 리액티브 프로그래밍은 데이터의 변화가 발생했을 때 변경이 발생한 곳에서 새로운 데이터를 보내주는 방식을 사용한다. -> push 방식
즉, 기존 자바 프로그래밍이 pull 방식이라면 리액티프 프로그래밍 방식은 push 방식이다.
2) 함수형 프로그래밍의 지원을 받는다.
우리가 알고 있는 콜백이나 옵서버 패턴을 넘어서 RxJava 기반의 리액티브 프로그래밍이 되기 위해서는 함수형 프로그래밍
이 필요하다.
콜백이나 옵서버 패턴은 옵서버가 1개 이거나 단일 스레드 환경에서는 문제 없지만 멀티 스레드 환경에서 사용할 때 많은 주의가 필요하다. ex) 데드락, 동기화 문제
콜백이나 옵서버 패턴이 스레드에 안전하지 않은 이유는 같은 자원에 여러 스레드가 경쟁 조건에 빠지게 되었을 때 예측할 수 없는 잘못된 결과가 나오기 때문이다.-> 부수 효과
한 두개의 스레드가 있을 때는 정상 동작하다가 수십 수백 개의 스레드가 동시에 단일 자원에 접근하면 계산 결과가 꼬이고 디버깅하기 매우 어려워진다.
때문에 함수형 프로그래밍은 부수 효과
가 없는 순수 함수
를 지향하면서 멀티 스레드 환경에서도 안전해진다.
즉, 자바 언어로 리액티브 프로그래밍을 하기 위해서는 함수형 프로그래밍의 지원이 필요하다.
리액티브 프로그래밍은 데이터 흐름과 변화의 전달에 관한 프로그래밍 패러다임이다. > 위키백과 | 리액티브 프로그래밍 에서는 컴퓨터 프로그램의 세 가지 분류 중 한가지로 소개되기도 한다.
컴퓨터 프로그램에는 크게 세 가지 종류가 있다. 첫 번째는 변환 프로그램으로 주어진 입력값을 바탕으로 결과를 계산하는 프로그램이다. 일반적인 예는 컴파일러와 수치 계산 프로그램이다. 두 번째는 상호작용 프로그램으로 프로그램이 주도하는 속도로 사용자 혹은 다른 프로그램과 상호작용을 한다. 사용자의 관점으로 볼 때 시분할 시스템은 상호작용 프로그램이다.
리액티브 프로그램은 주변의 환경과 끊임없는 상호작용을 하는데 프로그램이 주도하는 것이 아니라 환경이 변하면 이벤트를 받아 동작한다. 상호작용 프로그램은 자신의 속도에 맞춰 일하고 대부분 통신을 담당한다. 반면 리액티브 프로그램은 외부 요구에 반응에 맞춰 일하고 대부분 정확한 인터럽트 처리를 담당한다.
위 글에서는 리액티브 프로그래밍을 이해하는 데 필요한 개념이 담겨있다. 보통 애플리케이션을 만드는 프로그래머가 작성하는 프로그램은 변환 프로그램이거나 상호작용 프로그램이다. 혹은 클라이언트의 요청을 처리하는 서버 프로그래밍은 리액티브 프로그래밍에 가깝다.
애플리케이션에서 RxJava와 같은 리액티브 프로그래밍을 하려면 누군가 리액티브 프로그래밍을 할 수 있는 기반 시설을 제공해주어야 한다. -> push 필요
즉, 데이터 소스를 정의할 수 있고 그것의 변경 사항을 받아서 내 프로그램에게 알려줄 존재가 필요하다.
그것을 .NET 환경에서는 리액티브 확장이라 하고 JVM 위의 자바 언어로 구현해놓은 라이브러리가 RxJava이다.
리액티브 프로그래밍은 비동기 연산을 필터링, 변환, 조합해 위 세가지 핵심 이유를 해결할 수 있다. 따라서 RxJava는 Observable과 같은 데이터 소스
와 map(), Filter(), reduce()와 같은 리액티브 연산자
를 제공한다.
나는 안드로이드 스튜디오에서 테스트 코드로 작성할 예정이다.
import io.reactivex.Observable;
public class FirstExample {
@Test
public void main() {
FirstExample demo = new FirstExample();
demo.emit();
}
public void emit() {
Observable.just("Hello", "RxJava!")
.subscribe(System.out::println);
}
}
import 부분을 살펴보자. RxJava2의 기본 패키지 이름은 io.reactivex
이다.
Observable 클래스는 데이터의 변화가 발생하는 데이터 소스이다. Observable은 다음 포스팅에서 자세히 다룰 예정이다.
Observable 클래스의 just() 함수는 가장 단순한 선언 방식이다. 위 예제에서 데이터 소스에서 "Hello", "RxJava!"를 발행했다.
Integer와 같은 래퍼 타입부터 Order 같은 사용자 정의 클래스의 객체도 인자로 넣을 수 있다.
subscribe() 함수는 Observable 을 구독한다. Observable 은 subscribe() 함수를 호출해야 비로소 변화한 데이터를 구독자에게 발행한다. 만약 just() 함수만 호출하면 데이터를 발행하지 않는다.
반드시 데이터를 수신할 구독하자 subscribe() 함수를 호출해야 Observable 에서 데이터가 발행된다.
emit()는 내가 만든 메서드이다.
emit는 '어떤 것을 내보내다' 라는 뜻인데, RxJava 개발 문서에는 Observable이 subscribe() 함수를 호출한 구독자에게 데이터를 발행하는 것을 표현하는 용어로 사용한다. RxJava 관련 문서에 자주 등장하는 단어로 여러 표현이 있지만 '발행하다'로 표현한다.
마블 다이어그램은 RxJava를 이해하는 핵심 도구이다. map(), FlatMap() 함수 등의 많은 리액티브 연산자들을 이해하는 데 큰 도움을 주기 때문이다.
마블 다이어그램은 예를 보면서 어떻게 활용하는지 알아보겠다.
1) flip() 함수의 마블 다이어그램 예시
링크
onNext
알림이 발생한다.onComplete
알림이 발생한다.onError
알림이 발생한다.2) combineLatest() 함수의 마블 다이어그램 예시
링크
여기까지 리액티브 프로그래밍이 어떤 개념인지 살펴보고 RxJava 라이브러리가 무엇인지 알아보았다. RxJava는 리액티브 프로그래밍이라는 새로운 시각을 제공해주고 비동기 프로그래밍과 함수형 프로그래밍을 모두 활용해 문제를 해결할 수 있다.
다음 포스팅에는 RxJava의 핵심 클래스인 Observable에 대해 작성해 볼 예정이다.