BackEnd/Refactoring

[Refactoring] 중복 코드 (Duplicated Code)

샤아이인 2022. 2. 20.

백기선 님의 리팩터링 강의를 들으며 요약한 내용입니다.

 

2. 중복코드

 

중복되는 코드는 제거하여 코드의 가독성을 높혀야 한다.

  • 동일한 코드를 여러곳에서 사용하는 경우 => 함수로 추출하기 (Extract Function)
  • 코드가 어느정도는 비슷하게 생겼지만, 완전하게 같지는 않은경우 => 코드 정리하기 (Slide Statements)
    • Slide Statements는 말 그대로 문단의 위치를 조종하는 것 이다.
  • 여러 하위클래스에 동일한 코드가 있다면 => 메서드 올리기 (Pull Up Method)

위와 같은 방식으로 중복 코드를 제거 할때는 동일한 코드 부분 모두를 변경해주어야 한다.

일부분 만 변경해주면 나중에 버그가 발생할 확률이 높다.

 

1. 함수 추출하기

"의도""구현"을 잘 분리해야 한다.

 

어떤 코드를 읽을 때 메서드가 마치 책을 읽듯 이해가 되지 않는다면, 그 코드는 "구현"을 보고 있는 것 이다.

어떤 코드를 읽을 때 어떤일을 하는지 잘 이해가 된다면 "의도"를 파악할수 있는 좋은 코드이다.

 

해당 코드를 읽을때 어떤 일을 하고있는 코드인지 시간을 들여 이해해야 하는 코드는 "구현"에 관한 부분이다.

해당 부분을 메서드로 추출하여 메서드 이름으로 "의도"를 전달해야 한다.

 

또, 한줄짜리 메서드도 의도를 잘 전달한다면 사용해도 좋다!

Intellij Tip
cmd + 방향키 : 문장 한줄에서 맨앞, 맨뒤로 커서 이동
option + 방향키 : 문장 한줄에서 단어 기준으로 이동
shift + 방향키 : 드래그

코드 예시로 살펴보자.

private void printParticipants(int eventId) throws IOException {
    // Get github issue to check homework
    GitHub gitHub = GitHub.connect();
    GHRepository repository = gitHub.getRepository("whiteship/live-study");
    GHIssue issue = repository.getIssue(eventId);

    // Get participants
    Set<String> participants = new HashSet<>();
    issue.getComments().forEach(c -> participants.add(c.getUserName()));

    // Print participants
    participants.forEach(System.out::println);
}

위 메서드가 하는일을 파악하기 위해서는 시간을 투자하여 위에서 부터 한줄씩 읽어야 한다.

주석을 기준으로 3 덩어리로 함수로 추출하면 될것 같다.

 

변경후의 코드는 다음과 같다.

private void printParticipants(int eventId) throws IOException {
    GHIssue issue = getGhIssue(eventId);
    Set<String> participants = getUsernames(issue);
    print(participants);
}

이전에 사용하던 주석을 지워도, 동일하게 의미전달이 가능해졌다.

 

2. 코드 정리하기

관련있는 코드끼리 묶어두어야 이해하기 편하기 때문에, 코드를 상하로 이동시키면서 관련 group들로 나누는 것 이다.

 

대표적으로 변수같은 경우, 사용하지 직전에 생성해야 group으로 관리하기가 편하다.

예전 C언어 사용할 때 처럼 맨 상단에 사용할 변수를 모두 명시해 두면, 코드 중간쯤되서 해당 변수를 다시 만났을때 해당 변수가 뭔지 기억이 나지 않아 다시 맨 위로 올라가야 할수도 있다.

코드 line의 이동 Tip
option + shift + 방향키

 

3. 메서드 올리기

이번 내용은 하위 class에서 중복되는 메서드를 상위 class로 올리는 리팩토링 이다.

 

- 함수 매개변수화하기 (Parameterize Function)

비슷하지만 일부 값만 다른 경우라면, “함수 매개변수화하기 (Parameterize Function)” 리팩토링을 적 용한 이후에, 이 방법을 사용할 수 있다.

둘 이상의 함수의 로직이 아주 비슷하고 단지 리터럴 값만 다르다면, 그 다른 값만 매개변수로 받아 처리하는 함수 하나로 합쳐서 중복을 없앨 수 있다.

// from
public void tenPercentRaise(Person person) {
    person.MultiplySalaryByPercent(1.1);
}

public void fivePercentRaise(Person person) {
    person.MultiplySalaryByPercent(1.05); 
}

--------------------------------------------

// to
public void raiseByFactor(aPerson, factor) {
    person.MultiplySalaryByPercent(1 + factor); 
}

 

- 필드 올리기 (Pull Up Field)

하위 클래스에 있는 코드가 공통된 필드를 사용하고 있다면, “필드 올리기 (Pull Up Field)”를 적용할수도 있다.

출처 - https://refactoring.guru/pull-up-field

 

- 메서드 올리기 (Pull Up Method)

자식 클래스에서 공통된 메서드 또한 공통으로 뽑아 상위 class 로 올려줄수가 있다.

 

 

- 템플릿 메소드 패턴 (Template Method Pattern)

수 있다.

두 메소드가 비슷한 절차를 따르고 있다면, “템플릿 메소드 패턴 (Template Method Pattern)” 적용을 고려할 수 있다.

 

[Design Patterns] Template Method Pattern : 템플릿 메소드 패턴

Head First Design Patterns 책을 읽으며 정리한 내용입니다. 문제가 될 시 글을 내리도록 하겠습니다! Template Method Pattern 이란? " data-ke-type="html"> <>HTML 삽입 미리보기할 수 없는 소스 Template Me..

blogshine.tistory.com

 

댓글