> For the complete documentation index, see [llms.txt](https://jaemedevs-organization.gitbook.io/frontend_study/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jaemedevs-organization.gitbook.io/frontend_study/book/functional-programming/ch8.md).

# Chapter 8: 계층형 설계 I

## 🍄 1. 소프트웨어 설계란 무엇일까?

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

## 🍄 2. 계층형 설계란 무엇일까?

* 계층형 설계는 소프트웨어를 계층으로 구성하는 기술이다.
* 각 계층에 있는 함수는 바로 아래 계층에 있는 함수를 이용해 정의한다.
* 설계 감각을 키우면 소프트웨어를 고치고, 읽고, 테스트하고, 재사용하기 쉬운 코드를 만들기 위한 계층 구조가 무엇인지 알 수 있다.
* 각 계층을 정확히 구분하기는 어렵다. 계층을 잘 구분하려면 구분하기 위한 다양한 변수를 찾고 찾은 것을 가지고 어떻게 해야 하는지 알아야 한다.
* ‘가장 좋은 설계’를 위한 절대 공식과 그 공식을 만드는 변수는 많이 있지만 복잡하게 섞여 있어 찾기 어렵다. 하지만 좋은 설계를 위한 감각을 개발하고 그 감각을 따라겸 찾을 수 있다.

## 🍄 3. 설계 감각을 키우기

### 🌻 3-1. 전문가의 저주

* 전문가는 본인의 전문 분야를 잘 알지만, 설명은 잘 못하는 것으로 악명 높다. 전문가는 오랜 시간 노력으로 축적된 지식이 있지만, 그것을 다른 사람들에게 설명하는 방법을 모른다. 이것이 전문가의 저주이다.

### 🌻 3-2. 계층형 설계 감각을 키우기 위한 입력

* 계층형 설계 감각을 키우기 위해 다양한 입력을 생각해 볼 수 있다. 그리고 이러한 입력들이 계층형 설계에 대한 단서가 된다.
* 함수 본문
  * 길이
  * 복잡성
  * 구체화 단계
  * 함수 호출
  * 프로그래밍 언어의 기능 사용
* 계층 구조
  * 화살표 길이
  * 응집도
  * 구체화 단계
* 함수 시그니처
  * 함수명
  * 인자 이름
  * 인잣값
  * 리턴값

### 🌻 3-3. 계층형 설계 감각을 키우기 위한 출력

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

## 🍄 4. 계층형 설계 패턴

### 🌻 4-1. 직접 구현

* 직접 구현은 계층형 설계 구조를 만드는데 도움이 된다. 직접 구현된 함수를 읽을 때, 함수 시그니처가 나타내고 있는 문제를 함수 본문에서 적절한 구체화 수준에서 해결해야 한다. 만약 너무 구체적이라면 코드에서 나는 냄새이다.

### 🌻 4-2. 추상화 벽

* 호출 그래프에 어떤 계층은 중요한 세부 구현을 감추고 인터페이스를 제공한다.
* 인터페이스를 사용하여 코드를 만들면 높은 차원으로 생각할 수 있다.
* 고수준의 추상화 단계만 생각하면 되기 때문에 두뇌 용량의 한계를 극복할 수 있다.

### 🌻 4-3. 작은 인터페이스

* 시스템이 커질수록 비즈니스 개념을 나타내는 중요한 인터페이스는 작고 강력한 동작으로 구성하는 것이 좋다.
* 다른 동작도 직간접적으로 최소한의 인터페이스를 유지하면서 정의해야 한다.

### 🌻 4-4. 편리한 계층

* 계층형 설계 패턴과 실천 방법은 개발자의 요구를 만족시키면서 비즈니스 문제를 잘 풀 수 있어야 한다. 소프트웨어를 더 빠르고 고품질로 제공하는 데 도움이 되는 계층에 시간을 투자해야 한다.
* 코드와 그 코드가 속한 추상화 계층은 작업할 때 편리해야 한다.

## 🍄 5. 직접 구현

```jsx
// 넥타이 하나를 사면 무료로 넥타이 클립을 하나 주는 코드
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()` 함수가 알아야 할 필요가 없는 구체적인 내용을 담고 있다. 마케팅 캐페인에 관련된 함수가 장바구니가 배열이라는 사실을 알아야 할까? 배열을 돌다가 오프-바이-원 에러가 생기면 실패할까?
* 오프-바이-원 에러 : 주로 배열을 반복해서 처리할 때 ‘크다’ 또는 ‘크거나 같다’와 같은 비교문을 잘못 선택해 의도하지 않게 마지막 항목을 처리하지 못하거나 처리하는 오류를 말한다.

### 🌻 5-1. 장바구니가 해야 할 동작

* 장바구니 설계를 개선하기 위해 코드에 있는 지식으로 장바구니가 해야할 동작을 정리해보자.
* 아 방법으로 코드가 어떻게 동작하는지 알 수 있다. 습관적으로 코드를 바로 작성하는 대신 해볼 수 있는 방법이다.
* 구현된 동작
  * 제품 추가하기
  * 제품 삭제하기
  * 합계 계산하기
  * 제품 이름으로 가격 설정하기
  * 세금 계산하기
  * 무료 배송이 되는지 확인하기
* 구현되지 않은 동작
  * 장바구니에 제품이 있는지 확인하기
  * 장바구니 비우기

### 🌻 5-2. 제품이 있는지 확인하는 함수가 있다면 설계를 개선할 수 있다.

* `freeTieClip()` 에는 반복문을 통해 장바구니에 넥타이와 넥타이 클립이 있는지 확인하는 코드가 있다. 장바구니 안에 제품이 있는지 확인하는 함수가 있다면, 저수준의 반복문을 직접 쓰지 않았을 것이다.
* 저수준의 코드는 추출해야 할 가능성이 높다. 반복문에서 다른 제품 두 개가 있는지 확인하고 있는데 하나의 함수를 만들어 사용하자.

```jsx
// 넥타이 하나를 사면 무료로 넥타이 클립을 하나 주는 코드
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;
}

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

### 🌻 5-3. 호출 그래프를 만들어 함수 호출을 시각화하기

* `freeTieClip()` 함수를 또 다른 관점에서 살펴보자. 함수에서 사용하는 다른 함수와 언어 기능을 호출 그래프로 그릴 수 있다.
* 다이어그램
  * freeTieClip()

    → array index

    → for loop

    → make\_item()

    → add\_item()
* 호출 그래프 모두 같은 추상화 수준일까? 아니다. `make_item()` 함수와 `add_item()` 함수는 직접 만든 함수이다. 그리고 반복문이나 배열 인덱스 참조 기능은 언어에서 제공하는 기능이다. 직접 만든 함수와 언어 기능은 추상화 수준이 다르다. 반복문과 배열 인덱스를 참조하는 기능은 더 낮은 추상화 단계이다.
* 다이어그램
  * freeTieClip()

    →→ array index

    →→ for loop

    → make\_item()

    → add\_item()
* 코드를 읽을 때 `freeTieClip()` 함수가 서로 다른 추상화 단계에 있다는 점을 다이어그램에서 볼 수 있다. 화살표가 서로 다른 계층을 가리키고 있기 때문에 여러 계층을 사용하고 있다는 것을 알 수 있다.

### 🌻 5-4. 직접 구현 패턴을 사용하면 비슷한 추상화 계층에 있는 함수를 호출한다.

* 서로 다른 추상화 단계에 있는 기능을 사용하면 직접 구현 패턴이 아니다.

```jsx
// 넥타이 하나를 사면 무료로 넥타이 클립을 하나 주는 코드
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;
}
```

* `freeTieClip()` 에 있는 함수는 정확히 같은 추상화 단계인지 확신할 수 없지만 비슷한 추상화 단계를 사용하고 있는 것 같다.
* 개선된 함수는 장바구니가 배열인지 몰라도 된다. `freeTieClip()` 이 사용하는 모든 함수는 장바구니가 배열인지 몰라도 된다. 장바구니가 배열인지 몰라도 된다는 것은 함수가 모두 비슷한 계층에 있다는 것을 의미한다. 이처럼 하수가 모두 비슷한 계층에 있다면 직접 구현햇다고 할 수 있다.

## 🍄 6. 같은 계층에 있는 함수는 같은 목적을 가져야 한다.

* 다이어그램은 명확하고 모호한 것이 없는 여섯 개의 계층으로 되어 있다. 함수를 어떤 계층에 높을지 선택하는 과정은 복잡하다. 그래도 각 계층이 서로 구분되는 목적이 있다면, 함수가 위치할 계층을 선택하는 데 좋은 정보로 사용할 수 있다.
* 각 계층은 추상화 수준이 다르다. 그래서 어떤 계층에 있는 함수를 읽거나 고칠 때 낮은 수준의 구체적인 내용은 신경쓰지 않아도 된다. 예를 들어 장바구니 비즈니스 규칙에 있는 함수를 쓸 때, 장바구니가 배열로 구현되어 있다는 것과 같은 구체적인 내용은 신경 쓰지 않아도 된다.
* 다이어그램은 함수가 호출하는 것을 있는 그대로 표현한 것이기 때문에 함수를 어떤 계층에 놓을지 바로 알 수 있다. 그래서 다이어그램은 코드를 높은 차원에서 볼 수 있는 좋은 도구이다.

## 🍄 7. 3단계 줌 레벨

* 다이어그램에서 문제를 찾을 수도 있다. 하지만 다이어그램에는 너무 많은 정보가 있어 어느곳에 문제가 있는지 찾기 어렵다. 계층형 설계에서 문제는 세 가지 다른 영역에서 찾을 수 있다.

1. 계층 사이에 상호 관계
2. 특정 계층의 구현
3. 특정 함수의 구현

### 🌻 7-1. 전역 줌 레벨

* 전역 줌 레벨로 그래프 전체 중 필요한 부분을 살펴볼 수 있다. 전역 줌 레벨이 기본 줌 레벨이다. 계층 사이에 상호 관계를 포함해서 모든 문제 영역을 살펴볼 수 있다.

### 🌻 7-2. 계층 줌 레벨

* 계층 줌 레벨은 한 계층과 연결된 바로 아래 계층을 볼 수 있는 줌 레벨이다. 계층 줌 레벨로 계층이 어떻게 구현되어 있는지 알 수 있다.

### 🌻 7-3. 함수 줌 레벨

* 함수 줌 레벨로 함수 하나와 바로 아래 연결된 함수들을 볼 수 있다. 함수 줌 레벨로 함수 구현의 문제를 찾을 수 있다.

## 🍄 8. 반복문 빼내기

* `remove_item_by_name()` 함수에서 반복문을 빼서 새로운 함수를 만들어보자.

```jsx
// 원래 코드
function remove_item_by_name(cart, name){
	var idx = null;
	for(var i = 0; i < cart.length; i++){
		if(cart[i].name === name){
			idx = i;
		}
	}
	if(idx !== null){
		return removeItems(cart, idx , 1);
	}
	return cart;
}

