alt
Home 리팩터링 10장. 조건부 로직 간소화
Post
Cancel

리팩터링 10장. 조건부 로직 간소화

: 조건부 로직은 필연적인 요소이지만, 쉽게 프로그램을 복잡해보이게 만든다. 이 장의 리팩터링을 적용하면 이러한 로직들을 보다 이해하기 쉬운 코드로 바꿀 수 있다.


1. 조건문 분해하기

: 복잡한 조건절은 해당 코드의 목적이 무엇인지 파악하기 어렵게 만든다. 조건절과 작업들을 함수로 추출해주면 코드 의도가 확실히 전달된다.


2. 조건식 통합하기

: 같은 결과를 수행하는 조건절을 통합한다. 관련 코드를 모으면서 하려는 일이 명확해지고, 보통의 경우 함수 추출까지 이어지면서 의도를 파악하기 쉬운 코드가 된다.

  • 같은 결과를 수행하면 || 로 묶일 가능성이 크고, if문 중첩이라면 && 로 묶일 가능성이 크다.
  • 논리연산자로 묶여 더 복잡해보인다면 이 때 함수추출을 고민한다.


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

: early-return의 형태로 바꾸기

  • 정상 조건: if-else가 모두 정상인 형태. if, else 에 같은 무게를 두어 둘다 중요함을 나타낸다.
    • 만약 이러한 경우인데 early return로 바꾸었을 때 중복 코드가 나오게 되는 경우가 있다. 그러한 경우 오히려 if-else코드가 명확할 것 같다.
  • 비정상 조건: (보호 구문) 비정상인 경우 바로 함수에서 빠져나온다.
    • 이 케이스에선 조건을 반대로 만들어 더 간결해지는 경우도 있다.


함수 진입점과 반환점이 하나여야한다?

: 하나일 때 더욱 명확하다면 하나로, 그렇지 않다면 (e.g. 보호 구문의 경우) 더욱 명확하도록 early return 형태로 변경하는 것이 맞아보인다.


4. 조건부 로직을 다형성으로 바꾸기

: 클래스와 다형성 활용하기. 팩터리 함수를 정의해 적절한 서브클래스의 인스턴스를 반환해준다.

  • 무조건적인 다형성 활용은 당연히 오버엔지니어링 일 수 있고, 핵심은 ‘공통 switch 로직이 중복으로 있는가?’ 인 것 같다.
    • 특히, 해당 부분이 ‘다형성이 맞는가?’ 를 생각해야한다. 데이터만 다르고, 실제 동작 자체는 각각이 다를바가 없는 경우도 있다.
  • 기본 동작을 슈퍼 클래스로, 변형 동작들을 서브클래스로 만드는 방법도 있다.


5. 특이 케이스 추가하기

: 특정 값을 확인한 후 같은 동작을 수행하는 코드를 객체로 위임하기. 특히, null check에서 같은 특이 케이스를 반환해야 하는 경우가 많다. 이 때 특이 케이스 객체를 통해 반환하도록 한다. (aka. 특이 케이스 패턴, 널 객체 패턴, ..)


6. 어서션 추가하기

: 항상 해당 조건이 참이라고 가정하는 조건부 문장. 만약 어서션에 걸린다면 개발자가 로직을 짰음을 알려준다. 다른 개발자에게 어떤 상태여야함을 알려주는 소통 도구가 되기도 한다.

  • 테스트 코드: 어서션과 같은 역할을 한다. 따라서 테스트 코드가 존재한다면 어서션은 불필요할 수 있다.


어서션(error)과 catch
  • 어서션은 Error를 유발하기 때문에 제대로되지 않은 어서션은 위험할 수 있다. 자바에서는 exception을 확장한 Throwable만 catch가 가능하다. 따라서 어서션은 “어떠한 외부에 입력에 따라서도 유발되는 것이 아닌, 개발자의 실수로만 유발될 수 있는” 조건에 다는 것이 좋다.


7. 제어 플래그를 탈출문으로 바꾸기

: flag 역할을 하는 boolean 변수를 없애고 break, continue 를 통한 제어를 적극 활용한다.



Reference)

리팩터링 2판

This post is licensed under CC BY 4.0 by the author.

리팩터링 9장. 데이터 조직화

리팩터링 11장. API 리팩터링