본문 바로가기

Book

계층형 설계 1,2

chapter 8 계층형 설계 1

계층형 설계는 코드를 추상화 계층으로 구성함. 각 계층이 다른 계층에 구체적인 내용을 몰라도 됨. 8,9장에 걸쳐 계층형 설계를 구현하는 방법을 소개하는데 여기서는

직접 구현

방식을 소개함. 이게 특별한 게 아니고 이름처럼 특정 기능을 직접 구현하는 거임.

목적은 특정 계층이 의존하는 계층과의 차이가 크지 않게 구현하는거임. 정석은 현재 계층이 바로 밑에 계층에만 의존하게 만드는 거임.

여기서는 가장 아래 계층을 자바스크립트 기본함수들 계층 으로 두고. 그 위에 하나씩 계층을 쌓아 올림. 이렇게 하면 일반화된 함수도 뽑힐 테고, 그걸 재사용하는 계층이 자연스럽게 생김. 또한 호출 그래프를 보여주면서 쉽게 계층을 파악하는 예시를 제공함. 그리고 단순히 '중복 코드'를 찾기 위해 함수를 빼내는 것과 구현을 명확하게 하기 위해 빼는 건 다름. 그리고 래핑 함수를 사용해서 복잡한 코드를 추상화하는 것도 정석의 계층형 설계가 아님. 그니까 추상화를 하는 건 맞는데 단순히 래핑 하는 건 특수한 목적이 아닌 이상 그냥 같은 계층으로 옮긴 거밖에 안됨. 무조건 아래 계층에 의존하는 게 정석임.
그래서 보통 api 설계할때 레포지토리, 서비스, 뷰(컨트롤러?) 뭐 이런 식으로 나누는 게 같은 목적임.
(이건 내 생각, 근데 실제로 코드 작성해 보면 서비스 로직 내에서도 계층이 생기기 마련이고 서로 정보를 알게 되면 결합력이 높아짐 그래서 인터페이스를 쓰고 이 얘긴 뒤에서 나올 듯)

chapter 9 계층형 설계 2

여기서는 계층형 설계 패턴 나머지 3개 다룸 -> 추상화 벽, 작은 인터페이스, 편리한 계층
거창하게 패턴이라고 다뤘는데, 3개다 연결이 되어있는 내용임

패턴 2: 추상화 벽

추상화 벽은 말 그대로 벽을 세우는 건데 인터페이스를 만드는 거임. 1단계 직접 구현 패턴을 적용하면서 코드 구조가 계층화가 되었음. 여기서 세부적인 내용을 알고 외부 함수에 의해 호출되는 함수들이 있는 부분이 추상화 벽임. 이런 것만 추상화 벽이라고 하는 게 아니라. 컨트롤러 입장에서 보면 서비스 계층도 추상화 벽일 수 있음.

핵심은 추상화 벽이 있으면 구체적인 것을 신경 쓰지 않아도 된다는 거임.

사실 이게 가능하려면 직접 구현 단계에서 최대한 계층을 맞춰야 함. 그래야 상위 계층이 이벽을 넘어서 호출하지 않음.
여기서는 추상화 벽을 사용하면 좋은 경우 몇 가지를 소개함

  1. 쉽게 구현을 바꾸기 위해
  2. 코드를 읽고 쓰기 쉽게 만들기 위해
  3. 팀 간에 조율해야 할 것을 줄이기 위해
  4. 주어진 문제에 집중하기 위해

