나만보는개발공부블로그

Functional Programming 본문

Javascript&Typescript

Functional Programming

alexrider94 2021. 2. 11. 15:23

Functional Programming (FP) 는 소프트웨어를 구축하는 단계에서 순수한 기능(function)으로 구성되어지고 상태값(state),  변하는값(mutable data)을 공유되어지는것을 방지하거나 사이드 이펙트를 피해가는 것이라고 할 수 있다.

이러한 정의된 위의 원칙을 기반으로 소프트웨어를 구성하는 방법의 프로그래밍 패러다임이라고 할 수 있다.

 

* 다른 패러다임의 프로그래밍으로는 절차적 프로그래밍, 객체지향적 프로그래밍이 있다.

 

- 명령적(imperative)보단 선언(declarative)적이다.

- 객체지향 프로그래밍과 비교했을때 application state는 객체의 메서드와 보통 공유되고 배치되는 반면에 application state가 pure function들을 통해 흐른다.

 

- functional code들은 object oriented code들 보다 간결하고 예측 가능하며 테스트하기 쉬운 코드인 경향이 있는데 이러한 코드의 패턴과 익숙하지않으면 더 어려울수도 있다.

이러한 어려운 부분에서 익숙하지 않은 단어들이 존재하는데 functional programming의 주요 단어들은

 

  • Pure functions
  • Function composition
  • Avoid shared state
  • Avoid mutating state
  • Avoid side effects

이 존재하는데 functional programming을 제대로 알고 싶다면 위의 단어들을 숙지해가고 이해해 나가면서 진행하는것이 옳다.

 

이제 위의 단어들에 대해서 차례대로 설명할 것이다.

 

Pure Functions

- 동일한 입력(inputs)이 주어지면 항상 동일한 출력(output)을 반환해야하며 no-side-effects 가 되어야 한다.

- 참조 투명성(referential transparency)를 포함한 함수 프로그래밍에서 중요한 속성이 존재한다.

 

* 참조 투명성 - 프로그램의 의미를 변경하지 않고 함수 호출을 결과 값으로 바꾸는 것.

 

* Read “What is a Pure Function?” for more details.

Function composition

- 새로운 함수를 생성하거나 어떠한 결과값을 내기위해 둘 이상의 함수를 결합하는 과정

- 예를 들어 f*g라는 f와 g과 결합한 결합된 함수랑 f(g(x))랑 같다는것.

- 이 개념을 이해해야 함수형 프로그래밍을 설계 및 구축하는데 있어서 중요한 개념이라고 한다.

 

* 참고 문헌:  “What is Function Composition?”

 

Shared State

- 공유된 범위(shared scope) 안에 있거나 서로 전달되는 어떠한 변수(variables), 객체(objects), 메모리변수(memory space)들이 존재하는 경우다. 

- 공유 범위(shared scope)는 전역 범위(global scope) 또는 클로저 범위(closure scope)가 포함될 수 있다.

 

* 참고 문헌 :  “10 Tips for Better Redux Architecture”.

 

* 가끔 객체지향적 프로그래밍에서의 객체(object)는 다른 객체에 속성을 추가하거나 하여 scope간에 공유되기도 한다. 이러한 공유되는경우의 문제점으로 공유된 state가 함수가 사용하거나 영향을 미치는 모든 공유되는 variables들의 기록을 알아야하는것이다.

 

예시로 어떤 user의 객체를 가지고 있고 나는 saveUser()라는 기능을 만들어 서버에 API요청을 보내는동안 user의 프로필 사진을 변경하는 updateAvatar()를 실행하고 saveUser()를 또다시 요청햇다고 한다면 저장시에 서버에서 발생하는 변경 사항 및 다른 API의 응답으로 동기화하기위해 메모리에 있는 user 객체를 다시 보낸다. 불행하게도 두번째 saveUser()는 첫번째 saveUser()를 보내기전에 도착한다면 첫번째가 나중에 도착해 user 객체를 다시 반환하게 되고 메모리상에서 새로 업로드한 프로필사진은 지워지고 오래전껄로 대체되어지게 되는 오류가 발생한다. 

 

또 다른 에러로는 function을 call하게 될 경우 순서가 달라짐에 따라서 공유 상태에서 작동하는 함수가 타이밍에 의존하기 때문에 연속적인 오류가 발생할 수 있다는 것입니다.

 

- 타이밍에 의존성 있는 예시

const x = {
  val: 2
};

const x1 = () => x.val += 1;

const x2 = () => x.val *= 2;

x1();
x2();

console.log(x.val); // 6

// 위의 코드와 비슷하지만 한가지 다른점은
const y = {
  val: 2
};

const y1 = () => y.val += 1;

const y2 = () => y.val *= 2;

// function을 부르는 순서를 다르게 하는경우
y2();
y1();

// 결과값이 달라진다.
console.log(y.val); // 5

 공유상태(shared state)를 피할때는 타이밍과 함수를 부르는 순서에 의존하지않고 결과값이 변하지 않아야한다. Pure Function은 항상 동일한 입력값으로 동일한 반환값을 받아야하는데 이러한 것이 완전희 다른함수를 불러오는과정에서 의존성을 가지지 않기 때문이다.

 다음 코드는 타이밍에 의존성이 없는 코드이다.

