이 글은 리팩터링 2판(마틴 파울러) 책을 참고하였습니다.
순서
I. 리팩토링 정의 / 이유
II. 언제 하는가?
III. 코드의 악취("Smell")
I. 리팩토링 정의 / 이유
1. 리팩토링 정의
리팩토링[명사]
소프트웨어의 겉보기 동작은 그대로 유지한 채, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 기법
리팩토링[동사]
소프트웨어의 겉보기 동작은 그대로 유지한 채, 여러가지 리팩터링 기법을 적용해서 소프트웨어를 재구성 하다.
마틴 파울러는 위와 같이 정의하고 있다.
중복되는 워딩인 "겉보기 동작은 그대로 유지한 채" 가 포인트가 된다.
즉, 사용자 관점에서 달라지면 안된다.
버그 또한 그대로 남아있어야 한다.
+) 리팩토링은 성능 최적화와 구분되어야 한다.
리팩토링 : 코드를 이해하고 수정하기 쉽게 만들어준다. 성능개선? 모름.
성능 최적화 : 오로지 코드의 속도개선만 신경쓴다. 코드가 쉬워진다? 모름.
+) '리팩토링' '기능추가' 작업을 명확히 구분하여 작업한다.
리팩토링: 기능 추가는 절대 하지 않고 오로지 코드 재구성만 진행
기능추가 : 기존 코드는 절대 건드리지 않고 새 기능을 추가하기만 한다.
* 반드시 내가 어떤 작업을 하고 있는지 분명히 인식해야 한다.*
2. 리팩토링 이유
*소프트웨어 설계가 좋아진다
소프트웨어 이해가 쉬워진다
버그를 찾기 쉬워진다.
*프로그래밍 속도를 높일 수 있다.
같은 일을 하더라도 설계가 나쁘면 코드가 길어지기 십상이다.
또한 큰 프로젝트를 개발 하다보면 기능을 추가하기에 점점 시간이 오래걸리게 된다.
이는 모두 기존 코드베이스에 새로운 코드를 녹여내기 힘들다는 의미인데(계속 새로 만들고 싶은 이유)
리팩토링은 이를 해결하여 내부 품질을 높이기 위한 방법이다.
+) 개발 방법론
폭포수모델 / 애자일 모델
폭포수모델 : 순차적으로 개발단계가 정의되어 있음.
애자일모델 : 끊임없이 요구사항과 설계가 변경 되어야 함 (이 방법론을 갖자)
II. 언제 하는가?
"3의 법칙" by Don Roberts
1. 처음에는 그냥 한다.
2. 비슷한 일을 두 번째로 하게 되면(중복이 생겼다... 라는 것을 인식), 일단 계속 진행
3. 비슷한 일을 세 번째 하게 되면 리팩토링 한다.
그렇다면 정확히 어떤 시점일까?
이 시점을 설명하는데 마틴 파울러는 "Smell" 냄새 라는 표현을 사용하였다.
그 "Smell"들은 아래와 같다.
III. 코드의 악취 ("Smell")
그리고 해결 방법 표 정리
악취 명 | 특징 | 해결 방법 |
1. 기이한 이름 (Mysterious Name) | 이름만으로 무슨 일을 하고 어떻게 사용해야 하는지 명확하게 알 수 있어야 함. | 함수 선언 바꾸기 변수이름 바꾸기 필드이름 바꾸기 |
2. 중복 코드 (Duplicated Code) | 하나로 통합하기. | 함수 추출하기 문장 슬라이드하기 메서드 올리기 |
3. 긴 함수 (Long Function) | 오픈소스들은 하나같이 짧다. 요새는 함수 호출비용이 없어 끝없이 위임하는 방식으로 짧게 쪼개서 구성한다. 각 함수의 목적이 이름에 깔끔하게 드러나도록 새로운 함수를 만든다. |
함수 추출하기 임시 변수를 질의 함수로 바꾸기 매개변수 객체 만들기 객체 통째로 넘기기 함수를 명령으로 바꾸기 조건문 분해하기 함수 추출하기 조건부 로직 다형성으로 바꾸기(Switch) 반복문 쪼개기 |
4. 긴 매개변수 목록(Long Param List) | 이해를 쉽게 하기 위해 목록을 줄여야 한다. | 매개 변수를 질의 함수로 바꾸기 객체 통째로 넘기기 매개변수 객체 만들기 플래그 인수 제거하기 여러 함수를 클래스로 묶기 |
5. 전역 데이터 (Global Data) | 작은 수정이 나비효과를 일으킨다. | 변수 캡슐화 하기 |
6. 가변 데이터 (Mutable Data) | 무분별한 데이터 수정에 따른 위험을 줄여야 한다. | 변수 캡슐화 하기 변수 쪼개기 (용도별) 문장 슬라이드하기 함수 추출하기 질의 함수와 변경 함수 분리하기 세터 제거하기 파생 변수를 질의 함수로 바꾸기 여러 함수를 클래스 / 변환함수로 묶기 참조를 값으로 바꾸기 |
7. 뒤엉킨 변경 (Divergent Change) | 코드 수정 시 시스템에서 고쳐야 할 딱 한 군데를 찾아서 그 부분만 수정할 수 있도록 구현해야 한다. ** 단일 책임 원칙 (SRP)** 을 지키자 |
단계 쪼개기 함수 옮기기 함수 추출하기 클래스 추출하기 |
8. 산탄총 수술 (Shotgun Surgery) | 7. 뒤엉킨 변경과 비슷한데, 이는 코드 변경시 마다 자잘하게 수정해야 하는 클래스가 많을 때 나타난다. | 함수 / 필드 옮기기 여러 함수를 클래스 / 변환함수로 묶기 단계 쪼개기 함수 / 클래스를 인라인하기 |
9. 기능 편애 (Feature Envy) | 어떤 함수가 자기가 속한 모듈의 함수나 데이터보다 다른 모듈의 함수나 데이터와 상호작용이 더 많을 때 발생 | 함수 옮기기 함수 추출하기 |
10. 데이터 뭉치 (Data Clumps) | 몰려다니는 데이터들을 하나로 뭉쳐주기 | 클래스 추출하기 매개변수 객체 만들기 객체 통째로 넘기기 |
11. 기본형 집착(Primitive Obsession) | 정수, 부동소수점, 특히 문자열 등 기본형에 문제가 있다. | 기본형을 객체로 바꾸기 타입 코드를 서브클래스로 바꾸기 로건부 로직을 다형성으로 바꾸기 클래스 추출하기 매개변수 객체만들기 |
12. 반복 Switch문 (Repeated Switches) | 문제가 되는 이유는 조건절을 하나 추가할 때 마다 다른 switch문도 모두 찾아서 수정해야 하기 때문이다. | 조건부 로직을 다형성으로 바꾸기 |
13. 반복문 (Loops) | 시대에 걸맞지 않은 반복문을 쓰지 말자. 일급 함수들도 참고하자. |
반복문을 파이프라인으로 바꾸기 |
14. 성의 없는 요소 (Lazy Element) | 역할 없고 쓸데없는 것들 보내드리자. | 함수 / 클래스 인라인하기 계층 합치기 (상속시) |
15. 추측성 일반화 (Speculative Generality) |
'나중에 필요할거야'라는 안일한 생각 치워버리자. |
계층 합치기 함수 / 클래스 인라인하기 함수선언 바꾸기 죽은코드 제거하기 |
16. 임시 필드 (Temporary Field) | 당연히 모든 필드가 채워져 있다고 기대하기 때문에, 임시 필드를 따로 떼준다. | 클래스 추출하기 함수 옮기기 특이 케이스 추가하기 (조건부) |
17. 메시지 체인 (Message Chains) | getSomething()의 반복으로 이루어진 인터페이스 객체 호출 -> 클라이언트가 객체 네비게이션에 종속된 상태 |
위임 숨기기 함수 추출하기 함수 옮기기 |
18. 중개자 (Middle Man) | 캡슐화를 위해 위임을 사용하는 것. | 중개자 제거하기 함수 인라인하기 |
19. 내부자 거래 (Insider Trading) | 모듈 사이의 데이터 거래를 최소로 줄이고 모두 투명하게 처리해야 한다. | 함수 / 필드 옮기기 위임 숨기기 서브클래스를 위임으로 바꾸기 슈퍼클래스를 위임으로 바꾸기 |
20. 거대한 클래스 (Large Class) | 한 클래스가 너무 많은 일을 할 때, 필드가 너무 많을 때 중복코드를 막는다. 필드의 일부를 따로 묶어준다. |
클래스 추출하기 슈퍼클래스 추출하기 타입 코드를 서브클래스로 바꾸기 |
21. 서로 다른 인터페이스의 대안 클래스 들 (Alternative Classes with Different Interfaces) |
클래스의 가장 큰 장점은 언제든 클래스를 바꿀 수 있다는 것. 이를 위해 동일한 인터페이스가 필요하다. |
함수 선언 바꾸기 함수 옮기기 슈퍼클래스 추출하기 |
22. 데이터 클래스 (Data Class) | 데이터 필드, 게터, 세터 메서드로만 구성된 클래스 = 데이터 클래스 | 레코드 캡슐화하기 세터 제거하기 (데이터 접근 봉쇄) 함수 옮기기 함수 추출하기 단계 쪼개기 |
23. 상속 포기 (Refused Bequest) | 상속관계 중 필요한 몇 개만 받고 끝내려는 경우가 분명 있을 것이다. 상속하지 않는 코드를 모두 새로운 서브 클래스로 만들어준다. |
메서드 내리기 필드 내리기 서브클래스를 위임으로 바꾸기 슈퍼클래스를 위임으로 바꾸기 -> 상속을 깨버리기 |
24. 주석 (Comments) | 주석을 잘 입혀야한다. 주석이 없어도 이해가 되는 코드가 좋고 주석은 확실하지 않은 부분, 의도 및 추가 설명을 남겨야 한다. 작동 방식을 남기면 안된다. |
함수 추출하기 함수 선언 바꾸기 어서션 추가하기. |
'Programming > Refactoring(C++)' 카테고리의 다른 글
[Refactoring] 4. 조건문 분해하기 (For Long Function Smell) (0) | 2022.10.17 |
---|---|
[Refactoring] 3. 함수를 명령으로 바꾸기 (For Long Function Smell) (0) | 2022.10.17 |
[Refactoring] 2. 임시변수를 질의함수로 바꾸기 (For Long Function Smell) (0) | 2022.10.16 |
[Refactoring] 1. 함수 추출하기 (For Long Function Smell) (0) | 2022.10.13 |