Skip to content

chp.11 일급 함수 II ​

이전 장에서는 일급 함수를 활용해 코드의 냄새와 중복을 제거하고, 더 나은 추상화를 이끌어내는 리팩토링 방법을 살펴봤습니다. 이번 장에서는 그 연장선으로, 고차 함수를 중심으로 코드를 단순화하고 재사용성을 높이는 기법을 알아보겠습니다.

코드 냄새와 리팩터링 ​

앞 장에서는 중복을 줄이고 추상화를 강화하기 위해 일급 값과 고차 함수를 활용했습니다. Part II 전반에서 이 개념이 반복되므로, 다시 한번 정리해보겠습니다.

코드 냄새: 함수 이름에 숨어 있는 암묵적 인자 ​

  • 비슷한 동작을 하는 함수가 여러 개 존재한다.
  • 함수 이름 속에 price, shipping 같은 값이 암묵적으로 숨어 있다.

리팩터링: 암묵적 인자를 드러내기 ​

  • 함수 이름 속의 암묵적 인자를 명시적 인자로 바꾼다.
  • 본문에 하드코딩된 값을 인자로 치환해 중복을 없앤다.

리팩터링: 함수 본문을 콜백으로 바꾸기 ​

  • 본문 앞뒤의 고정된 코드를 분리하고, 가변적인 부분을 콜백 함수로 받는다.

카피 온 라이트 리팩터링하기 ​

챕터6: 불변성 유지하기에서는 카피-온-라이트 원칙을 통해 원본을 해치지 않는 불변성을 유지하는 방법을 배웠습니다.

그런데 배열의 경우, 복사본 생성 → 변경 → 반환이라는 패턴이 여러 함수에서 중복되기 때문에 고차 함수로 추출할 수 있습니다.

jsx
// 리팩토링 전
function add_element_last(array, elem) {
    var new_array = array.slice(); // 1. 복사본 만들기
    new_array.push(elem); // 2. 복사본 변경하기
    return new_array; // 3. 복사본 반환하기
}

---

// 리팩토링 후
function withArrayCopy(array, modify) {
  var copy = array.slice();
  modify(copy);
  return copy;
}

const new_copy = withArrayCopy(array, push);

withArrayCopy는 modify 콜백을 받는 고차 함수이므로, 배열에 push뿐 아니라 다른 동작도 쉽게 적용할 수 있습니다.

함수를 리턴하는 함수 ​

chp.10 일급 함수에서는 에러 로깅을 예시로 본문을 콜백으로 바꾸는 리팩터링을 살펴봤습니다.

jsx
function withLogging(f) {
  try {
    f();
  } catch (error) {
    logToSnapErrors(error);
  }
}

withLogging(function () {
  saveUserData(user);
});

이렇게 하면 중복된 try/catch를 제거되지만, 여전히 모든 코드마다 수동으로 withLogging()을 적용해야 하는 불편함이 남습니다.

이를 해결하는 더 나은 방법은 “함수를 받아 새로운 함수를 반환하는 고차 함수”로 만드는 것입니다.

jsx
function wrapLogging(f) {
  return function (arg) {
    try {
      f(arg);
    } catch (error) {
      logToSnapErrors(error);
    }
  };
}

var saveUserDataWithLogging = wrapLogging(saveUserDataNoLogging);

이제는 saveUserDataWithLogging()만 호출하면 언제나 에러 로깅이 적용됩니다.

즉, 고차 함수가 기존 함수에 부가 기능을 덧입히는 래퍼 역할을 하게 됩니다.

정리하며 ​

이번 장에서는 고차 함수를 중심으로 코드의 냄새를 제거하고 추상화를 강화하는 방법을 살펴봤습니다.

  • 콜백을 인자로 받는 함수로 반복되는 패턴 일반화
  • 함수를 반환하는 고차함수로 기존 함수에 새로운 동작을 덧입히는 방식