티스토리 뷰

코드가 복잡하다고 느끼는 건 언제일까요. 

복잡한 코드의 일반적인 특징은 내용이 길고 또  if-else 구문과 for문이 여러번 중첩 되는 경우가 많습니다. 

물론 구조적(상속, 복잡한 디자인패턴, 코드의 파편화 등)으로 복잡한 경우도 있지만 지금은 단순히 코드 그자체만 봤을 때입니다. 

실무에서 조건문만 잘 정리해도 코드가 확 바뀌는걸 볼 수 있었습니다. 

복잡한 조건문을 단순화하여 가독성을 향상시키는 작업을 하겠습니다. 


혹시나 구글에 참고할 만한 글이 있나 찾아봤더니 좋은 글이 있어 참고합니다. 

원본 링크 : https://wpshout.com/unconditionally-refactoring-nested-statements-cleaner-code/


조건문의 스타일을 Bubble styleGateway style로 분류한걸 볼 수 있습니다.  

Bubble style 


$is_first_thing_working = true;
$is_second_thing_working = true;
$is_third_thing_working = true;
$is_fourth_thing_working = true;
 
if( $is_first_thing_working === true ) {
    if( $is_second_thing_working === true ) {
        if( $is_third_thing_working === true ) {
            if( $is_fourth_thing_working === true ) {
                return 'Working properly!';
            }
            else {
                return 'Fourth thing broken.';
            }
        }
        else {
            return 'Third thing broken.';
        }
    }
    else {
        return 'Second thing broken.';
    }
}
else {
    return 'First thing broken.';
}

이미지만 봐도 복잡함이 느껴지지 않나요.

if-else 덩어리로 보입니다. 

또 다른 스타일인 Gateway style을 아래와 같습니다. 

Gateway style

$is_first_thing_working = true;

$is_second_thing_working = true;

$is_third_thing_working = true;
$is_fourth_thing_working = true;
 
if( $is_first_thing_working !== true ) {
    return 'First thing broken.';
}
 
if( $is_second_thing_working !== true ) {
    return 'Second thing broken.';
}
 
if( $is_third_thing_working !== true ) {
    return 'Third thing broken.';
}
 
if( $is_fourth_thing_working !== true ) {
    return 'Fourth thing broken.';
}
 
return 'Working properly!';


Gateway 스타일이 Bubble 스타일 보다 훨씬 쉽고 단순하게 변한걸 알 수 있습니다.  

조건문을 개선 하는 작업은 Bubble style을 Gateway style로 바꾸는게 작업이라고 볼 수 있습니다.  


예제를 통해 변환 작업을 해 보겠습니다. 


if(사용자정보가있다면){
    if(사용자권한이관리자라면){
        if(필수값이있다면){
            // 프로세스 처리 
            return true;
        }else{
            return false;
        } 
    }else{
        return false;
    }
}else{
    return false;
}

이런 소스가 익숙한가요? 거의 못 보셨다면 참 좋은 개발자들과 일하고 계신겁니다.  
전 자주 많이 봅니다. 그래서 리팩토링 할 일이 참 많습니다. 

실제 소스를 보면 조건문의 대부분은 값의 유무 확인, null 체크, 필수값 체크 등으로 이루어져 있습니다.  

이런 경우 return과 Exception을 활용한다면 조건문을 쉽게 풀어 낼 수 있습니다.  


if(사용자정보가없다면){
    return false;
}
if(사용자권한이관리자가아니라면){    
    return false;
}
if(필수값이없다면){    
    return false;
}
 
// 처리프로세스 
return true;

동일 결과물이지만 가독성이 확 바뀌지 않았나요?  

그런데 위의 코드는 쉽긴한데 실무에 써먹기에는 부족한 부분이 있습니다. 

Exception을 활용해서 바꿔보겠습니다.


if(사용자정보가없다면){
    throw new UsrNotFoundException("사용자 정보가 존재하지 않습니다.");
}
if(사용자권한이관리자가아니라면){
    throw new AccessDeniedException("관리자만 처리 가능합니다.");
}
if(필수값이없다면){    
    throw new IllegalArgumentException("**는 필수 입력 값입니다.");
}
 
// 처리프로세스 
return true;


단순히 결과값을 true/false로만 했을 때보다 훨씬 나은 결과물을 볼 수 있습니다. 

경우에 따라 반환값을 여러개 가져야 하거나 해당 경우에 따라 특정 처리를 해야 한다면 반환되는 객체와 Exception을 그에 맞게 설계하면 됩니다. 

위와 같은 경우가 프레임워크 또는 공통을 관리하는 사람이 Assert를 만들어서 사용하게 되면 소스는 더 간단하게 바뀔 수 있습니다.   


Assert.notNull(사용자정보, "사용자 정보가 존재하지 않습니다.");
Assert.isMatched(사용자권한, "관리자""관리자만 처리 가능합니다.");
Assert.notNull(사용자정보, "**는 필수 입력 값입니다.");
 
// 처리프로세스 
return true;


이와 같이 처리하기 위해서는 선결 과제가 있습니다. 


일관성 있는 예외 처리입니다. 

예외 발생시 어떻게 처리할지 정해 놓지 않으면 소스 여기 저기에 try-catch로 뒤덮히는 걸 볼 수 있습니다.  

예외 처리에 따른 예외 설계가 필요합니다. 

API에서는 예외를 메시지로 보여 줘야 합니다. 

웹 어플리케이션에서는 에러 페이지로 연결 시켜줘야 합니다.


예외 관련 처리와 설계 관련해서는 따로 정리를 하도록 하겠습니다. 

결론

최대한 Bubble style을 Gateway style로 전환하는게 중요합니다. 

중첩된 if문만 제거해도 코드의 가독성은 엄청나게 향상될 수 있습니다. 

Gateway style로 전환하기 위해서는 return과 Exception을 잘 사용해야 합니다. 


참고 

https://dzone.com/articles/code-smells-if-statements

* 조건문 처리에 대한 글인데 참고할 만한거 같습니다. 



댓글
댓글쓰기 폼