6 기본적인 리팩터링
- 함수 추출하기 <-> 함수 인라인하기
- 변수 추출하기 <-> 변수 인라인하기
- 함수 선언 바꾸기 : 함수 이름 바꾸기
- 변수 이름 바꾸기 --> 변수 캡슐화하기와 관련이 깊음
- 매개변수 객체 만들기 : 같이 다니는 인수들 묶기
- 여러 함수를 클래스로 묶기 : 함수를 만들고 고수준 모듈로 묶기
- 여러 함수를 변환 함수로 묶기 : 읽기전용 데이터 다루기 좋음
- 단계 쪼개기 : 묶인 모듈들의 작업 처리 과정을 명확한 단계로 구분짓기
6.1 함수 추출하기
코드를 언제 함수로 묶어야하는가
- 길이 , 재사용성 : 두번 이상 사용 되는 코드
- 목적과 구현을 분리 : 기능 파악이 어렵다면 함수로 추출하기
함수 내 코드 대여섯줄 정도 짧은 함수 작성 --> 이름 잘 짓기 !!!
절차
- 함수를 새로 만들고 목적을 잘 드러내는 이름 붙이기 (무엇을!! 하는지, not 어떻게)
- 이름이 안 떠오른다면 함수로 추출하면 안 될수도
- 추출할 코드를 원본 함수에서 복사하여 새 함수에 붙여넣는다
- 추출한 코드 중 원본 함수의 지역변수를 참조하거나, 추출한 함수의 유효범위를 벗어나는 변수 검사 -> 있다면 매개변수로 전달
- 중첩 함수 사용시 이런 문제 x
- 매개 변수 중 값이 변하는 것은 주의, 변하는 값이 하나라면 질의함수 취급해서 그 결과를 변수에 대입 ......?
- 지역변수가 너무 많으면 변수 쪼개기나 임시변수를 질의함수로 바꾸기 적용해서 코드 단순화한 후 추출 재시도
- 변수를 다 처리했으면 컴파일
- 원본 함수에서 함수 호출
- 테스트
- 다른 코드에 방금 추출한 함수랑 비슷하거나 같은 곳 없는지 확인 후 있다면 새 함수를 호출하도록 바꿀지 검토 (인라인 코드를 함수 호출로 바꾸기)
값을 반환할 변수가 여러개라면 ?
- 추출할 코드를 다르게 재구성하는 방향으로 처리함
- 함수가 값 하나만 반환하는 방식을 선호하기 때문에 각각 반환하는 함수 여러개 만듦
- 굳이 한 함수에서 여러개 반환하고 싶으면 값을 레코드로 묶어서 반환하는 것도 괜찮지만
- 임시 변수 추출 작업을 다른 방식으로 처리하는 것이 나을 때가 많다 (임시 변수를 질의 함수로 바꾸거나 변수를 쪼개는 것과 같이..임시변수를 질의함수로 바꾸는게 뭐야?)
추출함수를 최상위수준 같은 다른 문맥으로 이동할 때는 일단 그 함수 내에서 추출하고 다른데로 옮겨보기, 변수 처리가 힘들 것이라 예상하지만 막상 해봐야 알 수 있음
6.2 함수 인라인하기
메서드 내용 직접 삽입
본문 함수가 깔끔할 때는 간접 호출 대신 함수 인라인하기
잘못 추출 된 함수들도 인라인 하고 간접 호출 너무 과해도 인라인하기
절차
- 다형 메서드인지 확인
- 서브클래스에서 오버라이드 하는 메서드는 인라인 하면 안됨
- 이게 무슨 뜻일까?? ex 필요
- 인라인할 함수를 호출하는 곳을 모두 찾기
- 각 호출문을 함수 본문으로 교체
- 하나 교체 하고 테스트 반복
- 원래 함수 삭제
상황이 복잡하면 인라인 하지말기~
항상 단계를 잘게 나누기
6.3 변수 추출하기
표현식이 너무 복잡해서 이해 하기 어려울 때 변수로 추출
현재 함수 안에서만 의미가 있다면 변수로 추출하는 것이 좋음
함수를 벗어난 넓은 문맥에서 사용된다면 변수가 아닌 함수로 추출해야함
절차
- 추출하려는 표현식에 부작용 없는지 확인 (부작용이 뭐임?)
- 불변 변수를 선언하고 표현식의 복제본 대입
- 원본 표현식을 새로 만든 변수로 교체
- 테스트
- 표현식을 여러곳에서 사용 시 다 새로 만든 변수로 교체, 교체 시 마다 테스트 하기
6.4 변수 인라인하기
절차
- 대입문의 우변 (표현식) 부작용 여부 확인
- 변수가 불변으로 선언되지 않았다면 불변으로 만든 후 테스트
- 변수에 값이 한 번만 대입되는지 확인 가능
- 이 변수를 가장 처음 사용하는 코드 찾아서 표현식으로 변경
- 테스트
- 교체 - 테스트 반복
- 변수 선언문, 대입문 삭제
- 테스트
6.5 함수 선언 바꾸기
좋은 함수명 - 먼저, 함수의 목적을 설명해보기
매개변수 올바르게 선택하기 - 정답이 없음
절차
- 간단한 절차
- 매개변수 제거 시, 함수 본문에 제거 대상 매개 변수 참조하는 곳 없는지 확인
- 메서드 선언을 원하는 형태로 변경
- 기존 메서드 선언을 참조하는 부분을 모두 찾아 바뀐 형태로 수정
- 테스트
- 마이그레이션 절차
- 함수 본문을 적절히 리팩터링하기
- 함수 본문을 새로운 함수로 추출
- 새로 만들 함수 이름이 기존함수와 같다면 일단 임시 이름 붙여주기
- 추출한 함수에 매개변수를 추가해야한다면 간단한 절차에 맞춰 추가
- 테스트
- 기존 함수를 인라인
- 기존 함수 내용 다 묶어서 새 임시 함수 만들고 기존 함수에서 새함수 호출
- 임시로 붙인 이름을 함수 선언 바꾸기를 통해 원래 이름으로 되돌림
- 테스트
매개변수 추가 시 assert를 통해 추가된 매개변수를 실제로 사용하는지 확인
6.6 변수 캡슐화 하기
접근 범위가 넓은 데이터는 접근에 제한을 걸어주면 좋음
절차
- 변수로 접근, 갱신하는 전담 캡슐화 함수 만들기
- 정적 검사 수행 (어떻게?)
- 변수를 직접 참조하던 부분을 모두 캡슐화 함수 호출로 변경하고 테스트
- 변수의 접근 범위 제한
- 변수로 직접 접근을 막지 못할 때는 변수 이름을 바꿔서 테스트해보면 해당 변수를 참조하는 곳을 찾아낼 수 있음
- 테스트
- 변수 값이 레코드라면 레코드 캡슐화하기 적용 고려
6.7 변수 이름 바꾸기
명확한 프로그래밍의 핵심은 이름 짓기
절차
- 폭넓게 쓰이는 변수라면 캡슐화하기를 고려
- 이름을 바꿀 변수를 참조하는 곳 모두 찾아 변경
- 다른 코드베이스에서 참조하는 변수는 외부에 공개된 변수이므로 해당 리팩터링 적용 불가 (?)
- 변수값이 변하지 않는다면 다른 이름으로 복제본으로 만들어 하나씩 점진적으로 변경 후 테스트
- 테스트
6.8 매개변수 객체 만들기
데이터 항목 여러개를 데이터 구조로 모아 매개변수로 만들기
절차
- 적절한 데이터 구조 만들기
- 테스트
- 함수선언바꾸기 (매개변수 수정) 로 새 데이터 구조를 매개변수로 추가
- const exampleFunction = (originalData1, originalData2, newDataObject) => { ... }
- 테스트
- 함수 호출 시 데이터 구조 인스턴스 넘기도록 수정
- exampleFunction (originalData1, originalData2, newDataObject);
- 하나 고치고 하나 테스트
- 기존 매개변수를 사용하던 코드를 새 데이터 구조의 원소를 사용하도록 변경
- exampleFunction (newDataObject);
- 다 바꿨다면 기존 매개변수를 제거 하고 테스트
6.9 여러 함수를 클래스로 묶기
공통된 데이터를 사용하는 함수들을 새 클래스에 모으기
- 클라이언트가 객체의 핵심 데이터를 변경 가능
- 파생객체 일관되게 관리 가능
함수를 묶는 다른 방법 : 여러함수를 변환함수로 묶기
절차
- 함수들이 공유하는 공통 데이터 레코드를 캡슐화
- 공통 데이터가 레코드 구조로 묶여있지 않다면 매개변수 객체 만들기를 통해 데이터를 하나로 만들기
- 공통 레코드를 사용하는 함수 각각을 새 클래스로 옮기기 (함수 옮기기)
- 데이터 조작 로직들은 함수로 추출해 새 클래스로 옮기기
6.10 여러 함수를 변환 함수로 묶기
원본데이터가 코드 안에서 갱신 시 클래스로 묶기
변환 함수로 묶을 시 가공 데이터를 새 레코드에 저장하므로 원본 데이터가 깨짐
function wonToDollar (money) {...}
function wonToEuro (money) {...}
--> function wonToMoney (money) {
const result = _.cloneDeep(money);
result .euro = wonToEuro(result);
result .dollar = wonToDollar(result);
... // 여기에 중첩 함수로 wonTo~ 함수들 깔려있고
return result ;
}
// 이런 느낌인가?
절차
- 변환할 레코드를 입력 받아 값을 그대로 반환하는 변환함수 만들기
- 깊은 복사로 처리
- 묶을 함수 중 함수 하나를 골라 본문 코드를 변환 함수로 옮기고, 처리 결과를 레코드에 새 필드로 기록. 그 후 클라이언트 코드가 이 필드를 사용하도록 수정
- 테스트
- 반복
6.11 단계 쪼개기
서로 다른 두 대상을 다루면 쪼개기
다른 단계에 있는 코드들 쪼개기
절차
- 두번 째 단계에 해당하는 코드를 독립 함수로 추출
1. 양치하는 함수 2. 세수하는 함수 <-- 이게 두번 째 단계 코드?
- 테스트
- 중간 데이터 구조를 만들어 앞에서 추출한 함수의 인수로 추가
- 테스트
- 추출한 두번 째 단계 함수의 매개변수를 하나씩 검토 (ex. 세수), 그 중 첫번째 단계에서 사용되는 것은 중간 데이터 구조로 옮김. 하나씩 옮기면서 테스트
- 첫번째 단계코드를 함수로 추출하면서 중간 데이터 구조를 반환하도록 만들기
'Refactoring' 카테고리의 다른 글
[리팩터링 2판] 8장 (4) | 2024.02.28 |
---|---|
[리팩터링 2판] 7장 (0) | 2024.01.17 |
[리팩터링 2판] 3, 4장 (0) | 2023.10.04 |
[리팩터링 2판] 2장 (0) | 2023.02.21 |
[리팩터링 2판] 1장 (0) | 2023.02.09 |