소프트웨어공학

소프트웨어 구현_리펙토링(Refactoring), method (extract , move, rename, inline), bad smell, 코드 스멜

스윙스윙 2021. 9. 24. 11:35

 ▣ 소프트웨어 구현_리펙토링(Refactoring), method (extract , move, rename, inline), bad smell

 

■ Refactoring 대상 , Code Smell 종류

 

구분 설명 해결방법
중복코드
(Duplicated Code)
같은 코드가 두 군데 이상 존재할 때
서브 클래스에 같은 코드가 존재할 때
메서드 추출, 클래스 추출, 메서드 상향, 템플릿 메서드 형성
장황한 메소드
(Long Method)
메서드 안의 내용이 너무 길다 Replace Parameter with Method 매개변수 세트를 메소드로 전환
Introduce Parameter Object 매개변수 세트를 객체로 전환
Reserve Whole Object 객체를 통째로 전달하는 기법
방대한 클래스
(Large Class)
기능과 변수가 지나치게 많은 클래스 클래스 추출, 하위클래스 추출, 인터페이스 추출, 데이터 값을 객체로 전환
과다한 매개변수
(Long Parameter List)
메서드의 매개변수 길이, 개수가 지나치게 많음 매개변수 세트를 메서드로 전환, 매개변수 세트를 객체로 전환, 객체를 통째로 전달
수정의 산발
(Divergent Change)
하나의 클래스에 대해 잦은 변경이 발생하는 경우
Extract class
기능의 산재
(Shotgun Surgery)
변경이 발생할때 마다 많은 클래스가 수정되는 경우
Move Method, Move Field, Inline Class
잘못된 소속
(Feature Envy)
객체 안의 메서드와 데이터가 잘못연결
객체의 메서드가 다른 객체의 데이터에 더 많이 접근
메서드 이동, 필드이동, 메서드 추출
데이터 뭉치
(Data Clump)
동일한 목적/동일한 사용용도인 3~4개의 데이터가 몰려 있음 (주로 인스턴스변수가 매개변수 등에 몰림) 클래스 추출, 매개변수 세트를 객체로 전환, 객체를 통째로 전달
강박적 기본 타입사용
(Primitive Obsession)
객체 지향에서 제공하는 사용자 정의 타입(클래스)를 사용하지 않고 기본형 타입만을 사용한다 데이터 값을 객체로 전환, 클래스 추출, 매개변수 세트를 객체로 전환, 배열을 객체로 전환, 분류부호를 클래스로 전환, 분류 부호를 하위클래스로 전환, 분류 부호를 상태/전략 패턴으로 전환
switch문
(Switch Statements)
중복 코드 발생 확률이 높음 Extract Method 를 실시해서 Switch 문을 메소드로 빼낸 후 Move Method 를 실시
Replace type code with subclass 하위 클래스 전환 기법
Replace type code with state/strategy 상태 전략 패턴 전환 기법
평행 상속 계층
(Parallel Inheritance Hierarchies)
'기능의 산재'의 특수상황 : 서로 다른 두 상속 계층의 클래스가 서로 연관되어 있음
한 클래스의 하위 클래스를 만들 때 마다 매번 다른 클래스의 연관된 다른 클래스의 하위 클래스도 만들어야 함
메서드이동, 필드 이동
직무유기 클래스
(Lazy Class)
사용하지 않거나 비용대비 효율이 떨어지는 클래스 클래스 내용직접 삽입, 계층 병합
막연한 범용코드
(Speculative Generality)
추측성 일반화
향후 필요할 것이라는 막연한 생각으로 미리 만들어 둔 코드 계층 병합, 클래스 내용 직접삽입, 매개변수 제거, 메서드명 변경
임시필드
(Temporary Field)
클래스안의 인스턴스 변수가 아주 특정한 상황에서만 사용됨, 대부분의 경우 실제 사용되지 않는 변수 클래스 추출, Null 검사를 널 객체에 위임
메시지 체인
(Message Chains)
클라이언트는 A객체 요청 -> A객체는 B객체에 요청 -> B객체는 C 객쳉에 요청 순으로 연쇄적 요청이 발생하는 상황 대리 객체 은폐
과잉 중개 메서드
(Middle Man)
중개인
위임이 너무 남발하고 실제로 하는 일이 별로 없는 클래스
클래스 메서드의 절반 이상이 기능을 위임만 하고 있음
과잉중개 메서드 제거, 메서드 내용 직접 삽입, 위임을 상속으로 전환
지나친 관여
(Inappropriate Intimacy)
클래스 간 관계가 지나치게 밀접함
서로 너무 많이 관여하고 있음
메서드 이동, 필드 이동, 클래스의 양방향 연결을 단방향으로 전환, 대리 객체 은폐
인터페이스가 다른 대용 클래스
(Alternative Classes with Different Interface)
기능은 동일한데 시그니처(메서드 명이나 매개변수 구조 등)가 다른 메서드 메서드명 변경, 메서드 이동
미흡한 라이브러리 클래스
(Incomplete Library Class)
불충분한 라이브러리에 너무 의존하고 있다 외래 클래스에 메서드 추가, 국소적 상속확장 클래스 사용
데이터 클래스
(Data Class)
데이터 클래스란 필드와 필드 읽기/쓰기 메서드만 있는 클래스 메서드 이동, 필드 캡슐화, 컬렉션 캡슐화
방치된 상속물
(Refused Bequest)
상속받은 메서드나 데이터를 하위 클래스에서 사용하지 않음 상속을 위임으로 전환
불필요한 주석
(Comments)
코드 스멜을 감추기 위해 수 많은 주석을 남용함 메서드 추출, 어설션 넣기

 