const x = {
  val: 2
};

const x1 = x => Object.assign({}, x, { val: x.val + 1});

const x2 = x => Object.assign({}, x, { val: x.val * 2});

console.log(x1(x2(x)).val); // 5


const y = {
  val: 2
};

// Since there are no dependencies on outside variables,
// we don't need different functions to operate on different
// variables.

// Because the functions don't mutate, you can call these
// functions as many times as you want, in any order, 
// without changing the result of other function calls.
x2(y);
x1(y);

console.log(x1(x2(y)).val); // 5

 

위의 코드를 보면 Object.assign() 함수를 사용하고 빈 객체를 매개변수로 줘서 in-place복사가 아닌 x의 속성들을 복사한다. 이런 경우 새로운 객체를 만들게 되는데 이런식으로 mutation을 사용하지않고 이미 존재하는 state를 객체로 복사하는 패턴은 자바스크립트에서 일반적이다.

그리고 위의 console.log()의 내부 내용을 보면 f(g(x))처럼 Function composition을 사용한다. 위의 코드에서는  f()*g()가  x1(),x2()가 된다.

위의 코드에서 물론 함수를 사용하는 순서가 달라지면 결과 값이 달라지는 문제가 아직 존재하지만 변수들을 함수밖에서 사용할 경우에서의 문제는 없어지게된다.

 

* In-place : 추가 메모리를 사용하지않는 알고리즘

Mutating state

-immutable : 한번 생성되면 변하지 않는 경우

-mutable: 한번 생성되도 변할 수 있는 경우

 

immutability은 functional programming에서 중요개념으로 잡히는데 이것 없이는 프로그램에서의 데이터 흐름, state, 그리고 이상한 버그가 생기게 된다.

 

자바스크립트에서 const 랑 immutable이랑 헷갈리지 않는것이 중요하다. const는 생성 후에 재할당이 불가능한 변수를 만들어내고 바인딩을 하지만 변경 불가능한 객체를 생성하지는 않기 때문이다. 

바인딩은 참조하고 있는 객체는 변경할 수 없지만 속성은 변경할 수 있기 때문이다. 그래서 const는 mutable이고 immutable이라고 할 수 없다.

 

immutable한 객체를 만드는 코드는 아래처럼 할 수 있다.

const a = Object.freeze({
  foo: 'Hello',
  bar: 'world',
  baz: '!'
});

a.foo = 'Goodbye';
// Error: Cannot assign to read only property 'foo' of object Object

하지만 만약에 위의 코드의 속성값으로 또다른 객체를 선언한게 있다면 그것은 mutable이 된다. 그래서 모든 객체의 내부까지 다 freeze처리를 하지않는한 immutable을 만들어 낼수는 없다.

위의 문제를 해결하기 위해서 trie data structures 이라는 자료구조가 존재하는데 자바스크립트에서는 Immutable.js 와 Mori 같은 라이브러리가 존재한다.

 

 

 

* 참고 문헌 :  “The Dao of Immutability.”

Side effects

사이드 이펙트는 반환하는 결과값이 아니라 외부에서 state가 변하는 경우를 말한다.

몇가지 요소로는 다음과 같다.

  • 외부의 변수 및 객체의 속성 수정하는 경우 (전역변수 또는 부모함수의 변수)
  • 콘솔에서의 log
  • 파일을 쓰는 경우
  • 화면을 사용하는 경우
  • 네트워크를 사용하는 경우
  • 외부 프로세스의 트리거
  • 다른 함수 호출하는 경우

사이드 이펙트는 함수형 프로그래밍에서는 대부분 사용하지않도록 방지되므로 쉽게 테스트하고 리팩토링같은것을 할 수 있다.

Haskell 같은 다른 함수형 프로그래밍에서는 monads를 사용하여 사이드 이펙트를 분리해나간다고 한다.

 

결과적으로 사이드이펙트는 함수형 프로그래밍에서 내가 만든 프로그램에서 피해야하는 요소이고 피해갈수록 내가 만든 코드들이 리팩토링이나 디버그, 테스트, 확장성 그리고 유지하는데 있어서 더 유리해질것이다.

Reusability

함수형 프로그래밍에서는 공통으로 사용되는 함수들을 데이터처리를 하는데 있어서 효과적으로 하기위해 재사용(Reusability)하는 경향이 있다. 

 

-참고 사이트 문헌

medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0

 

Master the JavaScript Interview: What is Functional Programming?

“Master the JavaScript Interview” is a series of posts designed to prepare candidates for common questions they are likely to encounter…

medium.com

 

'Javascript&Typescript' 카테고리의 다른 글

Declarative and Imperative programming  (0) 2021.02.21
Closure  (0) 2021.02.19
Event loop - 2  (0) 2021.02.17
Event loop - 1  (0) 2021.02.16
[JS] for & forEach & map  (0) 2021.02.06