[2탄] 리팩터링 함수 추출하기

Sanghoon Han·2021년 5월 2일
0

리팩터링2판

목록 보기
2/2

6.1 함수 추출하기

코드 조각을 찾아 무슨 일을 하는지 파악한 다음, 독립된 함수로 추출하고 목적에 맞는 이름을 붙인다.

  1. 함수 하나가 한 화면을 넘어갈때

  2. 두 번 이상 사용될것 같을때

  3. 목적과 구현을 분리 함

    • 코드를 보고 무슨일을 하는지 파악하는 데 한참이 걸릴경우 그 부분을 함수 로 추출한 뒤

    • 무슨일에 걸맞는 이륾을 짖는다.

      (긴 함수에는 각각의 코드 첫머리에 주석이 달려있다. 이름을 지을 때 주석을 참고하자!)


💁 함수 뽑기 절차

  1. 함수를 새로 만들고 목적을 잘 드러내는 이름을 붙인다. ('어떻게'가 아닌 '무엇을' 하는지가 드러나야한다.)

    만약 코드가 함수 호출문 하나처럼 매우 간단하더라도 함수로 뽑아서 목적이 더 잘 드러나는 이름을 붙일 수 있다면 추출한다. 추출 하는 과정에서 좋은 이름이 떠오를 수도 있으니 처음부터 최선의 이름을 짓고 시작할 필요는 없다.

  2. 추출할 코드를 원본 함수에서 복사하여 새 함수에 붙여넣는다.

  3. 추출한 코드 중 원본 함수의 지역 변수를 참조하거나 추출한 함수의 유효범위를 벗어나는 변수는 없는지 검사한다. 있다면 매개변수로 전달한다.

    → 원본 함수의 중첩 함수로 추출할 때는 이런 문제가 생기지 않는다.

    → 추출한 코드에서만 사용하는 변수가 추출한 함수 밖에 선언되어 있다면 추출한 함수 안에서 선언 하도록 수정한다

    → 추출한 코드 안에서 값이 바뀌는 변수 중에서 값으로 전달 되는 것들은 주의해서 처리한다.

  4. 변수를 다 처리했다면 컴파일 한다.

    → 컴파일되는 언어로 개발 중이라면 변수를 모두 처리하고 나서 한번 컴파일 해보자.

  5. 원본 함수에서 추출한 코드 부분을 새로 만든 함수를 호출하는 문장으로 바꾼다(즉, 추출한 함수로 일을 위임한다)

  6. 테스트한다.

  7. 다른 코드에 방금 추출한 것과 똑같거나 비슷한 코드가 없는지 살핀다. 있다면 방금 추출한 새 함수를 호출하도록 바꿀지 검토한다.


//예시

function printOwing(invoice){
	let outstanding = 0;
	
	console.log("***************");
	console.log("*****고객 채무*****");
	console.log("***************");

	for (const o of invoice.orders){
		outstanding += o.amount;
	}

	//마감일(dueDate)을 기록한다.
	const today = Clock.today;
	invoice.dueDate = new Date(today.getFullYear(), today.getMonth(),
														 today.getDate() + 30);
	//세부 사항을 출력한다.
	console.log(`고객명 : ${invoice.customer}`);
	console.log(`채무액 : ${outstanding}`);
	console.log(`마감일 : ${invoice.dueDate.toLocaleDateString()}`);
}

배너 함수 추출


//예시

function printOwing(invoice){
	let outstanding = 0;

	printBanner();
	
 	for (const o of invoice.orders){
		outstanding += o.amount;
	}

	//마감일(dueDate)을 기록한다.
	const today = Clock.today;
	invoice.dueDate = new Date(today.getFullYear(), today.getMonth(),
														 today.getDate() + 30);
	//세부 사항을 출력한다.
	console.log(`고객명 : ${invoice.customer}`);
	console.log(`채무액 : ${outstanding}`);
	console.log(`마감일 : ${invoice.dueDate.toLocaleDateString()}`);
}

function printBanner(){
	console.log("***************");
	console.log("*****고객 채무*****");
	console.log("***************");
}

세부사항 출력 코드 추출


//예시

function printOwing(invoice){
	let outstanding = 0;

	printBanner();
	
 	for (const o of invoice.orders){
		outstanding += o.amount;
	}

	//마감일(dueDate)을 기록한다.
	const today = Clock.today;
	invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30);
	
	//세부 사항을 출력한다.
	printDetails();
}

function printBanner(){
	console.log("***************");
	console.log("*****고객 채무*****");
	console.log("***************");
}

