구어체로 설명하는 다이어리
06 기본적인 리팩터링 - 단계 쪼개기 본문
단계 쪼개기
const orderData = orderString.split(/\s+/);
const productPrice = priceList[orderData[0].split('-')[1]];
const orderPrice = parseInt(orderData[1]) * productPrice;
▼
const orderRecord = parseOrder(order);
const orderPrice = price(orderRecord, priceList);
function parseOrder(aString) {
const values = aString.split(/\s+/);
return {
productID: values[0].split("-")[1],
quantity: parseInt(values[1]),
};
}
function price(order, priceList) {
return order.quantity * priceList[order.productID];
}
배경
나는 서로 다른 두 대상을 한꺼번에 다루는 코드를 발견하면 각각을 별개 모듈로 나누는 방법을 모색한다. 코드를 수정해야 할 때 두 대상을 동시에 생각할 필요 없이 하나에만 집중하기 위해서다. 모듈이 잘 분리되어 있다면 다른 모듈의 상세 내용은 전혀 기억하지 못해도 원하는 대로 수정을 끝마칠 수도 있다.
이렇게 분리하는 가장 간편한 방법 하나는 동작을 연이은 두 단계로 쪼개는 것이다. 입력이 처리 로직에 적합하지 않은 형태로 들어오는 경우를 예로 생각해보자. 이럴 때는 본 작업에 들어가기 전에 입력값을 다루기 편한 형태로 가공한다. 아니면 로직을 순차적인 단계들로 분리해도 된다. 이때 각 단계는 서로 확연히 다른 일을 수행해야 한다.
가장 대표적인 예는 컴파일러다. 컴파일러는 기본적으로 어떤 텍스트(프로그래밍 언어로 작성된 코드)를 입력받아서 실행 가능한 형태(예컨대 특정 하드웨어에 맞는 목적 코드object code)로 변환한다. 컴파일러의 역사가 오래되다 보니 사람들을 컴파일 작업을 여러 단계가 순차적으로 연결된 형태로 분리하면 좋다는 사실을 깨달았다. 즉, 텍스트를 토큰화하고, 토큰을 파싱해서 구문 트리를 만들고, (최적화 등) 구문 트리를 변환하는 다양한 단계를 거친 다음, 마지막으로 목적 코드를 생성하는 식이다. 각 단계는 자신만의 문제에 집중하기 때문에 나머지 단계에 관해서는 자세히 몰라도 이해할 수 있다.
이렇게 단계를 쪼개는 기법은 주로 덩치 큰 소프트웨어들에 적용된다. 가령 컴파일러의 매 단계는 다수의 함수와 클래스로 구성된다. 하지만 나는 규모에 관계없이 여러 단계로 분리하면 좋을만한 코드를 발견할 때마다 기본적인 단계 쪼개기 리팩터링을 한다. 다른 단계로 볼 수 있는 코드 영역들이 마침 서로 다른 데이터와 함수를 사용한다면 단계 쪼개기에 적합하다는 뜻이다. 이 코드 영역들을 별도 모듈로 분리하면 그 차이를 코드에서 훨씬 분명하게 드러낼 수 있다.
절차
- 두 번째 단계에 해당하는 코드를 독립 함수로 추출한다.
- 테스트한다.
- 중간 데이터 구조를 만들어서 앞에서 추출한 함수의 인수로 추가한다.
- 테스트한다.
- 추출한 두 번째 단계 함수의 매개변수를 하나씩 검토한다. 그중 첫 번째 단계에서 사용되는 것은 중간 데이터 구조로 옮긴다. 하나씩 옮길 때마다 테스트한다.
- → 간혹 두 번째 단계에서 사용하면 안 되는 매개변수가 있다. 이럴 때는 각 매개변수를 사용한 결과를 중간 데이터 구조의 필드로 추출하고, 이 필드의 값을 설정하는 문장을 호출한 곳으로 옮긴다.
- 첫 번째 단계 코드를 함수로 추출하면서 중간 데이터 구조를 반환하도록 만든다.
- → 이때 첫 번째 단계를 변환기transformer 객체로 추출해도 좋다.
...
익일 수정
'읽을거리 > 리팩터링' 카테고리의 다른 글
06 기본적인 리팩터링 - 여러 함수를 변환 함수로 묶기 (0) | 2024.12.06 |
---|---|
06 기본적인 리팩터링 - 여러 함수를 클래스로 묶기 (2) | 2024.12.05 |
06 기본적인 리팩터링 - 매개변수 객체 만들기 (0) | 2024.12.05 |
06 기본적인 리팩터링 - 변수 이름 바꾸기 (0) | 2024.11.06 |
06 기본적인 리팩터링 - 변수 캡슐화하기 (0) | 2024.11.06 |