Reactive Programming

비동기적 데이터 흐름을 처리하는 프로그래밍 기법

1. 명령형 프로그래밍

interface ShoppingCardService{
	Output calculate(input value);
}
class OrderService{
	private final ShoppingCardService scService;

	void process(){
		input input = ...;
		Output output = scService.calculate(input);
		... // 사후 처리 로직
	}
}

ShoppingCardService가 HTTP요청이나 데이터베이스 쿼리와 같이 시간이 걸리는 I/O 작업을 실행한다고 가정하자. 위 코드에 대한 설명은 아래와 같다.

  1. ShoppingCardService인터페이스를 선언한다
  2. OrderService를 선언한다. ShoppingCardServce를 동기적으로 호출하고 실행 직후 결과를 받는다.
  3. 이후 이 서비스는 시간과 강결합된다. 단순히 OrderService를 실행하는 경우에도 실행결과와 강결합되어, ShoppingCardService가 요청을 처리하는 동안 다른 작업을 실행할 수 없다.

→ 정리하자면 OrderService로직을 처리하는 동안 스레드가 차단된다. 따라서 별도 독립적은 처리를 위해서는 스레드를 추가 할당해야한다. 다만 스레드 추가할당은 많은 비용이 들기때문에 손익을 잘 고려해야한다.

2. 콜백 기법을 적용한 문제해결

interface ShoppingCardService{
	void calculate(input value, Consumer<Output> c);
}
class OrderService{
	private final ShoppingCardService scService;
	void process(){
		Input input = ...;
		scService.calculate(input, output ->{
			... // 사후 처리 로직
		});
	}
}
  1. calculate의 인터페이스 선언부를 보면 input을 받아 로직수행 후 Consumer<Output>에 저장한다.
    1. calculate는 void를 반환하므로 호출하는 인스턴스가 즉시 대기상태에서 해제되며 그 결과는 나중에 지정된 Consumer<> 콜백으로 전달된다.
  2. OrderService선언부에서 비동기식으로 ShoppingCardService를 호출하고 이후 작업을 진행한다. 콜백함수를 실행하면 실제 결과에 대한 처리를 계속할 수 있다.

→ OrderService는 작업 완료 후에 반응할 콜백함수를 전달한다. 이는 OrderService가 ShoppingCardService로부터 분리되었음을 의미하며, OrderService로 결과를 전달하는 함수형 콜백 호출을 위해 동기, 비동기 방식으로 calculate메서드를 구현할 수 있다.