**function printDetails(){
	console.log(`고객명 : ${invoice.customer}`);
	console.log(`채무액 : ${outstanding}`);
	console.log(`마감일 : ${invoice.dueDate.toLocaleDateString()}`);
}**

지역 변수를 사용할 때

  • 지역 변수와 관련하여 가장 간단한 경우는 변수를 사용하지만 다른 값을 다시 대입하지는 않을 때다.
  • 이 경우에는 지역 변수들을 그냥 매개변수로 넘기면 된다.

//예시

function printOwing(invoice){
	let outstanding = 0;

	printBanner();
	
	//미해결 채무 outstanding 계산
 	for (const o of invoice.orders){
		outstanding += o.amount;
	}

	//마감일(dueDate)을 기록한다.
	const today = Clock.today;
	invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30);
	
	//세부 사항을 출력한다.
	printDetails(invoice, outstanding);

function printBanner(){
	console.log("***************");
	console.log("*****고객 채무*****");
	console.log("***************");
}
	
function printDetails(invoice, outstanding){
	console.log(`고객명 : ${invoice.customer}`);
	console.log(`채무액 : ${outstanding}`);
	console.log(`마감일 : ${invoice.dueDate.toLocaleDateString()}`);
}

지역 변수가 (배열, 레코드, 객체와 같은) 데이터 구조라면 똑같이 매개변수로 넘긴 값을 수정할 수 있다.


//예시

function printOwing(invoice){
	let outstanding = 0;

	printBanner();
	
	//미해결 채무 outstanding 계산
 	for (const o of invoice.orders){
		outstanding += o.amount;
	}
	
	recordDueDate(invoice);
	printDetails(invoice, outstanding);

function printBanner(){
	console.log("***************");
	console.log("*****고객 채무*****");
	console.log("***************");
}

function recordDueDate(invoice){
	const today = Clock.today;
	invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30));
}
function printDetails(invoice, outstanding){
	console.log(`고객명 : ${invoice.customer}`);
	console.log(`채무액 : ${outstanding}`);
	console.log(`마감일 : ${invoice.dueDate.toLocaleDateString()}`);
}

지역 변수의 값을 변경할 때


//예시

function printOwing(invoice){

	printBanner();
	
	//미해결 채무 outstanding 계산
	let outstanding = 0; //맨 위에 있던 선언문을 이 위치로 이동

 	for (const o of invoice.orders){
		outstanding += o.amount;
	}
	
	recordDueDate(invoice);
	printDetails(invoice, outstanding);
}
	
  • 그런 다음 추출할 부분을 새로운 함수로 복사한다.
function calculateOutstanding(invoice){
	let outstanding = 0;
	for (const o of invoice.orders){
		outstanding += o.amount;
	}
	return outstanding
}
  • 반환값 저장해주기
function printOwing(invoice){

	printBanner();
  
	//미해결 채무 outstanding 계산
	let outstanding = calculateOutstanding(invoice); //맨 위에 있던 선언문을 이 위치로 이동
	recordDueDate(invoice);
	printDetails(invoice, outstanding);

	function calculateOutstanding(invoice){
		let outstanding = 0;
		for (const o of invoice.orders){
			outstanding += o.amount;
		}
		return outstanding
	}
}
  • 마지막으로 반환값의 이름을 내 코딩 스타일에 맞게 바꾼다
function printOwing(invoice){

	printBanner();
	const outstanding = calculateOutstanding(invoice);
	recordDueDate(invoice);
	printDetails(invoice, outstanding);
}

///////////////////////////////////////////////////////////////////////////

function calculateOutstanding(invoice){
	let result = 0;
	for (const o of invoice.orders){
		result += o.amount;
	}
	return result;
}

function printBanner(){
	console.log("***************");
	console.log("*****고객 채무*****");
	console.log("***************");
}

function recordDueDate(invoice){
	const today = Clock.today;
	invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30);
}![](https://velog.velcdn.com/images%2Fhoon2hooni%2Fpost%2Fed4eec15-49a7-4511-a4cb-642fecdbdef8%2F%EB%A6%AC%ED%8C%A9%ED%84%B0%EB%A7%81%EC%B1%85.jpg)

function printDetails(invoice, outstanding){
	console.log(`고객명 : ${invoice.customer}`);
	console.log(`채무액 : ${outstanding}`);
	console.log(`마감일 : ${invoice.dueDate.toLocaleDateString()}`);
}

reference

  • 리팩터링 2판 코드 구조를 체계적으로 개선하여 효율적인 리팩터링 구현하기 [ 『리팩토링』 개정판 ]마틴 파울러 저/개앞맵시, 남기혁 역 | 한빛미디어 | 2020년 04월 01일
profile
Fail Fast learn Faster

0개의 댓글