BackEnd/Refactoring

[Refactoring] 데이터 클래스 (Data Class), 유산 포기 (Refused Bequest), 주석 (Comments), 중첩 조건문을 보호 구문으로 바꾸기 (Replace Nested Conditional with Guard Clauses)

샤아이인 2023. 1. 8.

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

18. 데이터 클래스

▶ 데이터 클래스 : public 필드 또는 필드에 대한 게터와 세터만 있는 클래스

 

- 코드가 적절한 위치에 있지 않기 때문에 이러한 냄새가 생길 수 있다.

- 예외적으로단계 쪼개기에서 중간 데이터를 표현하는데 사용할 레코드는 불변 객체로 데이터를 전달하는 용도로 사용할 수 있다.

 

public 필드를 가지고 있다면 레코드 캡슐화하기 (Encapsulate Record)”를 사용해 getter/setter를 통해서 접근하 도록 고칠 수 있다.

(여기서 말하는 "레코드"는, public 필드로 구성된 데이터 클래스를 말한다)

 

변경되지 않아야 할 필드에는세터 제거하기 (Remove Setting Method)”를 적용할 수 있다.

게터와 세터가 사용되는 메소드를 찾아보고 함수 옮기기 (Move Function)”을 사용해서 데이터 클래스로 옮길 수 있.

메소드 전체가 아니라 일부 코드만 옮겨야 한다면 함수 추출하기 (Extract Function)”을 선행한 뒤에 옮길 수 있다.

 

19. 유산 포기

서브클래스가 슈퍼클래스에서 제공하는 메소드나 데이터를 잘 활용하지 않는다는 것은 해당 상속 구조에 문제가 있다는 뜻이다.

 

기존의 서브클래스 또는 새로운 서브클래스를 만들고 슈퍼클래스에서 메소드와 필드를 내려주면 (Push Down Method / Field)” 슈퍼클래스에 공동으로 사용하는 기능만 남 길 수 있다.

 

서브클래스가 슈퍼클래스의 기능을 재사용하고 싶지만 인터페이스를 따르고 싶지 않은 경 우에는 슈퍼클래스 또는 서브클래스를 위임으로 교체하기리팩토링을 적용할 수 있다.

 

20. 주석

모든 주석이 나쁜것이 아니다!, 좋은 냄새에 해당되는 주석 또한 있다.

다만 불필요한 주석은 제거하자는 의미이다.

 

시스템적으로 어떤 필요한 규칙이 있다면, "Introduce Assertion"을 적용하여 사용할 수 있다.

 

20 - 1) Introduce Assertion

종종 코드로 표현하지 않았지만 기본적으로 가정하고 있는 조건들이 있다. 그러한 조건을 Assertion을 사용해서 보다 명시적으로 나타낼 수 있다.

 

Assertionifswtich 문과 달리 항상” true이길 기대하는 조건을 표현할 때 사용한다.

  • 프로그램이 Assertion에서 실패한다면 프로그래머의 실수로 생각할 수 있다.
  • Assertion이 없어도 프로그램이 동작해야 한다. (자바에서는 컴파일 옵션으로 assert 문을 사용하지 않도록 설정할 수도 있다.)

 

특정 부분에선 특정한 상태를 가정하고 있다는 것을 명시적으로 나타냄로써, 의사소통적인 가치를 지니 고 있다.

다만, 명확한 의사소통을 위해서 사용할뿐 기능적으로 의존하면서 사용하면 안된다!

 

21. 중첩 조건문을 보호 구문으로 바꾸기

일반적인 if ..(1).. else ..(2).. 문 에서 (1), (2)번은 둘다 동일하게 50:50으로 중요한 정도를 나타낸다.

하지만, 조건문에서 한쪽을 강조해야 하는 경우도 있다.

 

예를 들어 다음 코드를 살펴보자!

public class GuardClauses {

    public int getPoint() {
        int result;
        if (isVip()) {
            result = vipPoint();
        } else if (isPlat()) {
            result = platPoint();
        } else {
            result = normalPoint();
        }
        return result;
    }

    private boolean isPlat() { ... }

    private boolean isVip() { ... }

    private int vipPoint() { return 100; }

    private int platPoint() { return 50; }

    private int normalPoint() { return 10; }
}

getPoint()에서는 Plat인지? Vip인지? 에 따라 나뉘며, 둘다 아니라면 normal에 해당된다.

위 코드를 다음과 같이 변경하자!

public int getPoint() {
    if (isVip()) return vipPoint();
    if (isPlat()) return platPoint();
    return normalPoint();
}

 

댓글