우석
계층형 설계 1
계층형 설계란?
- 계층형 설계는 소프트웨어를 계층으로 구성하는 기술
- 각 계층의 함수는 바로 아래 계층의 함수로 구성된다.
- 다음과 같은 계층들이 생길 수 있다.
- Layer 1: 비즈니스 규칙
- Layer 2: 장바구니를 위한 동작들
- Layer 3: 카피-온-라이트
- Layer 4: 언어에서 지원하는 배열 관련 기능
- 단, 각 계층을 나누는 절대적인 기준은 없다.
계층형 설계 패턴
- 계층형 설계에는 크게 4가지 패턴이 존재한다.
- 직접 구현: 함수 시그니처가 나타내는 문제를 함수 본문에서 적절한 구체화 수준으로 해결한다.
- 추상화 벽: 호출 그래프에 특정 계층은 세부 구현은 감추고 인터페이스만 제공하여 고수준의 추상화 단계만 생각해도 되도록 돕는다.
- 작은 인터페이스: 비즈니스 개념을 나타내는 중요한 인터페이스를 작고 강력하게 구성하려고 노력한다.
- 편리한 계층: 각 계층은 비즈니스 문제를 잘 풀 수 있도록 구현해야 하고 도움이 될 때 시간을 투자해야 한다.
패턴 1: 직접 구현
- 직접 구현 패턴은 함수의 구현부가 적절한 계층의 함수를 호출하여 해결할 수 있도록 구성하는 것
- 상위 계층을 호출해서는 안 되고, 계층을 너무 많이 건너 뛰어 아래 계층을 호출하는 것도 지양해야 한다.
- 그 이유는 계층을 올라갈 수록 여러 문제가 해결된 함수를 사용하여 해당 계층에서 고민하는 문제를 줄여 개발에 편리한 구조를 만들기 위함이라 이해했다.
- 이를 위해서 같은 계층에 있는 함수는 같은 목적을 가져야 한다
function isInCart(cart, name) {
for (var i = 0; i < cart.length; i++) {
if (cart[i].name === name) {
return true;
}
}
return false;
}
function indexOfItem(cart, name) {
for (var i = 0; i < cart.length; i++) {
if (cart[i].name === name) {
return i;
}
}
return null;
}
- 위 2개의 메서드는 각기 다른 계층에 존재하는 메서드이다.
- isInCart는 장바구니를 위한 동작들이 정의된 계층이고, indexOfItem은 일종의 배열의 기능을 제공하는 계층으로 isInCart가 더 높은 계층에 위치한다.
- 하지만 위 구조를 보면 isInCart는 바로 아래 계층을 건너 뛰고 언어에서 지원하는 기능을 직접 호출하고 있다.
function isInCart(cart, name) {
return indexOfItem(cart, name) !== null
}
- 위와 같이 정의하면 계층들이 모두 바로 아래 계층을 호출하는 구조가 된다.
- 또한 장바구니를 위한 동작인 isInCart를 구현하며 배열과 관련된 구현 로직을 고민하지 않아도 되기 때문에 개발 생산성이 더 높아질 것을 기대할 수 있다.
직접 구현 패턴의 장/단점 및 생각
- 함수를 읽을 때 알아야 할 구체화 로직의 범위가 제한되기 때문에 가독성 측면에서 뛰어나다. (단, 바로 아래 계층의 인터페이스를 기준으로 로직을 파악하면 된다.)
- 추가적인 도구로 호출 그래프를 활용하여 계층과 함수 관계를 쉽게 파악할 수 있고 계층 기준으로 파악하며 리팩토링의 단서를 찾을 수도 있다.
- 직접 구현 패턴을 사용하면 더 일반적인 함수를 만들도록 노력하게 되고 이는 함수의 재사용성 측면에서 장점을 가질 수 있다.
- 단, 계층 자체가 복잡성의 일부가 될 수 있을 것 같다. 업무에 적용해보기 위해서는 계층에 대한 정의와 프로젝트에 적용할 계층에 정의를 모두가 숙지하고 있어야 할 것 같다.
만혁
계층형 설계 1
계층형 설계란 무엇인가?
설계 감각을 키우기
전문가의 저주
전문가는 본인의 전문 분야를 잘 알지만, 설명은 잘 못하는 것으로 악명 높다
계층형 설계 감각을 키우기 위한 입력
계층형 설계 패턴
- 직접 구현
- 너무 구체적이라면 코드에서 나는 냄새
- 추상화 벽
- 인터페이스를 사용해 코드를 만들면 높은 차원으로 생각할 수 있다.
- 고수준의 추상화 단계만 생각하면 되기 때문에 두뇌 용량의 한계를 극복할 수 있다.
- 작은 인터페이스
- 중요한 인터페이스는 작고 강력한 동작으로 구성하는 것이 좋다.
- 편리한 계층
- 코드와 코드가 속한 추상화 꼐층은 작업할때 편리해야 한다.
패턴 1 : 직접 구현
// as-is
function freeTieClip(cart) {
// ...
for(const i=0; i<cart.length; i++) {
const item = cart[i];
if (item.name === "tie") {
hasTie = true;
}
if (item.name === "tie clip") {
hasTieClip = true;
}
}
// ...
}
function isInCart(cart, name) {
for (const i=0; i<cart.length; i++) {
if (cart[i].name === name) {
return true;
}
}
return false;
}
// to-be
function freeTieClip(cart) {
const hasTie = isInCart(cart, "tie");
const hasTieClip = isInCart(cart, "tie cilp");
}