함수형 프로그래밍 (Functional Programming)
함수형 프로그래밍: 프로그래밍 패러다임 중 하나로, 선언형 프로그래밍에 속하며 자료 처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리한다.
프로그래밍에 익숙한 사람이라면, 기존 절차적 프로그래밍(ex. C언어)과 객체 지향형 프로그래밍(Java, C++, Python)는 익숙 할 것이다.
함수형 프로그래밍은 이런 기존의 프로그래밍 패러다임과는 새로운 방식으로, 다른 방식의 사고하는 방법을 배우는 것이다.
다양한 사고방식으로 프로그래밍을 바라본다면, 더욱 유연한 문제해결이 가능하다.
순수 함수 (Pure Function)
함수형 프로그래밍은 순수 함수로 이루어져 있다. 순수 함수란 부수효과가 없는 함수이며, 이는 즉 동일한 input(인자 값)에 대해 동일한 output(리턴 값)을 리턴하는 함수를 말하며, 외부의 상태를 변경하지 않는 함수이다.
다음과 같은 함수는 순수 함수이다.
function add(a, b){
return a+b;
}
console.log(1+2); // 3
외부 상태에 의존하는 부분이 없고, 영향을 주지 않아 부수 효과가 없다.
순수 함수가 아닌 예시를 보자.
let state = 1;
function mul(a){
return a * state;
}
console.log(mul(1)); // 1
console.log(mul(2)); // 2
state = 2;
console.log(mul(1)); // 2
console.log(mul(2)); // 4
다음과 같은 mul()
함수는 순수 함수가 아니다. 외부 상태에 따라 결과 값이 변하기 때문이다.
let state = 10;
function mul(a, b){
state += b;
return a * b;
}
console.log(mul(1,2), state); // 2, state = 12
console.log(mul(1,2), state); // 2, state = 14
다음 코드 또한 순수 함수가 아니다. 외부 상태에 변경을 주기 때문이다.
그렇다면, 객체의 데이터를 조작하고 싶을 때는 어떻게 할까?
예측 했을 수 있겠지만, 순수 함수내에서는 객체 값을 참조한다. 참조된 객체를 바탕으로 원하는 연산을 새로운 객체에 담아 반환하는 것이다.
let obj1 = { val : 1 };
function addVal(obj){
return { val : obj.val + 1 };
}
console.log(addVal(obj1)); // {val: 2}
console.log(obj1); // {val: 1}
이렇게 만들어진 순수 함수는 입력 값에 대한 결과를 예측 할 수 있어 테스트가 용이하다.
무상태와 불변성 (Stateless & Immutability)
앞선 예시에서 볼 수 있드시, 함수형 프로그래밍에서는 데이터가 변하지 않는 불변성을 유지해야 한다. 그리고 데이터를 조작하기 위해서는, 데이터의 참조값을 통해 새로운 데이터(복사)를 이용한다.
일급 객체와 고차 함수
일급 객체는 다음과 같은 특징을 갖는다.
- 무명의 리터럴로 생성 할 수 있다.
- 변수나 자료구조 (객체, 배열)에 저장할 수 있다.
- 함수의 매개변수에 전달 할 수 있다.
- 함수의 반환값으로 사용할 수 있다.
고차 함수는 다음과 같은 특징을 갖는다.
- 함수를 인자로써 전달 할 수 있다.
- 함수의 반환 값으로 또 다른 함수를 사용 할 수 있다.
이처럼 함수형 프로그래밍 방식을 채택하게 되면, 높은 수준의 모듈화가 진행 될 수 있다. 그렇다면 당연히 재사용성도 높고, 읽기 좋은 코드가 생성될 것 이다. 이러한 함수형 프로그래밍은 다음과 같은 이점을 준다.
- 높은 수준의 추상화
- 높은 함수 단위의 재사용성
- 프로그램의 동작 예측 수월
하지만 당연히 단점도 존재한다.
- 코드의 가독성이 좋지 않아 질 수도 있다.
- 재귀문의 잘못된 코드 스타일은 무한 루프에 빠지기도 한다.
- 순수 함수 끼리의 조합은 높은 cost를 갖을 수 있다.
개인적인 생각으로 가장 합리적이고, 유지보수적으로 좋은 프로그래밍 패러다임이라고 생각한다. 유지보수를 위해 새로운 서비스를 리뷰 할 때, 가장 답답한 부분 중 하나는 depth이다.
DOM트리의 구조가 깊을 수록, 컴포넌트의 구조가 깊을 수록, props drilling이 일어날 수록 코드는 정말 이해하기 어렵고, 많은 시간이 걸린다. 이러한 부분들을 모듈화하여, 비즈니스 로직에서 분리하고, 각 부분들에 대한 예측과 이해를 따로 할 수 있다는 점이 큰 메리트로 다가왔다.
진행하게 될 리팩토링 및 개발 부분에도, 항상 염두하며 좋은 함수형 코드들을 짜도록 하고자 한다.
'Software Engineering' 카테고리의 다른 글
Git 브랜치 전략, Git-flow (0) | 2022.09.03 |
---|---|
성능을 위한 프론트엔드 설계와 코드 - 1 (0) | 2022.08.28 |
Quality Assurance (QA: 품질보증) (0) | 2022.08.26 |
명령형 프로그래밍 VS 선언형 프로그래밍 (2) | 2022.08.15 |
리팩토링(Refactoring) 이란? (0) | 2022.08.14 |