본문 바로가기

CS/Software Engineering

함수형 프로그래밍의 컨셉과 순수 함수 예시

 

다음은?

 

함수형 프로그래밍의 컨셉


변경 가능한 상태를 불변상태(immutable)로 만들어 side effect를 없애자

모든 것은 객체이다

코드를 간결하게 하고 가독성을 높여 구현할 로직에 집중시키자

동시성 작업을 보다 쉽게 안전하게 구현 하자


 

변경 가능한 상태를 불변 상태로 만들어 side effect를 없애자

어떤 input parameter가 주어지느냐에 따라 output (return value) 이 정해지는 구조로 한다.
그 외에 어떤 외부 상태도 함수의 return 값에 영향을 줄 수 없다.

 

모든 것은 객체이다

함수형 언어에서는 모든 것이 객체. → 클래스 외에 함수 또한 객체

  • 함수를 값으로 할당할 수 있다.
  • 함수를 parameter로 전달할 수 있다.
  • 함수를 return 값으로 반환할 수 있다.

사실 값으로 할당할 수 있고, parameter나 return 값으로 전달할 수 있는 것을 모두 만족한다면 1급 객체라고 부른다.
JAVA 8부터 함수도 이러한 성질을 충족할 수 있게 되었고(lambda, 함수형 인터페이스)
함수도 이제 JAVA에서 1급 객체(first-class citizen)다!

 

코드를 간결하게 하고 가독성을 높여 로직에 집중시키자

Lambda 및 Collection, Stream과 같은 API를 통해 보일러 플레이트를 제거하고, 내부에 직접적인 함수 호출을 통해 가독성을 높일 수 있다.

이렇게 함수형 프로그래밍을 도입하면 일을 위한 일들이 줄어들어 실제 구현할 로직에만 집중할 수 있다.

*보일러 플레이트 : 일종의 템플릿/상용구 코드. 예를 들면 Java의 getter와 setter이다. 꼭 필요하면서도 간단한 기능인데 많은 코드를 필요로 하는 친구들

 

동시성 작업을 보다 쉽고 안전하게 구현하자.

immutable을 이용하면 여러 스레드에서 접근을 하더라도 side effect를 발생시키지 않을 수 있다.
lock / unlock도 필요없어진다.

 

 

함수형 프로그래밍 코드 예시


순수 함수

var z = 10;
function add(x, y) { 
	return x + y;
}

add 함수는 오로지 주어진 parameter인 x, y만 이용하여 return값을 만들었다.
외부에 선언된 변수인 z는 전혀 건드리지 않는다. 이런 것을 순수함수라고 할 수 있다.

function justTen() { 
	return 10;
}

justTen 함수처럼 매개변수가 없는 경우에는 사용할 수 있는 변수가 없으므로 자연스레 상수를 return할 수 밖에 없다.

사실 매개변수가 없는 순수함수는 그저 상수를 return하기 때문에, 위와 같이 단순한 상황이라면 상수를 정의해서 사용하는 것이 더 나을 것이다.

function addNoReturn(x, y) {
	var z = x + y;
}

addNoReturn 함수는 return 값이 없는 함수인데, 이는 순수 함수이지만 아무 것도 return하지 않기 때문에 결국 쓸모가 없다.

대부분의 유용한 순수 함수는 최소 1개 이상의 매개변수를 가지고, 반드시 무엇인가를 반환해야한다.

 

function add(x, y) { 
	return x + y;
}
console.log(add(1, 2)); // prints 3
console.log(add(1, 2)); // still prints 3
console.log(add(1, 2)); // WILL ALWAYS print 3

add함수는 아무리 여러 번 호출하더라도 계속해서 똑같은 값을 return할 수 있다.

순수 함수는 같은 입력 값을 넣었을 때 항상 같은 출력 값을 반환한다.

 

writeFile(fileName); // 파일 쓰기
updateDatabaseTable(sqlCmd); // DB 수정
sendAjaxRequest(ajaxRequest); // 데이터를 서버로 전송
openSocket(ipAddress); // 소켓 얻기 위해 OS 호출

위의 함수들은 외부 상태를 이용하거나, 외부 변수를 수정하기 때문에 매 실행마다 값이 달라질 수 있다.
따라서, 위의 함수들은 모두 순수하지 않다.

 

불변성

앞서 함수형 프로그래밍에서는 side effect를 없애기 위해 객체를 immutable하게 관리한다고 했다.

마찬가지로 변수를 정의하고 값을 할당했다고 하더라도, 그 변수 또한 immutable하다. 상수라고 보면 된다.
그래서 함수형 프로그래밍엔 변수가 없다. 

함수형 프로그래밍은 수정된 변수가 있는 레코드 복사본을 하나 더 만듦으로써 레코드 내 변수 수정을 가능하게 한다. 레코드의 모든 것을 복사할 필요가 없기 때문에 효율적이다.

함수형 프로그래밍은 "값을 복사"하는 위와 동일한 방법으로 단일 속성 수정도 해결한다.

불변성을 위해, 함수형 프로그래밍에는 변수가 없다.

 

// simple loop construct
var acc = 0;
for (var i = 1; i <= 10; ++i) 
	acc += i;
console.log(acc); // prints 55

// without loop construct or variables (recursion)
function sumRange(start, end, acc) { 
	if (start > end) 
		return acc; 
	return sumRange(start + 1, end, acc + start)
}
console.log(sumRange(1, 10, 0)); // prints 55

같은 일을 하는 반복문과 재귀함수이다.

for문을 이용하는게 훨씬 쉽다고 생각할 수 있고, 친숙하기도 하다.
하지만 비 재귀 함수 반복은 결국 변함 (mutability) 을 요구해서 함수형 프로그래밍 패러다임에 그렇게 부합한다고 할 수 없다.

불변성을 위해서는 반복문 대신 재귀 함수를 사용하는 것이 알맞다.

 

불변의 장점

  • 프로그램 내 변수에 접근을 해야할 일이 있을 때, 읽기 권한만 가진다. 
    아무도 그 값을 수정할 수 없다. 그러므로, 실수로 값이 바뀔 일이 없다.
  • thread-safe하다. 다른 스레드가 그 값을 수정할 수 없고, 수정하려면 기존 값으로부터 새로운 값을 만들어낼 뿐이다.
불변성은 코드를 간단하고 안전하게 해준다.

 

함수형 프로그래밍을 왜 하려는 걸까?


이 부분은 내 뇌피셜이 심히 포함되어 있다

사람마다 함수형 프로그래밍을 왜 하겠다고 생각했는지는 다를 수 있지만, 이 이유가 현실적이라고 생각다.

기존의 방법 (절차지향이든 OOP이든) 대로 작성된 코드는 수많은 side effect의 위험을 내포하고 있다.
이는 이러한 side effect의 위험을 줄여주고, 좀 더 가독성을 높여주기 때문에 협업 시 분명 도움이 될 것이라 생각한다.
(물론 혼자 작업할 때도)

물론 보통 아직 대부분은 코드 열어보면 다 절차지향이나 객체지향일 것은 뻔하지만.. 앞으로 나아가면 좋을 방향인 것에는 동의한다.

 


 

References


'CS > Software Engineering' 카테고리의 다른 글

MSA / 마이크로 서비스 / 마이크로 아키텍처  (0) 2019.10.27