우석
더 좋은 액션 만들기
액션에서 암묵적 입출력 줄이기
- ch4에서 액션에서 계산을 빼내면서 암묵적 입출력을 제거하여 완전한 계산으로 변경하였다.
- 암묵적 입출력을 줄인다는 원칙은 단지 계산에만 적용되는 것이 아니다.
- 액션에 존재하는 암묵적 입출력을 제거하는 작업 또한 장점을 가진다.
- 암묵적 입출력이 존재하는 함수는 시점에 의존하는 코드이기 때문에 아무때나 실행할 수 없고 테스트가 까다롭다.
- 암묵적 입출력을 제거하면 시점에 의존하지 않게 만들 수 있고 테스트에 용이한 구조를 가져갈 수 있다.
계산 분류하기
- 함수를 사용하면 자연스럽게 관심사를 분리할 수 있다.
- 관심사가 분리되면서 자연스럽게 코드의 크기가 줄며 계층이 생겨나고 아래와 같은 장점을 얻을 수 있다.
- 재사용하기 쉽다.
- 유지보수하기 쉽다.
- 테스트하기 쉽다.
// Cart, Item
function add_item(cart, name, price) {
var new_cart = cart.slice();
new_cart.push({
name: name,
price: price
});
return new_cart;
}
// Cart, Item, Business
function calc_total(cart) {
var total = 0;
for (var i = 0; i < cart.length; i++) {
var item = cart[i];
total += item.price;
}
return total;
}
// Business
function gets_free_shipping(cart) {
return calc_total(cart) >= 20
}
// Business
function calc_tax(amount) {
return amount * 0.10;
}
- 위 예시는 메서드가 의존하는 것들에 대해 정의한 것이다.
- add_item()은 Cart와 Item의 구조를 알아야 하며 calc_total()는 Cart, Item 그리고 Business 규칙이 포함되어 있다.
- gets_free_shipping()과 calc_tax()는 Business 규칙에 대한 메서드이다.
- 여기서 add_item()은 Cart와 Item을 알아야 하는 메서드인데 관심사를 불리해보자.
// Util
function add_element_last(arry, elem) {
var new_array = array.slice();
new_array.push(elem);
return new_array;
}
// Item
function make_cart_item(name, price) {
return {
name: name,
price: price
}
}
// Cart
function add_item(cart, item) {
return add_item_last(cart, item);
}
- 1개의 메서드 add_item()가 3개의 메서드로 쪼개졌다.
- 이제 각 메서드는 하나의 의존성만 가지기 때문에 변경 이유 또한 1개로 줄었다.
- 또한 add_element_last()의 경우 비슷한 동작을 하는 메서드 어디에서나 쓰일 수 있는 Util성 메서드가 되었다.
- 아래와 같은 장점을 얻은 것을 확인할 수 있다.
- 재사용하기 쉽다. -> Util 메서드는 어디서든 재사용이 가능하다. 또한 make_cart_item()과 add_item()도 로직이 작아져 범용적으로 쓰일 가능성이 커졌다.
- 유지보수하기 쉽다. -> 메서드 변경의 이유가 1가지로 줄었다
- 테스트하기 쉽다. -> 입출력이 명확하고 동작이 명확하고 짧아 테스트에 용이하다.
만혁
더 좋은 액션 만들기
비즈니스 요구 사항과 설계를 맞추기
요구 사항에 맞춰 더 나은 추상화 단계 선택하기
기계적인 리팩토링이 항상 ㅊ최선의 구조를 만들어 주진 않는다.
비즈니스 요구 사항과 함수를 맞추기
함수의 동작을 바꿨기 때문에 엄밀히 말하면 리팩터링이라고 할 수 없다.
//as-is
function gets_free_shipping(total, price) {
return total + price >= 20;
}
// to-be
function gets_free_shipping(cart) {
return calc_total(cart) >= 20; // 별도의 계산 함수를 사용해 금액 합계를 구한다
}
원칙 : 암묵적 입력과 출력은 적을수록 좋다.
암묵적 입력과 출력이 있는 함수는 아무때나 실행할 수 없기 때문에 테스트하기 어렵다.
입력과 출력이 많을수록 테스트는 더 어려워 진다.
계산은 암묵적 입력과 출력이 없기 때문에 테스트하기 쉽다. 모든 암묵적 입력과 출력을 없애지 못해
액션을 계산으로 바꾸지 못해도 암묵적 입력과 출력을 줄이면 테스트하기 쉽고 재사용성이 좋다.
암묵적 입력과 출력 줄이기
update_shipping_icons() 함수에 원칙을 적용해 암묵적 입력과 출력을 줄여본다.
// as-is
function update_shipping_icons() {
// do something
// in for loop
const new_cart = add_item(shopping_cart, item.name, item.price) // shopping_cart 는 전역변수
// do something
}
// to-be
function update_shipping_icons(cart) { // 인자 추가
// do something
// in for loop
const new_cart = add_item(cart, item.name, item.price) // cart 인자 추가
// do something
}
원칙 : 설계는 엉켜있는 코드를 푸는 것이다.
재사용하기 쉽다.
함수는 작을수록 재사용하기 쉽다.
유지보수하기 쉽다.
작은 함수는 쉽게 이해할 수 있고 유지보수하기 쉽다.
테스트하기 쉽다.
작은 함수는 테스트하기 좋다. 한 가지 일만 하기 때문에 한 가지 테스트만 하면 된다.
카피-온-라이트 패턴을 빼내기
장바구니와 제품에만 쓸 수 있는 함수가 아닌 어떤 배열이나 항목에도 쓸 수 있는 이름으로 변경
이 함수는 재사용할 수 있는 유틸리티 함수이다.
// as-is
function add_item(cart, item) {
const new_cart = cart.slice();
new_cart.push(item);
return new_cart;
}
// to-be
function add_element_last(array, elem) {
const new_array = array.slice();
new_array.push(elem);
return new_array;
}
회독 후기
- 작업하는 코드에 적용하려면 위에서 소개한 방법대로 적용해보면 좋을듯
- 카피온 라이트 위주로 작업한다면 안전성도 보장