참고
시스템 구현과 유지보수
NOTE
함수형 프로그래밍은 부작용 없음(사이드 이펙트)와 불변성이라는 개념으로 유지보수성을 향상시켜준다!
•
유지보수에서 코드 크래시 디버깅 문제를 일으키는 요소는 예상하지 못한 변수값 때문이다.
◦
함수형 프로그래밍이 이러한 변수값이 바뀌는걸 막아줌!
•
변수가 예상하지 못한 값을 가지는 이유는, 유지보수하는 시스템의 여러 메서드에서 공유된 가변 데이터 구조를 읽고 갱신하기 때문이다.
•
자신을 포함하는 클래스의 상태 그리고 다른 객체의 상태를 바꾸지 않으며 return문을 통해서만 결과를 반환하는 함수를 순수 메서드, 부작용 없는 메서드라고 부른다.
◦
⇒ 이러한 방식을 함수형 프로그래밍이라 한다!
•
구체적으로 부작용은 무엇일까?
◦
자료구조를 고치거나 필드에 값을 할당
◦
예외 발생
◦
파일에 쓰기 등의 I/O 동작 수행
•
불변 객체를 이용해서 부작용을 없애는 방법도 있다.
◦
불변 객체는 복사하지 않고, 상태를 바꿀 수 없으므로 쓰레드 안전성을 제공한다.
함수형 자바
NOTE
실질적으로 자바로는 완벽한 함수형 프로그래밍을 구현하기 어렵다!
예외가 발생하는 함수는 함수형이 아니다.
•
함수나 메서드는 지역 변수만을 변경해야 함수형이라 할 수 있다.
•
함수나 메서드에 참조하는 객체가 있다면 그 객체는 불변 객체여야 한다.
•
함수나 메서드가 어떤 예외도 일으키지 않아야 한다.
◦
예외가 발생하면 return으로 결과를 반환할 수 없기 때문
예외없이 나눗셈을 표현하려면?
•
Optional<T>를 사용해서 해결할 수 있다.
•
혹은 지역적으로만 예외를 사용해서 해결할수도 있다.
참조 투명성
NOTE
같은 인수로 함수를 호출했을 때 항상 같은 결과를 반환한다면 참조적으로 투명한 함수라 한다!
•
참조 투명성은 프로그램 이해에 큰 도움을 주며, 오랜 시간이 걸리는 연산을 기억화 또는 캐싱을 통해 다시 계산하지 않고 저장하는 최적화도 제공한다.
객체지향 프로그래밍과 함수형 프로그래밍
NOTE
같은 인수로 함수를 호출했을 때 항상 같은 결과를 반환한다면 참조적으로 투명한 함수라 한다!
데이터를 함수로 연결하는 것을 중심으로 사고하는 방식( 함수형 프로그래밍)
•
프로그래밍 형식을 스펙트럼으로 표현하자면 스펙트럼의 한 쪽끝에는 모든 것을 객체로 간주하고, 객체를 갱신하는 방식으로 동작하는 익스트림 객체지향이 위치한다.
•
반대쪽 끝에는 참조적 투명성을 중요시하는, 즉 변화를 허용하지 않는 함수형 프로그래밍 형식이 위치한다.
재귀와 반복
NOTE
순수 함수형 프로그래밍 언어에서는 for, while 같은 반복문을 포함하지 않는다!
static long factorialRecursive(long n) {
return n == 1 ? 1 : n * factorialRecursive(n-1);
}
Java
복사
하지만 재귀는 반복보다 비싸다.
호출마다 스택이 증가함
•
반복에 의한 변화가 코드에 스며들 수 있기 때문이다.
•
일반적으로 반복 보다 재귀 코드가 더 비용이 높다.
◦
재귀 입력값에 비례해서 메모리 사용량이 증가한다.
◦
큰 입력값을 넣으면 StackOverflowError가 발생
그러면 재귀는 쓸모가 없는가?
static long factorialTailRecursive(long n) {
return factorialHeper(1, n);
}
static long factorialHelper(long acc, long n) {
return n == 1 ? acc : factorialHelper(acc*n, n-1);
}
Java
복사
함수형 언어에서는 꼬리 호출이라는 해결책을 제공한다.
꼬리재귀를 통해 컴파일러가 하나의 스택 프레임을 재활용할 가능성이 생기도록한다.
자바 8에서는 반복을 스트림으로 대체하여 변화를 피한다.
•
반복 → 재귀로 바꾸면 더 간결하고 부작용이 없는 알고리즘을 만들 수 있다.
•
약간의 실행 시간보다, 프로그래머의 효율성이 더 중요할 때도 많다.