쏙쏙 들어오는 함수형 코딩 - 8

binary·2022년 6월 12일
0
post-thumbnail

Chapter 8 계층형 설계 (1)

이 책에서는 소프트웨어 설계를 코드를 만들고, 테스트하고, 유지보수하기 쉬운 프로그래밍 방법을 선택하기 위해 미적 감각을 사용하는 것이라고 말한다. 소프트웨어 설계를 위한 미적 감각은 계층형 설계를 통해 키울 수 있을 것이라 기대한다.

여기서 계층형 설계는 소프트웨어를 계층으로 구성하는 기술을 말한다.

설계 감각 키우기

다양한 입력 생각해보기

  • 함수 본문
    • 길이
    • 복잡성
    • 구체화 단계
    • 함수 호출
    • 프로그래밍 언어의 기능 사용
  • 계층 구조
    • 화살표 길이
    • 응집도
    • 구체화 단계
  • 함수 시그니처
    • 함수명
    • 인자 이름
    • 인잣값
    • 리턴값

다양한 출력 생각해보기

  • 조직화
    • 새로운 함수를 어디에 놓을 지 결정
    • 함수를 다른 곳으로 이동
  • 구현
    • 구현 바꾸기
    • 함수 추출하기
    • 데이터 구조 바꾸기
  • 변경
    • 새 코드를 작성할 곳 선택하기
    • 적절한 수준의 구체화 단계 결정하기

계층형 설계 패턴

패턴 1. 직접 구현

직접 구현된 함수를 읽을 때, 함수 시그니처가 나타내고 있는 문제를 함수 본문에서 적절한 구체화 수준에서 해결해야 한다.

패턴 2. 추상화 벽

계층형 설계를 할 때 어떤 계층에서는 세부 구현을 감추고 인터페이스를 제공한다.

패턴 3. 작은 인터페이스

비즈니스 개념을 나타내는 중요한 인터페이스는 작고 강력한 동작으로 구성하는 것이 좋다.

패턴 4. 편리한 계층

계층을 잘 나누고 각 계층이 하는 일을 잘 추상화 해야 한다.

패턴 1. 직접 구현

아래는 넥타이 하나를 사면 무료로 넥타이 클립을 하나 주는 코드이다.

function freeTieClip(cart) {
  var hasTie = false
  var hasTieClip = false;
  for(var i = 0; i < cart.length; i++) {
    var item = cart[i];
    if(item.name === "tie")
      hasTie = true;
    if(item.name === "tie clip")
      hasTieClip = true;
  }
  if(hasTie && !hasTieClip) {
    var tieClip = make_item("tie clip", 0);
    return add_item(cart, tieClip);
  }
  return cart;
}

한 함수에서 아주 많은 일들을 하고 있다. 장바구니를 돌고, 항목을 체크하고, 또 무언가를 결정하고...

이 코드는 첫번째 계층형 설계 패턴인 직접 구현을 따르지 않고 있다. 게다가 마케팅과 관련된 함수인데 배열인 장바구니를 순회하는 등 너무 구체적인 내용을 담고 있다.

장바구니 설계 개선

  • 제품 추가하기
function add_item(cart, item) {
  return add_element_last(cart, item);
}
  • 제품 삭제하기
function remove_item_by_name(cart, name) {
  var idx = null;
  for(let i = 0; i < cart.length; i++) {
    if(cart[i].name === name)
      idx = i;
  }
  if(idx !== null)
    return removeItems(cart, idx ,1);
  return cart;
}
  • 장바구니에 제품이 있는지 확인하기
    아직 구현하지 않음

  • 합계 계산하기

function calc_total(cart) {
  var total = 0;
  for(var i = 0; i < cart.length; i++) {
    var item = cart[i];
    total += item.price;
  }
  return total;
}
  • 장바구니 비우기
    아직 구현하지 않음

  • 제품이름으로 가격 설정하기

