목차
1. Mysterious Name (이해하기 힘든 이름)
깔끔한 코드에서 중요한 것 중 하나가 ‘좋은 이름’이다.
함수, 변수, 클래스, 모듈의 이름을 보고 역할과 쓰임새를 짐작할 수 있어야 한다.
- 사용할 수 있는 Refactoring 기술
- Change Function Declaration(함수 선언 변경하기)
- Rename Variable(변수 이름 바꾸기)
- Rename Field(필드 이름 바꾸기)
Change Function Declaration(함수 선언 변경하기)
(함수명, 메소드명 매개변수 추가, 매개변수 제거, 시그니처 변경)
- 좋은 이름을 가진 함수는 함수가 어떻게 구현되었는지 코드를 보지 않아도 함수명을 보고 이해할 수 있다.
- 좋은 이름을 찾아내는 방법 : 함수에 주석을 작성한 후 주석을 함수이름으로 만든다.
- 함수의 매개변수
- 함수 내부의 문맥을 결정(ex, 전화번호 formatting 함수)
- 의존성을 결정(ex, Payment 만기일 계산 함수)
Rename Variable (변수 이름 바꾸기)
- 더 많이 사용되는 변수 일 수록 그 이름이 중요
- 람다식에서 사용하는 변수 vs 함수의 매개변수
- Dynamic Type을 지원하는 언어에서는 타입을 이름에 넣기도한다.
- 여러 함수에 걸쳐 쓰이는 필드 이름에는 더 많이 고민하고 이름을 짓는다.
Rename Field(필드 이름 바꾸기)
- Record 자료구조의 필드 이름은 프로그램 전반에 걸쳐 참조될 수 있기 때문에 중요하다.
- Record 자료구조 : 특정 데이터와 관련있는 필드를 묶어놓은 자료구조
- 파이썬의 Dictionary, 또는 줄여서 dicts.
- C#의 Record.
- Java의
record는 14에서 미리 보기 기능으로 도입됐고, 16부터 정식 언어 기능이다. Oracle 문서를 참고한다. - 자바에서는 Getter, Setter 메소드 이름도 필드의 이름과 비슷하게 간주할 수 있다.
예제: 이름만 읽고 계산의 뜻을 알 수 있는가?
주문 금액을 계산하는 다음 코드에서 f, x, p, q만 보고는 어떤 금액인지 알기 어렵다. p의 단위가 원인지 센트인지도 알 수 없다.
// 변경 전
type Line = { p: number; q: number };
function f(x: Line[]): number {
return x.reduce((n, v) => n + v.p * v.q, 0);
}
const t = f([{ p: 1200, q: 2 }]);
함수에 주석을 쓴다면 “주문 항목의 단가와 수량을 곱해 합계를 구한다”가 될 것이다. 그 문장을 함수 이름과 필드 이름으로 옮긴다.
// 변경 후
type OrderLine = { unitPriceWon: number; quantity: number };
function calculateOrderSubtotalWon(lines: OrderLine[]): number {
return lines.reduce(
(subtotal, line) => subtotal + line.unitPriceWon * line.quantity,
0,
);
}
const subtotalWon = calculateOrderSubtotalWon([
{ unitPriceWon: 1200, quantity: 2 },
]);
calculateOrderSubtotalWon은 무엇을 계산하는지와 단위가 무엇인지 알려 준다. 세금과 배송비를 포함하지 않는다면 total보다 subtotal이 더 정확하다. 반면 같은 화면의 아주 짧은 반복문에서 i처럼 범위가 좁고 관례가 분명한 이름까지 길게 늘릴 필요는 없다.
이 변경은 앞에 적은 세 기법을 함께 사용한다. 함수 선언을 바꿨다면 호출부 f(...)도 함께 갱신하고, Line.p 같은 필드 이름을 바꿨다면 객체를 생성·읽는 곳을 모두 찾아야 한다. JSON API나 저장된 데이터에 쓰는 필드라면 외부 사용자가 그 이름을 계약으로 사용 중일 수 있으므로, 내부 변수 이름을 바꾸는 것과 별도로 호환성 계획이 필요하다.
동작은 이름 변경 전후 모두 1200 × 2 = 2400이다. 리팩터링의 목적은 이 계산 결과를 바꾸지 않고 읽는 사람이 코드를 해석하는 시간을 줄이는 것이다. 이름을 바꾼 뒤 기존 계산 테스트와 호출부의 타입 검사를 실행해 의도치 않은 변경이 없는지 확인한다.