리팩토링 43. Assertions 추가하기

    들어가기 전

    이 글은 인프런 백기선님의 강의를 복습하며 작성한 글입니다. 


    리팩토링 43. Assertions 추가하기 (Introduce Assertion)

    • 문제 상황
      • 종종 코드로 표현하지 않았지만 기본적으로 가정하고 있는 조건들이 있다. 그런 조건은 알고리즘으로 추론하거나 주석을 읽으면서 확인할 수 있다.
      • 전제조건 / 후처리 조건은 Assertion을 사용해서 보다 명시적으로 나타낼 수 있다. (런타임에는 영향 없음)
    • Assertions 추가하기
      • Assertions은 if / switch 문과 달리 '항상' True이길 기대하는 조건을 표현할 때 사용한다.
      • 프로그램이 Assertion에서 실패한다면 프로그래머의 실수로 생각할 수 있다.
      • Assertion이 없어도 프로그램이 동작해야 한다. (자바에서는 기본 컴파일 옵션이 assert 문을 사용하지 않도록 설정되기 때문임.)
    • 'Assertion 추가하기'의 가치
      • 특정 부분에서 특정한 상태를 가정하고 있다는 것을 명시적으로 나타낸다. 따라서 '의사전달' 부분에서 가치를 지니고 있다. 
      • 프로그램적으로 반드시 지켜져야 하는 조건이라면 Assertion 대신, If 조건문을 사용하자. 

     

    예를 들어 어떤 메서드를 시작하기 전에 '어떤 값은 양수일 것이다'라고 하는 전제조건들이 있다. 이 전제조건들을 Assertion으로 표현해주면 디버깅 할 때 유용하고, 이 코드를 읽는 사람에게도 전제조건이 무엇인지 명확히 전달된다. 

    Assertion을 넣어두면, 가정하고 있는 조건을 명시적으로 드러내준다. 따라서 전제조건 같은 것을 주석에 적지 않아도 되며, 프로그래머는 주석을 읽지 않고 Assert 문을 보는 것만으로 알 수 있게 된다. 또한 어떤 계산을 완료했을 때 생성된 값이 적어도 이런 조건을 만족해야한다는 것 역시 assert 문으로 표현할 수 있을 것이다. 


    자바에서 Assertions

    자바에서는 Assertion이 옵션이다. 런타임에서 Assertion을 체크할지는 JVM 옵션으로 선택할 수 있는데, 기본값은 무시하는 옵션이다. 따라서 컴파일 할 때 assert문이 없어지며, 이 때문에 런타임에서는 assert문이 없다. 따라서 정말로 확인해야하는 조건이라면 assert 문과 상관없이 동작하도록 프로그래밍 해야한다.

    따라서 프로그래밍적으로 반드시 체크해야하는 것은 If / Swtich 문을 사용해야한다. assert문은 '의사소통'으로서의 가치를 지닌 프로그래밍적인 문법이라고 보면 된다. 코드를 읽는 사람을 위한 용도로 보면 된다. 


    인텔리제이 테스트코드에서 Assertions

    테스트 코드를 실행할 때는 인텔리제이에서 assert 문을 확인하도록 해주기 때문에 assert문의 동작을 테스트 코드에서 볼 수 있다. 이것은 인텔리제이에서 코드를 실행할 때 -ea라는 JVM 옵션을 넣어주기 때문이다. -ea는 Enable Assertion의 약자로 볼 수 있다. 


     

    코드

    Customer 클래스는 discountRate라는 필드를 받는다. 내부적으로 discountRate는 다음 가정을 가지고 있다.

    • discountRate는 음수가 아니다. 

    이 전제조건은 어디에 어떻게 표현하는 것이 좋을까? 다음 두 가지로 선택할 수 있다.

    1. 주석으로 표현할 수 있음.
    2. assert 문으로 표현할 수 있음. 

    주석을 읽기보다는 메서드 내부에 assert 문으로 전제조건이 표현되어있는 것이 코드를 읽는 사람 입장에서는 더욱 읽기 쉬운 코드가 될 것이다. 따라서 내부에 assert문으로 전제조건을 표현해보자.

    // discountRate는 음수가 아님을 가정한다.
    // 이 전제조건은 현재 어디에도 표현되어 있지 않다.
    // 전제 조건을 주석으로 작성하는 것보다는 assert 문으로 표현해주는 것이 좋다.
    public class Customer {
    
        private Double discountRate;
    
        public double applyDiscount(double amount) {
            return (this.discountRate != null) ? amount - (this.discountRate * amount) : amount;
        }
    
        public Double getDiscountRate() {
            return discountRate;
        }
    
    
        public void setDiscountRate(Double discountRate) {
            this.discountRate = discountRate;
        }
    }

    아래와 같이 표현할 수 있다. 아래는 assert문 / If문을 둘다 사용했다. 각각의 역할은 다음과 같다. 

    1. assert문 : 전제조건을 표현할 때 사용.
    2. If문 : 프로그래밍적으로 반드시 필요한 조건일 때 사용. 
    public void setDiscountRate(Double discountRate) {
        assert discountRate >= 0; // 단순히 주석 용도라면 이걸로.
        if (discountRate < 0) throw new RuntimeException(); // 프로그래밍적으로 필요하다면 이걸로.
        this.discountRate = discountRate;
    }

     

    'etc > 리팩토링' 카테고리의 다른 글

    자바 성능 최적화 3  (0) 2023.06.24
    냄새 24. 주석  (0) 2023.05.10
    냄새 23. 상속포기  (0) 2023.05.10
    리팩토링 42. 레코드 캡슐화 하기  (0) 2023.05.10
    냄새 22. 데이터 클래스  (0) 2023.05.10

    댓글

    Designed by JB FACTORY