콘텐츠로 이동

계층형 설계와 재귀

코드의 구조를 어떻게 설계할 것인가는 함수형 프로그래밍에서도 중요한 주제입니다. 이 글에서는 계층형 설계 패턴과 재귀 함수를 다룹니다.

코드를 만들고, 테스트하고, 유지보수하기 쉬운 프로그래밍 방법을 선택하기 위해 미적 감각을 사용하는 것입니다.

함수 본문계층 구조함수 시그니처
길이화살표 길이함수명
복잡성응집도인자 이름
구체화 단계구체화 단계인잣값
함수 호출리턴값
프로그래밍 언어의 기능 사용
  • 조직화: 새로운 함수를 어디에 놓을지 결정, 함수를 다른 곳으로 이동
  • 구현: 구현 바꾸기, 함수 추출하기, 데이터 구조 바꾸기
  • 변경: 새 코드를 작성할 곳 선택, 적절한 수준의 구체화 단계 결정

한 계층의 함수가 바로 아래 계층의 함수만 호출하도록 합니다.

// Before - 여러 추상화 수준이 섞여 있음
function setPriceByName(cart, name, price) {
const cartCopy = cart.slice();
for (let i = 0; i < cartCopy.length; i++) {
if (cartCopy[i].name === name) {
cartCopy[i] = setPrice(cartCopy[i], price);
}
}
return cartCopy;
}
// After - 같은 수준의 추상화로 구현
function indexOfItem(cart, name) {
for (let i = 0; i < cart.length; i++) {
if (arrayGet(cart, i).name === name) return i;
}
return null;
}
function arraySet(array, idx, value) {
const copy = array.slice();
copy[idx] = value;
return copy;
}
function arrayGet(cart, i) {
const copy = [...cart];
return copy[i];
}
function setPriceByName(cart, name, price) {
const idx = indexOfItem(cart, name);
if (idx !== null) {
const item = arrayGet(cart, idx);
cart = arraySet(cart, idx, setPrice(item, price));
}
return cart;
}

세부 구현을 감춘 함수로 이루어진 계층입니다. 반복문이나 배열을 직접 다루는 코드를 추상화를 통해 감출 수 있습니다.

  • 라이브러리나 API를 만드는 것과 비슷
  • **“어떤 것을 신경 쓰지 않아도 되지?”**를 모아 함수로 만든 느낌
  • 추상화 벽에 코드를 만드는 것은 계약과 비슷 (새로운 함수를 만들 때 용어를 맞춰야 하는 등의 시간 소요)

추상화 벽에 가능한 적은 수의 함수를 노출합니다.

실용적인 관점에서 편리하게 사용할 수 있는 계층을 설계합니다.

가장 상단에 있는 것이 바꾸기 쉽습니다. → 자주 바뀌는 코드는 가능한 위쪽에 있어야 합니다.

가장 하단에 있는 함수를 테스트하는 것이 효율적입니다. → 영향을 주는 곳이 많기 때문에 한 번의 테스트로 많은 부분을 확인 가능합니다.

하단에 있을수록 재사용성이 높습니다. → 낮은 수준의 단계로 함수를 빼낼수록 재사용성이 높아집니다.

재귀 함수는 자기 자신을 호출하는 함수입니다. 함수형 프로그래밍에서는 반복문 대신 재귀를 사용하는 경우가 많습니다.

const factorial = function (num) {
if (num === 1) {
return 1;
}
return num * factorial(num - 1);
};
factorial(5); // 120
const countUp = (n) => {
if (n < 1) {
return [];
} else {
const countArray = countUp(n - 1);
countArray.push(n);
return countArray;
}
};
const array = countUp(5); // [1, 2, 3, 4, 5]

재귀 함수의 핵심은 두 가지입니다:

  1. 종료 조건(Base case): 재귀를 멈추는 조건
  2. 재귀 단계(Recursive case): 문제를 더 작은 단위로 나누어 자기 자신을 호출
  • 계층형 설계는 함수를 추상화 수준별로 배치하여 유지보수성, 테스트 가능성, 재사용성을 높입니다
  • 추상화 벽을 통해 세부 구현을 감추면 자료 구조 같은 세부 사항을 신경 쓰지 않아도 됩니다
  • 자주 변경되는 코드는 상위 계층에, 재사용되는 코드는 하위 계층에 배치합니다
  • 재귀 함수는 종료 조건과 재귀 단계로 구성되며, 반복문을 대체할 수 있습니다

다음 글에서는 Lodash와 Ramda를 활용한 실전 함수형 프로그래밍을 다룹니다.