해당 포스팅 글이 로컬에서만 보이는 문제로 인하여 재업로드한 글입니다.

RxJava와 관련된 내용은 RxJava 프로그래밍 책을 구매하여 공부하면서 참고하였습니다. 앞으로 작성하는 RxJava 글은 위의 책으로 공부하면서 정리한 내용입니다. 문제가 된다면 해당 게시글을 삭제하도록 하겠습니다. 아래 글은 제가 책을 보고 공부한 내용과 참고한 내용으로 작성되었으므로 정확하지 않을 수 있으니 깃헙에 있는 이메일로 연락주시면 감사하겠습니다.

리액티브 프로그래밍

리액티브 프로그래밍(Reative Programming)은 반응형 프로그래밍이라고도 한다. 데이터 의 흐름과 전달에 관한 프로그래밍 패러다임이다. 기존의 명령형 프로그래밍은 주로 컴퓨터 하드웨어를 대상으로 프로그래머가 작성한 코드가 정해진 절차에 따라 순서대로 실행된다. 리액티브 프로그래밍은 데이터 흐름을 먼저 정의하고 데이터가 변경되었을 때 연관되는 수식이나 함수가 업데이트되는 방식이다.

가장 쉽게 이해할 수 있는 예는 MS의 엑셀(즉, 스프레드 시트)이다. 엑셀에서 값을 변경했을 때 자동으로 반영되는 것이 이러한 예를 설명한다.

  • 기존의 명령형 프로그래밍 <–> 반응형 프로그래밍(즉, 리액티브 프로그래밍)
  • 명령형 프로그래밍 방식은 변경이 발생했다는 통지를 받아서 연말 매출액을 새로 계산하는 당겨오는(pull) 방식이지만, 리액티브 프로그래밍은 데이터 소스가 변경된 데이터를 밀어주는(push 방식이다. 일종의 옵저버 패턴이라고 생각하면 된다.
  • 명령형 프로그래밍의 반대말은 선언형 프로그래밍이라고도 한다.
    • ex) SQL.
    • 반응형 프로그래밍은 선언형 프로그래밍을 지향한다.

자바언어와 리액티브 프로그래밍

  • 기존의 pull 방식의 프로그래밍 개념 -> push 방식의 프로그래밍 개념으로 바뀜.
  • 함수형 프로그래밍의 지원을 받는다.

리액티브 프로그래밍에서는 데이터의 변화가 발생했을 때 변경이 발생한 곳(데이터 소스)에서 새로운 데이터를 보내(push 방식) 준다. 기존 자바 프로그래밍이 pull 방식이라면 리액티브 프로그래밍은 push 방식이다.

한편 우리가 아는 콜백이나 옵저버 패턴을 넘어서 RxJava 기반의 리액티브 프로그래밍이 되려면 함수형 프로그래밍이 필요하다. 콜백이나 옵저버 패턴은 옵저버가 1개이거나 단일 스레드 환경에서는 문제가 없지만, 멀티 스레드 환경에서는 사용시 많은 주의가 필요하다.
대표적인 예가 데드락동기화문제이다.

추가적으로 함수형 프로그래밍은 부수 효과(side effect)가 없다. 부수 효과란 콜백이나 옵저버 패턴이 스레드에 안전하지 않은 이유가 같은 자원에 여러 스레드가 경쟁 조건(race condition)에 빠지게 되었을 때 예측할 수 없는 잘못된 결과가 나오는 것을 말한다. 한 두개의 스레드가 있을 때는 잘 동작하다가 수십, 수백개의 스레드가 동시에 단일 자원에 접근하면 계산 결과가 꼬이게 되고 디버깅도 어려워진다.

함수형 프로그래밍은 부수 효과가 없는 순수 함수(pure function)를 지향한다. 따라서 멀티 스레드 환경에서도 안전하다. 자바를 사용해 리액티브 프로그래밍을 하기 위해서는 함수형 프로그래밍의 도움이 필요하다.

그럼 여기서 말하는 함수형 프로그래밍은 무엇을 말하는 걸까?

간략하게 말하면 함수형 프로그래밍 언어는 함수를 단지 호출하는 대상이 아닌 변수로도 할 수 있고 인자로도 넘길 수 있고 마음대로 지지고 볶고? 할 수 있다. (아직 개념이 정확히 잡히지 않아서. . ㅜㅜ) 어려운 말로는 일급 시민이라고 표현한다고 한다.

반응형 프로그래밍은 이런 함수형 언어의 도구들을 자유자재로 활용해야 한다. 예를 들어 Java 8에 도입된 람다 표현식은 반드시 알아야 한다.

