함수형 코딩 스터디 (쏙쏙책) 1일차

chichi·2024년 7월 4일

함수형 코딩

좋은 설계에 관한 글을 찾다보면 꼭 나오는 키워드였던 것 같다. 이전부터 함수형 코딩의 공부에 대한 갈망은 있었는데 바쁘다는 이유로 미루곤 했었다.

이번에 좋은 기회로 함수형 코딩의 스터디에 참여하게 되었고, ‘쏙쏙 들어오는 함수형 코딩’ 이라는 책으로 스터디를 진행하기로 했다.

이번 주는 3. 액션과 계산 데이터의 차이를 알기, 4. 액션에서 계산 빼내기, 5. 더 좋은 액션 만들기 까지가 범위였고, 스터디를 통해 배운 것들을 정리하는 겸, 새로 알게된 사실을 기록하고자 블로그를 작성하기로 했다.

배운 내용들을 간단하게나마 꾸준히 적고, 알차게 완독까지 마무리 하는 것이 목표!


암묵적 인자, 암묵적 출력이 아닌 명시적 인자, 명시적 출력 사용하기

  • 전역 변수에 의존하지 않아야 한다
  • 암묵적 인자와 출력은 인자와 리턴값으로 바꾼다
  • 하나의 함수에 액션이 있게 되면, 그 함수는 액션이 된다. (액션은 번진다)
    함수는 하나의 일만 수행해야 한다

왜 함수형 코딩을 해야할까?

  • 코드는 데이터, 계산, 액션 이라는 관점으로 나눌 수 있고 엉켜있는 코드를 분리하게 되면 코드를 잘 구성할 수 있게 된다.
  • 테스트를 쉽게 할 수 있다. 함수형으로 분리된 코드 조각만 가지고 테스트 할 수 있어야 한다.
  • 부수 효과를 지양함으로서 예측이 가능한 함수로 만들어준다.
  • 재사용 할 수 있는 유틸리티 utility 함수로 사용이 가능하다.
  • 코드가 작아짐으로서 유지보수 하기가 쉬워진다.

아래는 함수 체이닝을 사용한 함수형 코드의 예제이다.

함수 체이닝은 함수형 프로그래밍의 기법 중 하나로 객체 자체를 반환하는 메서드를 연속적으로 호출할 수 있는 기법이다. 배열 메서드 체이닝을 통해 순수 함수와 불변성을 지킬 수 있게 된다.

// 함수형 코드
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const isOdd = (num) => num % 2 !== 0;
const cube = (num) => num * num * num;
const sum = (acc, current) => acc + current;

const sumOfCubes = numbers
  .filter(isOdd)
  .map(cube)
  .reduce(sum, 0);

console.log(sumOfCubes);

그리고 아래는 명령형 코드로 작성되어 있다.

// 명령형 코드
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let sumOfCubes = 0;

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] % 2 !== 0) {
    const cube = numbers[i] * numbers[i] * numbers[i];
    sumOfCubes += cube;
  }
}

console.log(sumOfCubes);

두 함수를 비교했을 때 함수형 코드가 더 좋지! 라고 생각했는데 조금 더 찾아보니, 함수형 코딩만이 정답만은 아닌 것 같았다. (은탄환은 없다)

함수형 프로그래밍의 핵심은 순수 함수

  • 반복문을 통한 코드 vs 함수형 프로그래밍으로 구현된 함수
    • 두 코드의 성능을 비교했을 때 성능적으로 우수한 것은 명령형 접근 방식인 전자
      • 명령형은 배열을 한 번만 순회하며, 추가적인 배열 생성 없이 결과를 누적
      • 함수형은 배열을 여러 번 순회해야 하고, 각 단계에서 새로운 배열을 생성함
    • 가독성이 좋은 것은 병렬적으로 작성된 함수형 코드
    • 반복문의 성능과 함수형의 장점을 가져가기 위해 라이브러리를 사용하는 방법도 있다.
    • 함수형으로 작성하는 것이 꼭 정답은 아니다
      • 함수형 프로그래밍에 대해 찾다보니, 함수를 마구 분리한다고 해서 함수형 프로그래밍의 본질에 닿는 것은 아니라고 한다. 함수형 프로그래밍의 핵심은 순수함수이지 고차 함수가 아니다. (NvironmentE님)

키워드 정리

  • 카피 온 라이트
    • 방어적 복사 (원본 데이터를 보호), 전역적으로 선언된 변수를 변경하지 않고 카피한 뒤 사용함으로서 함수형 프로그래밍의 순수성을 지킬 수 있게 된다
      • 최근에 더미 데이터를 이용한 코딩 중 sort 메서드를 사용할 일이 있었는데 sort로 정렬하지도 않았던 데이터가 무조건 정렬되어서 나오는 이상한 현상이 있었다. (어라)
      • 알고보니 sort는 원본 배열을 훼손시키는 메서드였고 이미 훼손된 원본 배열에 접근했던 것이 문제였다. 스프레드 연산자 (…) 를 통해서 복사한 뒤 사용했더니 해당 문제가 해결되었다.

  • 제너레이터 함수
function* myGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

const gen = myGenerator();

console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
console.log(gen.next().value); // undefined
  • 코드의 실행을 일시 중지하고 제어하는 함수. (다음, 다음 하고 부르는 것처럼 생겼다)
  • 정의할 때 function*, 내부에서 값을 반환하고 실행을 중지할 때 yield, 함수의 실행을 다시 시작하고 yield 값을 반환할 때 next() 를 사용한다.

혼자서는 100페이지까지도 읽기 힘들었던 걸 스터디 날이 다가올 수록 점점 초조해지더니 (?) 한번에 2챕터를 다 읽어버렸다.
다른 분들도 책 읽었나 궁금해서 봤는데 스터디 시작 직전 열심히 독서 중인 분도 계셨다. (나만 벼락치기 우르릉쾅쾅 한 거 아니구나ㅋㅋㅋ)

완독하면 맛있는 디저트를 먹어야겠다
끝!

0개의 댓글