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);

withArrayCopymodify 콜백을 받는 고차 함수이므로, 배열에 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()만 호출하면 언제나 에러 로깅이 적용됩니다.

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

정리하며

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

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