부수 효과 (Side Effect), 참조 투명성 (Referential Transparency)

함수형 프로그래밍 (Functional Programming) 의 정의를 설명할 때, 중요하게 언급되는 2가지 개념을 설명하려고 한다. 바로 “부수 효과” 와 “참조 투명성” 이다.

먼저 “부수 효과” 는 함수 내의 실행으로 인해 함수 외부가 영향을 받는 것을 의미한다. 함수의 매개 변수의 값이 변경되어, 이로 인해 함수를 사용하는 코드에 영향을 주거나, 함수의 외부 세계인 데이터베이스, 파일 시스템, 네트워크로 데이터 이동이 함수 실행 중에는 발생하지 않아야 함수형 코드가 된다.

public static int add(int a, int b) {
  while (b > 0) {
    a++;
    b--;
  }
  return a;
}

위의 메쏘드는 함수적이다. 정수형 a, b 를 매개 변수로 받은 후, 그것들의 값을 변경하지 않고 결과를 반환한다. a, b 값을 변경한다고 해도 함수적이다. 왜냐하면 Java 에서는 원시 타입의 매개 변수는 pass by value 형태로 전달되기 때문에, 함수 내에서 값을 변경해도 함수를 벗어난 후에는 영향을 주지 않는다.

public static int div(int a, int b) {
  return a / b;
}

위의 함수는 함수적이지 않다. b의 값이 0인 경우 divide by zero 예외가 발생하는데, 예외를 발생시키는 것은 함수적이지 않다. 위의 코드는 아래와 같이 변경할 수 있다.

public static int div(int a, int b) {
  return (int) (a / (float) b);
}

b의 값이 0이어도 예외가 발생하지 않으며, 특별한 값이(2147483647) 반환된다. 이 값을 처리하는 것은 함수 사용자의 몫이다.

함수형 프로그래밍 (Functional Programming) 의 중요한 특징 중에서 2번째로 언급되는 것은 바로 “참조 투명성” 이다. “참조 투명성”은 함수 (또는 메쏘드) 가 함수 외부의 영향을 받지 않는 것을 의미한다. 다른 말로 하면, 함수의 결과는 입력 파라미터에만 의존하고, 함수의 외부 세계인 입력 콘솔, 파일, 원격 URL, 데이터베이스, 파일 시스템 등에서 데이터를 읽지 않는다. 함수 외부의 값을 변경하거나, 외부 세계의 의존적이지 않은 코드를 가리켜 “참조 투명성 있다” 라고 말한다.

참조 투명성을 가진 코드는 아래와 같은 특징들을 지닌다.

  • 자기 충족적이다 (self-contained). 함수 외부에 의존하는 코드가 없고, 함수 사용자 입장에서는 유효한 매개변수만 전달하면 된다.
  • 결정론적이다 (deterministic). 동일한 매개변수에 대해서는 항상 동일한 결과가 나온다.
  • 예외 (Exception) 를 던지지 않는다. out of memory error 혹은 stack overflow error 는 발생할 수 있지만, 이러한 에러들은 버그로 취급되며, 함수의 사용자가 다룰 수 있는 것은 아니다.
  • 다른 코드가 예기치 않게 실패하는 조건을 만들지 않는다. 예를 들어, 참조 투명성을 가진 함수는 매개 변수의 값을 변경하거나 함수 외부의 데이터를 변경하지 않는다.
  • 데이터베이스, 파일 시스템, 네트워크 등의 외부 기기로 인해 동작이 멈추지 (hang) 않는다.

함수형 프로그래밍을 통해서 얻을 수 있는 이득은 아래와 같다.

  • 함수형 프로그램은 결정론적이기 때문에, 원인을 찾기가 더 쉽다. 함수형 코드는 특정한 입력에 대해서 항상 동일한 결과를 반환한다. 많은 경우 프로그램을 광범위하게 테스트하는 대신 올바른 프로그램임을 증명할 수 있으며, 예기치 않은 상황에서 프로그램이 중단될지 여부를 여전히 확신하지 못할 수 있다.
  • 함수형 프로그램은 테스트 하기가 쉽다. 부수 효과가 없기 때문에, mock 을 만들지 않아도 된다.
  • 함수형 프로그램은 조립하기가 더 쉽다. 함수형 프로그램은 함수들의 조합으로 구성된다. 다루어야할 부수 효과가 없고, 예외가 없으며, 값의 변경이 일어나지 않는다. 동시성 문제도 발생하지 않는다.
  • 함수형 프로그램은 구성, 재구성이 쉽다. 함수형 프로그램을 작성할 때, 기반이 되는 함수들을 먼저 작성한 후에, 상위 레벨에서 함수들을 조합한다. 원하는 함수를 가질 때까지 함수들을 조합한다. 모든 함수는 참조 투명하기 때문에, 다른 프로그램을 작성할 때도 코드의 변경없이 재사용하기가 쉽다.

위의 내용은 Functional Programming in Java: How functional techniques improve your Java programs 1st Edition 에서 발췌, 번역, 요약한 것입니다.