리액티브 프로그래밍 개념 다시 잡아보자.

RxJava를 비롯해서 리액티브 프로그래밍을 공부하다 보면 새로 등장하는 개념으로 인해 많은 혼란을 겪는다고 한다. 일단, 프로그래밍 스타일이 너무 다르다. 자바는 객체 지향 언어인데 리액티브 프로그래밍은 뭔가 좀 다른 것 같다. 그리고 내가 문제를 바라보는 개념도 이전과는 달라야 하는 것 같다. 이 부분은 아직 감이 안잡히지만 천천히 잡아보도록 하겠다.

아무튼 어렵고 새로운 개념은 초반에 잘 잡아놓으면 나중에 공부할 때 도움이 많이 되기 때문에 여기서 잘 잡아서 앞으로 나아가자. 다음은 위키 백과에 나와 있는 설명 중 일부분이다.

위키 백과의 일부

  • 상호 작용 프로그램은 프로그램이 주도하는 속도로 사용자 혹은 다른 프로그램과 상호작용 한다.
  • 사용자의 관점으로 볼 때 시분할 시스템은 상호작용 프로그램이다.
  • 리액티브 프로그래밍은 주변의 환경과 끊임없이 상호작용을 하는데 프로그램이 주도하는 것이 아니라 환경이 변하면 이벤트를 받아 동작한다.
  • 상호작용 프로그램은 자신의 속도에 맞춰 일하고 대부분 통신을 담당하는 반면 리액티브 프로그램은 외부 요구에 반응에 맞춰 일하고 대부분 정확한 인터럽트 처리를 담당한다.

자바에서는 이런 RxJava와 같은 리액티브 프로그래밍을 하기 위해서 기반이 마련되야 한다. 즉, 데이터 소스를 정의할 수 있고 그것의 변경 사항을 받아서 내 프로그램에 알려줄 존재(push)가 필요하다. 이를 RxJava 라이브러리를 통해서 구현할 수 있다.

RxJava를 만든 이유가 뭘까??

RxJava는 지금 우리가 아주 아주 잘 사용하는 [넷플릭스](https://www.netflix.com/kr/)의 기술 블로그에서 처음 소개되었다. 성능 개선을 위해서 넷플릭스는 .NET 환경의 리액티브 확장 라이브러리(Rx)를 JVM에 포팅(??)하여 RxJava를 만들었다. 넷플릭스가 RxJava를 만든 핵심적인 이유는 아래와 같다.

  1. 동시성을 적극적으로 끌어안기에 자바는 번거롭다.

자바가 동시성(? 정확히 뭐지…?)을 처리하기에 번거롭기 때문에 넷플릭스는 클라이언트의 요청을 서비스 계층에서 동시성을 적극적으로 끌어안음으로 이를 해결했다. 클라이언트의 요청을 처리할 때 다수의 비동기 실행 흐름(스레드 등등)을 생성하고 그것의 결과를 취합하여 최종 리턴하는 방식으로 내부 로직을 변경했다고 한다.

  1. 자바의 Future를 조합하기 어렵다?!

약 6년 전 (시간이 벌써 2019년이라니ㅜ.ㅜ) 내가 대학교 1학년일 때이다. 이 당시에 자바 8에서 제공하는 CompletableFuture 같은 클래스가 제공되지 않았다고 한다. 그래서 비동기 흐름을 조합할 수 있는 방법이 거의 없었고, RxJava에서는 이를 해결하려고 비동기 흐름을 조합(Compose)할 수 있는 방법을 제공한다.
RxJava에서 조합하는 실행 단위를 리액티브 연산자(Operator)라고 한다.

  1. 콜백 지옥 탈출!

콜백이 콜백을 부르는 콜백 지옥(Callback Hell) 상황은 코드의 가독성을 떨어트린다. 또한, 문제 발생 시 디버깅을 어렵게 만든다. 콜백은 비동기 방식으로 동작하는 가장 대표적인 패턴이다. 이런 지옥을 탈출하고자 RxJava에서는 콜백을 사용하지 않는 방향으로 설계하려고 했다.

정리

위에서 쭉 반응형 프로그래밍(즉, 리액티브 프로그래밍)은 비동기 데이터의 흐름과 전달에 초점을 맞춘 패러다임이다. 그리고 함수형 프로그래밍 언어의 지원을 받고 이를 활용한다고 했다.

정리하자면 반응형 프로그래밍은 함수형 프로그래밍 언어의 도구들을 가지고 데이터의 흐름을 Composable(구성 가능하게?!)하게 구현하는 것이라고 할 수 있다.

참고