내용만 보면 그냥 추상화를 해야 하는 이유랑 똑같다. 아무튼 여기서 좀 강조하는 게, 추상화를 위해서 아직 필요하지 않은 상황을 대비해서 코드를 미리 만드는 경우도 있다는데, 이런 건 좋지 않다고 함. 대부분의 데이터 구조는 바뀌지 않음. 패턴 3: 작은 인터페이스 작은 인터페이스는 목적은 새로운 코드를 추가할 위치에 관한 것이라고 함. 인터페이스를 추가하면 하위계층이 복잡해지는 것을 막을 수 있음. 위랑 같은 추상화 이야기인데, 인터페이스 측면에 초점을 좀 더 맞춘 패턴이라 보면 될 듯.
새로운 기능을 만들 때 하위 계층에 기능을 추가하거나 고치는 것보다 상위 계층에 만드는 것이 작은 인터페이스 패턴이라고 한다. 말은 쉽지 실제로는 구현된 계층들 만으로 구현하기 힘든 기능도 있고 구분하려면 함수들을 리팩토링 해야 할 경우가 많다.
또한 여기서 장바구니에 아이템 추가할때 로그를 남기는 기능을 추가해야 하는 예시가 나오는데, 단순히 하위계층에 추가할 수도 있지만, 그렇게 되면 하위 계층을 호출하는 상위 계층 함수 중에 로깅이 필요 없는 함수에서 로깅을 호출하게 됨. 더욱이 '계산' 형태로 작성된 하위 계층의 함수가 '액션'이 되어버리고 이걸 호출하는 함수들이 전부 영향받음. 그렇기 때문에 웬만하면 장바구니 추가 기능을 하는 서비스 계층? 아니면 그 위 계층의 동작이 다 끝나는 지점에 추가하는 게 좋다고 함. 책에서 여러 예시를 들면서 특정 패턴처럼 이야기하고 싶어 하지만, 이걸 실현하기 위한 방식은 각 계층이 필요한 함수만 갖게 하면 된다는 거다. 그럼 다시 내부 함수들을 보면 함수도 필요한 기능만 하게 작성하면 된다. 계층과 함수는 자기 유사성을 갖는다.

//하위 계층 
function add_item (cart, item){ 
logAddToCart(global_user_id, item); 
return objectSet(cart,item.name, item); 
} 
// 상위 계층 function add_item_to_cart(name,price){ 
var item =make_cart_item(name,price); 
shopping_cart = add_item(shopping_cart, item); 
var total = calc_total(shopping_cart); 
set_cart_total_dom(total); 
update_shipping_icons(shopping_cart); update_tax_dom(total); logAddToCart();
}

패턴 4: 편리한 계층

이건 더 정형화된 패턴을 얘기하는 게 아니고, 코드를 작성할 때 아까 했던 3가지 패턴을 계속 적용하면서 계층 분리를 잘하고 있는지 파악하는 과정을 말한다. 또한 이러한 과정이 비즈니스 요구사항을 만족하는 방향이어야 한다.

호출 그래프를 통해 알 수 있는 비기능적 요구사항들

계층형 설계 이야기 초반에 호출 그래프를 소개했는데, 이 그래프를 통해 알 수 있는 부분이 많다. 비즈니스와 관련 있는 부분을 기능적 요구사항이라 하고, 그 외 테스트, 재사용 잘할 수 있나, 유지보수 용이한가 등등 이 비기능적 요구사항이라고 책에서 소개한다. 다음은 호출 그래프로 알 수 있는 3가지 비기능적 요구사항 들이다.

  • 유지보수성: 요구 사항이 바뀌었을 때 가장 쉽게 고칠 수 있는 코드는 어떤 코드인가?
  • 테스트성: 어떤 것을 테스트하는 것이 가장 중요한가?
  • 재사용성: 어떤 함수가 재사용하기 좋나? 그래프의 가장 위에 있는 코드가 고치기 쉬움, 그래서 테스트가 자주 변경될 수 있음. 그럼 재사용하기가 어려움. 사실 위의 3가지 내용이 다 연결이 되어 있다.
    아래에 있을수록 많은 코드들이 호출하고 있기 때문에 고치기 어려움. 위에는 본인만 고치거나 새로운 게 필요하면 따로 함수를 추가하면 됨. 그리고 위는 자주 변경 될 수 있다. 가장 비즈니스 요구사항에 가깝기 때문임.
    그리고 물론 테스트를 최대한 많이 하면 좋지만, 우선순위를 굳이 두자면 내부 로직들이 자주 변하지 않고 재사용가능할 테니 필수적으로 테스트하는 게 좋을 것이다.
    그리고 재사용성은 간단하게 예시를 들면, 현재 프로젝트의 언어의 표준라이브러리들이 어떻게 보면 하위 계층인데, 제일 많이 씀.

항상 생각하고 있지만, 습관이 안되어서 제대로 안 지킨 적이 많은 거 같은데 추상화에 대한 이야기를 이렇게 계층을 중점으로 이야기를 하니 정리가 더 잘된 거 같다.

참고 및 출처: <쏙쏙 들어오는 함수형 코딩> (에릭 노먼드 지음, 김은민 옮김, 제이펍 , 2022)

'Book' 카테고리의 다른 글

컴포넌트 응집도, 결합  (1) 2023.12.31
프로그래밍 패러다임  (0) 2023.12.22
의존성 주입(그리고 부트스트래핑)  (0) 2023.11.16
명령-질의 책임 분리(CQRS)  (0) 2023.11.03
커맨드와 커맨드 핸들러  (0) 2023.10.29