정수를 제곱하기
FP가 무엇인지 설명하기 위한 예제
//자바 언어
public class Squint{
public static void main(String args[]){
for(int i=0;i<25;i++)
System.out.println(i*i);
}
}
//LISP에서 파생한 클로저는 함수형 언어로, 클로저를 이용하면 같은 프로그램을 아래처럼 구현 가능
(println (take 25 (map (fn [x] (* x x)) (range))))
(println ; -> 출력한다
(take 25 ; -> 처음부터 25까지
(map (fn [x] (* x x)) ; -> 제곱을
(range)))) ; -> 정수의
println, take, map, range 모두 함수다.
(fn [x] (* x x))는 익명 함수로, 곱셈 함수를 호출하면서 입력 인자를 두번 전달한다.
클로저 vs 자바
자바
- 가변 변수를 사용
- 가변 변수는 프로그램 실행 중에 상태가 변할 수 있다
- 앞의 예제의 i는 가변 변수이다.
클로저
- 앞의 예제의 i는 가변 변수이다.
- 가변 변수는 프로그램 실행 중에 상태가 변할 수 있다
- 가변 변수가 없다
- x와 같은 변수가 한번 초기화 되면 절대로 변하지 않는다.
불변성과 아키텍처
아키텍처를 고려할 때 이러한 내용이 왜 중요한가?
- race Condition, DeadLock 조건, 동시성 문제가 모두 가변 변수로 인해 발생하기 때문이다.
만약 어떠한 변수도 갱신되지 않는다면 위의 문제들은 발생하지 않는다.
결국 우리가 Appdㅔ서 마주치는 모든 문제, 즉 다중 스레드와 프로세스를 사용하는 App에서의 모든 문제는 가변 변수가 없다면 발생하지 않는다.
가변성의 분리
불변성과 관련하여 가장 주요한 타협 중 하나는 App 또는 App 내부의 서비스를 가변 컴포넌트와 불편 컴포넌트로 분리하는 일이다.
불변 컴포넌트에서는 순수하게 함수형 방식으로만 작업이 처리되며, 어떤 가변 변수도 사용되지 않는다.
이벤트 소싱
저장 공간과 처리 능력의 한계는 계속해서 사라지고 있다.
프로세서는 초당 수십억 개의 명령을 수행하고
RAM 용량은 엄청 커졌다.
입금과 출금 트랜잭션이 있다고 해보자
편히 알고 있는 방법은 계좌 잔고를 변경했지만,
발생하는 트랜잭션을 저장한다고 가정해보자 -> 가변 변수가 필요가 없다.
무한한 공간과 처리능력이 필요하여 비현실적이다.
-> 하지만 App의 수명주기 동안만 문제없이 동작할 정도의 리소스만 있으면 충분할 것이다.
이벤트 소싱
기본 발상이 바로 이것이다.
상태가 아닌 트랙잭션을 저장하자는 전략이다.
상태가 필요해지면 단순히 상태의 시작점부터 모든 트랙잭션을 처리한다.
-> 물론 중간 중간(매일 자정)마다 계산한 후에 그 뒤에 들어오는 트랜잭션만 처리해도 된다.
결론
- 구조적 프로그래밍
- 제어흐름의 직접적인 전환에 부과되는 규율
- 객체 지향 프로그래밍
- 제어흐름의 간접적인 전환에 부과되는 규율
- 함수형 프로그래밍
- 변수 할당에 부과되는 규율