■ 리펙토링(Refactoring) 주요 기법

기법 설명
Extract Method 그룹으로 함께 묶을 수 있는 코드 조각이 있으면 코드의 목적이 잘 드러나도록 메소드의 이름을 지어 별도의 메소드로 추출
Move Method 메소드가 자신이 정의된 클래스보다 다른 클래스의 기능을 더 많이 사용하고 있다면, 이 메소드를 가장 많이 사용하고 있는 클래스에 비슷한 몸체를 가진 새로운 메소드 생성
Rename Method 메소드의 이름이 그 목적을 드러내지 못하고 있다면 메소드의 이름 변경
Inline Method 메소드 몸체가 메소드의 이름 만큼이나 명확할 때는 호출하는 곳에 메소드의 몸체를 넣고 메소드를 삭제
Extract Class 두 개의 클래스가 해야 할 일을 하나의 클래스가 하고 있는 경우 새로운 클래스를 만들어 관련 있는 필드와 메소드를 기존 클래스에서 새로운 클래스로 이동
Replace Temp With
Query
수식의 결과값을 저장하기 위해서 임시 변수를 사용하고 있다면, 수식을 추출해서 메소드를 만들고, 임시 변수를 참조하는 곳을 찾아 모두 메소드 호출로 교체
Substitute Algorithm 알고리즘을 보다 명확한 것으로 바꾸고 싶은 경우, 메소드의 몸체를 새로운 알고리즘으로 교체

 


2018년 38번

정답 : 2번

 

Switch문 관련해서 code smell을 제거하기 위해 replace type code with subclass 기법(하위 클래스 전환기법)

또는 replace type code with state/strategy 기법(상태/전략 패턴 전환 기법)을 판단하여 사용한다 .

즉 서브클래스로 대체 하거나 디자인 패턴을 적용

 

■ 과대한 매개변수 (Long Parameter List)
Code Smell : 메소드에 전달하는 인수의 수가 너무 많다
- 대표적 해결방법
Replace Parameter with Method 매개변수 세트를 메소드로 전환
Introduce Parameter Object 매개변수 세트를 객체로 전환
Reserve Whole Object 객체를 통째로 전달하는 기법

■ Switch 문 (Switch Statement)
Code Smell : Switch 문 또는 If 문을 이용하여 동작을 분할하고 있다
- 대표적 해결방법
Extract Method 를 실시해서 Switch 문을 메소드로 빼낸 후 Move Method 를 실시
Replace type code with subclass 하위 클래스 전환 기법
Replace type code with state/strategy 상태 전략 패턴 전환 기법

 

- 분류코드(type code)는 객체 종류를 나타내는 값

분류코드를 상태/전략 패턴으로 치환(Replace Type Code with State/Strategy) 리팩토링에서 상태패턴 또는 전략패턴이라는 디자인패턴을 사용함
- 분류 코드를 상태/전략 패턴으로 치환은 분류 코드를 상태 객체라고 부르는 객체를 사용해 치환함