function setPriceByName(cart, name, price) {
  var cartCopy = cart.slice();
  for(var i = 0; i < cartCopy.length; i++) {
    if(cartCopy[i].name === name)
      cartCopy[i] = setPrice(cartCopy[i], price);
  }
  return cartCopy;
}
  • 세금 계산하기
function cartTax(cart) {
  return calc_tax(calc_total(cart));
}
  • 무료 배송이 되는지 확인하기
function gets_free_shipping(cart) {
  return calc_total(cart) >= 20;
}

장바구니에 제품이 있는지 확인하기 구현하기

function freeTieClip(cart) {
  var hasTie = false
  var hasTieClip = false;
  for(var i = 0; i < cart.length; i++) {
    var item = cart[i];
    if(item.name === "tie")
      hasTie = true;
    if(item.name === "tie clip")
      hasTieClip = true;
  }
  if(hasTie && !hasTieClip) {
    var tieClip = make_item("tie clip", 0);
    return add_item(cart, tieClip);
  }
  return cart;
}

방금 구현한 freeTieClip() 함수를 보니 직접 구현 패턴을 적용할 수 있을 것 같다.
장바구니 안에 제품이 있는지 확인하는 함수가 있다면 계층의 저수준인 for문을 사용하지 않아도 된다.

function isInCart(cart, name) {
  for(var i = 0; i < cart.length; i++) {
    if(cart[i].name === name)
      return true;
  }
  return false;
}

위처럼 함수에서의 for문 빼내어 함수를 만들고 아래처럼 직접 구현 패턴을 적용할 수 있다.

function freeTieClip(cart) {
  var hasTie = isInCart(cart, "tie");
  var hasTieClip = isInCart(cart, "tie clip");
  if(hasTie && !hasTieClip) {
    var tieClip = make_item("tie clip", 0);
    return add_item(cart, tieClip);
  }
  return cart;
}

호출 그래프

지금까지 작성한 함수들을 계층을 나누어 생각해볼 수 있다.

  1. 장바구니 비즈니스 규칙
  2. 일반적인 비즈니스 규칙
  3. 장바구니 기본 동작
  4. 제품에 대한 기본 동작
  5. 카피-온-라이트 동작
  6. 자바스크립트 언어 기능

함수 그래프를 그려 함수 호출을 시각화해보면 아래와 같다.

같은 계층에 있는 함수는 같은 목적을 가졌고, 함수가 호출하는 함수를 화살표로 가리켰다.

위 그래프는 그렇지 않지만, 직접 구현 패턴을 사용하면 모든 화살표가 같은 길이를 가져야 한다.
이 그래프처럼 화살표가 다양한 계층을 넘나드는 것은 어떤 것은 너무 많이 구체화 했고, 어떤 것은 덜 구체화했다는 증거이다.

직접 구현 패턴이 지향하는 것은 상위 계층에 있는 함수가 바로 아래 계층의 동작에 의존하게 만드는 것이다. 쉽게 말하면 모두 같은 길이의 화살표를 가져야 한다.

🤷‍♀️ 어떻게 같은 길이의 화살표를 가지게 만드나요?

일반적인 방법으로는 함수에서 코드를 추출하여 추출한 코드를 가진 함수를 추가하여 화살표 길이를 짧게 만드는 것이다.

이렇게 화살표 길이를 줄이는 것에 집중하면 더 좋은 계층 구조를 만들 수 있다.
화살표 길이를 줄이다보면 오히려 구조가 더 복잡해지는 경우도 있지만, 일단은 화살표 길이를 줄이는 것에 집중해야 한다. 계층형 설계에서 모든 계층은 바로 아래 계층에 의존해야 한다.

직접 구현 패턴을 사용하면 좋은 점

  1. 직접 구현한 코드는 한 단계의 구체화 수준에 관한 문제만 해결한다.

  2. 계층형 설계는 특정 구체화 단계에 집중할 수 있게 도와준다.

  3. 함수를 추출하면 더 일반적인 함수로 만들 수 있다.


혹시나 잘못된 정보가 있다면 댓글로 알려주세요 ! 저의 성장의 큰 도움이 될 것 같습니다.🌱

0개의 댓글