애플리케이션의 부수효과를 방지하고, 상태 변이를 감소하기 위해 데이터의 제어 흐름과 연산을 추상하는 것이다.
부수효과
상태 변이 감소
데이터의 제어 흐름과 연산 추상
솔직히 아직 뭔소리인지 잘모르겠지만, 일단 이정도 하고 넘어간다.
더 작은 프로그램 조각
으로 나눈 다음에 그 조각들을 run, pipe, compose 등의 함수형 툴을 이용해 조합해서 쓰는 버릇을 들이면, 매번 앞서 말한 절차형의 분기처리를 복붙해서 다시 쓴다던지, 혹은 복붙하면서 아주 살짝 다른 로직을 처리하기 위해 flag를 쓴다던지 할 필요가 없다. 그냥 새로운 기획 혹은 새로운 분기처리를 위한 함수 조각을 하나 더 만들어서 새로운 조합, 예를 들어, 앞선 조합이 조합 A 였으면 이젠 조합 B로 만들어서 쓰면 된다. 이런 부분에 있어서 재사용성, 확장성이 좋다고 하는 것 같다. 함수에 함수 파라미터를 넣을수도 있다는 것을 생각해보면, 함수형 프로그래밍은 작은 함수 조각들로 확장성 좋은 함수 블록 놀이(?)를 하는거라고 생각해볼 수 있다. const getMainQuestion = (ev: Event) =>
checkIsEmptyString((ev.target as HTMLInputElement).value)
.chain(validateMainQuestion)
.orElse(setMainQuestionErrorMessage)
.chain(resetMainQuestionErrorMessage);
위에 함수는 내가 만든 함수인데, 쉽게 설명해보면, question이라는 값을 input tag로 받아서(input event handler 함수이다) 인풋 값에 대해서 빈값인지 확인하고(checkIsEmptyString) 빈값이면 Either.left를 반환한다(⇒ 더이상 진행하는게 의미가 없다는 의미로 이해하자).export const checkIsEmptyString = (value: string) => (value.length === 0 ? Either.left('') : Either.of(value));
그러면 그 다음 chain을 건너띄고, orElse 문으로 간다. 거기서는 setMainQuestionErrorMessage
이를 통해 input UI 밑에 보여줄 에러 메세지를 세팅하는데, 방금 경우에는 left 안에 빈 string(’’)을 넣어줬으므로 에러 메시지가 출력되지 않는다. 그럼 방금 checkIsEmptyString에서 빈배열이 아니었어서 Either.of(=Either.right) 를 리턴하고, 다음 체인으로 넘어갔다고 해보자. 그럼 다음 체인에서는 validateMainQuestion
을 통해 해당 인풋값을 정해진 로직으로 유효성 검사를 실행한다. 이 때, 유효성 검사를 통과하면 Right를 리턴해서 orElse를 통과하고, 실패하면 에러 메시지와 함께(해당 유효성 검사에 맞는) orElse에 걸린다. 그리고 마지막에 있는 resetMainQuestionErrorMessage
이건 만약 input 값에 에러가 없어서, 즉, 유효성 검사를 통과한 경우 orElse를 통과해서 마지막에 에러 메시지를 ‘’로 리셋해주기 위한 로직이다. 이걸 실행하는 이유는 input을 입력하다가 에러가 생겨서 에러메시지를 화면에 출력했는데, 다음 input이 추가되고서는 유효성 검사를 통과했다면 이전 에러 메시지는 지워줘야하기 때문에 reset 로직을 추가해둔 것이다. 설명이 길었는데 포인트는 여태까지 설명한 로직들은 저 함수의 이름들만으로 선언적으로 이해할 수 있고, 굳이 저 안에 내부 로직을 설명할 필요도 알아볼 필요도, 알아볼수도 없다는게 선언적 프로그래밍의 포인트라고 할 수 있다. 만약 저게 절차형 프로그래밍이었으면, if(value === ‘’) return 이런식의 로직들이 있을 것이고, 그 절차를 따라가면서 코드를 이해해야 했을 것이다. 하지만, 지금은 아 checkIsEmptyString → 아 빈 스트링인지 확인하고, chaining으로 유효성 검사를 하는구나 등등 선언적으로 로직을 파악할 수 있고, 그 내부를 알 필요가 없다(물론 내가 변수명을 잘지었는지는 논외다).무상태성
과 불변성
을 지향한다.예시
```jsx
export const isValid = <T>(value: T) => value !== undefined && value !== null;
```
그리고 위에 순수함수를 이용해서 만든 또다른 순수함수는 아래와 같다.
```jsx
export const returnArrayOrEmptyArray = <T>(value: NullAndUndefined | T[]): T[] => {
return isValid(value) ? value : [];
};
```
그러나 현실적으로, 순수함수로만 프로그램을 만들순 없다. 생각해보면, 유저 인터페이스에 따른 state 변동 및 state를 참조하는 함수들 등.. 수많은 불순함수가 존재하는 FE 프로젝트에서,, 순수함수만으로 프로그래밍으로 한다는건 어불성설이다.. 하지만, 어차피 모두 순수함수로 만들자도 아니고, 단지 이둘을 구분해서 알아두고, 구분해서 개발하자는 취지로 알고 넘어가면 될 것 같다.
참조 투명성 : 숨수함수를 정의하는 좀 더 공식적인 방법으로 위에서 설명한 것 과 같다.