// 수정 코드
function remove_item_by_name(cart, name){
	var idx = indexOfItem(cart, name);
	if(idx !== null){
		return removeItems(cart, idx , 1);
	}
	return cart;
}

function indexOfItem(cart, name){
	for(var i = 0; i < cart.length; i++){
		if(cart[i].name === name){
			return i;
		}
	}
	return null;
}
```

## 🍄 9. 직접 구현 패턴 리뷰

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

* 좋은 설계를 고민하지 않고 만든 코드는 읽거나 고치기 어렵다. 코드가 서로 다른 구체화 단계에 있다면 읽기 어렵기 때문이다.
* 코드를 읽을 대 이해해야 할 것이 많이 있는데 구체화 단계가 다르다면 이해하기가 더 어렵다. 직접 구현하면 코드를 읽기 위해 알아야 하는 구체화 단계의 범위를 줄일 수 있다.

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

* 쉽지 않지만, 코드에 있는 다양한 단서를 통해 구체화 수준에 집중하다 보면 설계 감각을 키울 수 있고 코드를 필요에 따라 알맞게 바꿀 수 있다.

### 🌻 9-3. 호출 그래프는 구체화 단계에 대한 풍부한 단서를 보여준다.

* 코드에는 설계를 개선하기 위한 단서가 많이 있다. 하지만 큰 그림으로 한 번에 보기에는 너무 많은 정보가 있다. 호출 그래프는 함수가 서로 어떻게 연결되어 있는지 보여준다. 함수 시그니처와 본문, 호출 그래프와 같은 다양한 단서를 가지고 직접 코드 패턴을 적용할 수 있다.

### 🌻 9-4. 함수를 추출하면 더 일반적인 함수로 만들 수 있다.

* 함수에 직접 구현 패턴을 적용하는 방법의 하나는 함수가 더 구체적인 내용을 다루지 않도록 함수를 일반적인 함수로 빼내는 것이다. 일반적인 함수는 보통 구체적인 내용을 하나만 다루기 때문에 테스트하기 쉽다. 명확한 코드와 알맞은 이름을 가진 함수는 더 읽기 쉽다.

### 🌻 9-5. 일반적인 함수가 많을수록 재사용하기 좋다.

* 함수로 빼내면 재사용할 수 있는 곳이 보인다. ‘중복 코드’를 찾기 위해 함수를 빼내는 것과는 다르다. 구현을 명확하게 하기 위해 일반적인 함수를 빼내는 것이다. 일반적인 함수는 구체적인 함수보다 더 많은 곳에서 쓸 수 있다. 그리고 사용할 곳을 따로 찾지 않아도 재사용할 수 있는 곳을 발견할 수 있다.

### 🌻 9-6. 복잡성을 감추지 않는다.

* 직접 구현 패턴을 적용한 코드처럼 보이게 만드는 것은 쉽다. 명확하지 않은 코드를 감추기 위해 도우미함수를 만들면 된다.
* 하지만 위 방법은 계층형 설계가 아니다. 계층형 설계에서 모든 계층은 바로 아래 계층에 의존해야 한다. 복잡한 코드를 같은 계층으로 옮기면 안된다.
* 더 낮은 구체화 수준을 가진 일반적인 함수를 만들어 소프트웨어에 직접 구현 패턴을 적용해야 한다.

## 🍄 10. 정리

* 계층형 설계는 코드를 추상화 계층으로 구성한다. 각 계층을 볼 때 다른 계층에 구체적인 내용을 몰라도 된다.
* 문제 해결을 위한 함수를 구현할 때 어떤 구체화 단계로 쓸지 결정하는 것이 중요하다. 그래야 함수가 어떤 계층에 속할지 알 수 있다.
* 함수가 어떤 계층에 속할지 알려주는 요소는 많이 있다. 함수 이름과 본문, 호출 그래프 등이 그런 요소이다.
* 함수 이름은 의도를 알려준다. 비슷한 목적의 이름을 가진 함수를 함께 묶을 수 있다.
* 함수 본문은 중요한 세부 사항을 알려준다. 함수 본문은 함수가 어떤 계층 구조에 있어야 하는지 알려준다.
* 호출 그래프로 구현이 직접적이지 않다는 것을 알 수 있다. 함수를 호출하는 화살표가 다양한 길이를 가지고 있다면 직접 구현되어 있지 않다는 신호이다.
* 직접 구현 패턴은 함수를 명확하고 아름답게 구현해 계층을 구성할 수 있도록 알려준다.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jaemedevs-organization.gitbook.io/frontend_study/book/functional-programming/ch8.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
