Reactive Programming (Reactive stream)

지난 포스팅(Reactive manifesto) 에 이어 작성한다.

 

Reactive Programming (반응형 프로그래밍) 이란..

비동기 이벤트 처리 및 데이터 스트림 개념을 기반으로 하는 선언적 프로그래밍 패러다임이다.

 

위의 정의를 대충 느끼지말고 정확하게 의미를 짚어서 이해를 해보자..

그럼, 알아야할 개념을 한단계씩 알아가보겠다.

 

고차 함수 (High Order Function) 란..

함수를 매개변수로 받거나 함수를 리턴하는 함수를 뜻한다.

 

일급 객체 (First Class Object) 란..

- 변수에 할당할 수 있어야한다.

- 객체의 인자로 넘길수 있어야한다.

- 객체의 리턴 값으로 리턴할 수 있어야한다.

 

참고

자바 8 이전에서는 함수가 일급 객체에 해당되지 않았지만..

자바 8 이후 부터는 함수가 일급 객체에 해당된다. (함수형 인터페이스, 람다)

자바 8 이후 부터는 함수가 일급 객체에 해당되기 때문에 고차 함수를 만들수 있는 것이다.

 

순수 함수 (Pure Function) 란..

- 사이드 이펙트를 만들면 안된다. (함수 밖에 있는 값을 변경하지 말 것)

- 함수 내에 상태가 없어야한다.

- 멱등성을 가진다.

 

 

함수형 프로그래밍 (Functional Programming) 이란..

- 데이터 처리를 수학적 함수의 계산으로 취급하고

상태와 가변 데이터를 멀리하는 프로그래밍 패러다임의 하나이다.

- 명령형 프로그래밍에서는 상태를 바꾸는 것을 강조하는 것과는 달리,

함수형 프로그래밍은 함수의 응용을 강조한다.

- 문이 아닌 식이나 선언으로 수행되는 선언적 프로그래밍 패러다임을 따르고 있다.

 

참고. Java 에서의 함수형 프로그래밍

- 함수를 일급 객체(First Class Object) 로 사용

- 순수 함수 (pure function) 를 사용

- 고차 함수 (High-Order Class) 를 사용

- 불변성을 가져야한다.

 

 

선언형 프로그래밍 (Declaritive Programming) 이란..

반대의 개념으로 명령형 프로그래밍이 있다.

명령형 프로그래밍은 어떻게(How) 에 초점이 맞춰진 방식이고..

선언형 프로그래밍은 무엇을(What) 에 초점이 맞춰진 방식이다..

 

선언형 프로그래밍은 코드상 추상화를 진행한 것을 떠올리면 쉬운데..

비유하자면..

선언형은 메서드 레퍼런스를 사용하는 것이라면..

명령형은 메서드 레퍼런스를 사용하지 않고 직접 구현하는 것에 가깝다.

또다르게 비유하자면..

명령형은 구체적인 라이브러리 내부 Callee 코드라면..

선언형은 라이브러리 클래스나 메서드를 호출하는 Caller 의 코드이다. 

 

간단하게는..

Java 의 함수형 인터페이스, 람다, 메서드 레퍼런스 등과

Stream, CompletableFuture 사용을 떠올리면 쉽다.

 

 

자 이제..

선언형 프로그래밍에 대해 알게 되었으니..

Reactive Programming 정의의 반을 알게 되었다.

"비동기 이벤트 처리 및 데이터 스트림 개념을 기반으로 하는 선언적 프로그래밍 패러다임이다."

 

 

 

나머지 반도 알아가보자..

우선, 비동기 이벤트 처리와 데이터 스트림 개념이 왜 기반이 되어야 하는지 알 필요가 있다.

Reactive Manifesto 를 참고하여 Reactive System 디자인을 생각해 봤을 때..

Java 8 을 공부했다면..

Stream, CompletableFuture 등을 떠올릴 수 있을 것이다..

이들로 Reactive System 을 만들 수 있을까?

 

참고

Reactive Manifesto 에서 Reactive System 을 만들기 위해선

Message Driven 방법을 써야한다고 선언하고 있다.

Message Driven 에서는 비동기 메시지 전달과 메시지 큐, back-pressure 개념이 나왔다.

 

 

우선 상황을 가정해보겠다.

어떤 함수가 있는데..

함수를 호출하는 영역을 Caller

해당 함수 영역을 Callee 로 한다.

Caller 에는 Callee 가 전달하는 "데이터(함수 결과)에 

처리해야할 특정 작업"이 존재하는 상황이다.

 

비동기 이벤트 처리의 필요성

Java Stream 을 리턴 타입으로 하는 함수를 생각해보겠다.

 

Caller 입장에서 생각해보자.

Caller 는 Callee 로 부터 Stream 을 받았다.

Stream 타입으로 받아서 중간 연산자를 붙임으로써 "특정 작업"을 처리하고..

종료 연산자를 사용하여 최종 데이터를 가지게 될 것이다.

 

즉,

1. Stream 은 callback 을 등록할 수 없기 때문에 Caller 에서

"특정 작업" 을 실행할 수 밖에 없다. (동기)

2. Stream 은 그 자체로 메시지 큐 특성을 가졌으나

back-pressure 특징은 없다.

 

참고

종료 연산자를 호출하는 것은 Caller 이므로..

데이터 흐름을 생성하는 것도 Caller 라서.. blocking 이라 볼 수 있다.

 

 

데이터 스트림 개념의 필요성

Java CompletableFuture 를 리턴 타입으로 하는 함수를 생각해보겠다.

 

Caller 입장에서 생각해보자.

Caller 는 Callee 로 부터 CompletableFuture 를 받았다.

CompletableFuture 타입으로 받아서 callback 을 등록함으로써

"특정 작업" 을 처리할 수 있다.

 

즉,

1. CompletableFuture 는 callback 을 등록할 수 있어서

"특정 작업" 의 실행을 Caller 에서 Callee 로 넘길 수 있다. (비동기)

2. CompletableFuture 는 메시지 큐 특성을 가지지 않는다.

 

 

결론..

Reactive Manifesto 를 보면서.. 떠올린 Stream 과 CompletableFuture 으로는

Reactive System 을 만들기엔 많이 부족하다는 것을 알게되었다.

무언가 새로운게 등장해야할 시점이다.

 

이제.. Reactive Programming 의 정의를 온전히 이해할 수 있을 것이다.

"비동기 이벤트 처리 및 데이터 스트림 개념을 기반으로 하는 선언적 프로그래밍 패러다임이다."

 

 

Reactive Stream

Reactive Programming 을 위해서

비동기 스트림 처리와 back-pressure 에 대한 표준이 만들어졌다.

그것이 바로 Reactive Stream 이다.

 

 

Reactive Stream API 의 사양을 인터페이스로 만들어 놓은 것이 존재한다.

대표적으로 Publisher, Subscriber, Subscription, Processor 인터페이스가 존재한다.

 

Java 9 이전에는 org.reactivestreams 의 독립적인 라이브러리가 존재하였다.

Java 9 부터는 java.util.concurrent.Flow 위치에 공식 Java API 의 일부로 되었다.

 

'Spring Reactive Stack > Reactive Streams' 카테고리의 다른 글

Reactive Stream  (0) 2023.11.08
Reactive Manifesto (Reactive System Guide)  (1) 2023.11.06