■ 제어 플래그 제거 (Remove Control Flag)
Code Smell : for 문 등 루프내 제어 플래그를 활용한 제어 행위
- 대표적 해결방법
for 문 등 루프내 제어 플래그 대신 break 나 continue 사용하여 가독성 키울 것

 


2019년 47번

정답 : 4번

extract method(메소드 추출)기법은 하나의 메소드가 너무 거대할 경우 이를 분리하여 고유의 기능을 가진 별도의 작은 메소드로 추출하여 분리하는 것임

 

리펙토리 전인 'print'메소드는 3개의 기능(테두리 출력, 내용 출력, 테두리 출력)이 모두 하나의 메소드 안에 들어 있음

리펙토링 결과를 보면 3개 기능을 3개의 별도 메소드로 분리했음

 

1) hide method

클래스의 어떤 public메소드가 다른 클래스에서 사용되지 않는다면 해당 메소드는 private으로 변경함

2) push down method

수퍼클래스의 어떤 메소드가 특정 서브클래스하고만 관련 있다면 해당 메소드를 그 서브클래스로 옮김

3) inline method

메소드 본문이 간단하고 명확하다면 이를 별도의 메소드로 만들지 말고 해당 메소드를 호출하는 곳 안으로 옮기고 해당 메소드를 삭제함

 

before)

after)

 

 


2021년 35번

정답 : 1번

1) inline method

메소드 본문이 간단하고 명확하다면 이를 별도의 메소드로 만들지 말고 해당 메소드를 호출하는 곳 안으로 옮기고 해당 메소드를 삭제함

 

2) extract method

그룹으로 함께 묶을 수 있는 코드 조각이 있으면 코드의 목적이 잘 드러나도록 메소드의 이름을 지어 별도의 메소드로 추출

2019년 47번 참고

 

3) move method

메소드가 정의된 클래스보다 다른 클래스에서 더 많이 사용된다면 해당 클래스로 메소드를 옮기고, 이전 메소드는 간단한 위임으로 바꾸거나 완전히 제거함

 

 

4) substitute algorithm

알고리즘을 더욱 명료하게 변경하고 싶으면 메서드의 내용을 새로운 알고리즘으로 변경함

- 적용전

- 적용후

 


2012년 31번

정답 : 2번

Refactoring 정의

소프트웨어 시스템의 원래 기능은 그대로 두면서 내부의 구조를 개선하는 활동

버그의 가능성을 최소화하기 위해서 코드를 깔끔하게 정리하는 방법

이미 작성된 코드의 설계를 나중에 개선하는 행동

 

목적

버그를 찾기 쉽게함

기능을 추가하기 쉽게 함

리뷰하는 것을 쉽게 함

 

* 인스펙션(inspection) : 정적 시험 방법의 하나로 공식적인 리뷰 절차

* 정보은닉(information hiding) : 객체지향 개념 중 하나로 메소드나 속성과 같은 정보를 외부로부터 차단하고 인터페이스를 통해 접근토록 하여 모듈간 결합도를 낮추는 방법

* 확인(verification) : 소프트웨어가 고객의 의도에 따라 구현되었음을 보장하는 활동

고객이 원하는 목적에 맞는 제품을 만들고 있음을 보장하는 것

 


2016년 37번

정답 : 4번

확산적 변경(divergent change)는 하나의 클래스에 대해 잦은 변경이 발생하는 경우 Extract class

Extract Class 두 개의 클래스가 해야 할 일을 하나의 클래스가 하고 있는 경우 새로운 클래스를 만들어 관련 있는 필드와 메소드를 기존 클래스에서 새로운 클래스로 이동

 


2016년 40번

정답 : 2번

Shotgun surgery : 변경이 발생할 때 마다 많은 클래스가 수정되는 경우

divergent change : 하나의 클래스에 대해 잦은 변경이 발생하는 경우

Switch Statements : 스위치 문장이 지나치게 많은 case를 포함할 경우(많은 중복이 발생됨)

middle man : 클래스가 가진 메소드 대부분이 다른 클래스에 책임을 넘기는 경우

 


2021년 41번

정답 : 3번

Shotgun surgery : 변경이 발생할 때 마다 많은 클래스가 수정되는 경우

 


2021년 50번

정답 : 1번

Hide Delegate(위임 숨기기) : 클라이언트에게 위임객체를 숨김