본문 바로가기
개발팁

code bad smell - early return(얼리리턴, 빠른리턴)을 사용한 refactoring 기법

by devscb 2022. 10. 14.
반응형




code bad smell - early return을 사용한 refactoring 기법





 early return을 소개하는 이유


if문이 중첩으로 있으면 보통 읽기가 어렵습니다.
이를 개선하기위한 방법 중 하나가, early return이라는 방식이 있습니다.


 early return이란?


말 그대로 빨리 리턴을 한다는 뜻입니다.
조건이 부합하지 않으면 곧바로 return을 하도록 하는 코딩 패턴입니다.
이렇게 작성함으로써, 가독성이 좋은 코드가 될 수 있습니다.

 

 

 early return을 적용한코드와 그렇지 않은코드


javascript 의 예시로 early return을 적용한 코드와, 그렇지 않은 코드의 예시를 살펴보겠습니다.


//early return을 적용한 코드
function foo1(){
 if (!bar()) {
   return null;
 }
 return 1;
}

//earyl return이 적용되지 않은 코드
function foo2(){
 var ret = null;
 if (bar()) {
   ret = 1;
 }
 return ret;
}
 


earyl return을 사용한 코드는 말그대로,
if(!bar()) 쪽에 조건이 맞지 않으면 return을 써주었습니다.
foo1, foo2는 로직이 똑같고, 가독성도 큰 차이는 없는 것 같습니다.
하지만 코드가 길어진다면 early return을 사용한 foo1 쪽 코드가 더 가독성이 좋아집니다.
좀 더 복잡한 코드를 보고, 코드 개선을 해보면서 살펴보겠습니다.

 

 

 early return으로 코드 개선하기



아래와 같이 중첩된 if문의 코드를 봅시다.


public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    int retval = SUCCESS;
    if (someCondition)
    {
        if (name != null && name != "")
        {
            if (value != 0)
            {
                if (perms.allow(name)
                {
                    // Do Something
                }
                else
                {
                    retval = PERM_DENY;
                }
            }
            else
            {
                retval = BAD_VALUE;
            }
        }
        else
        {
            retval = BAD_NAME;
        }
    }
    return retval;
}



depth 가 깊어질수록, 가독성이 떨어지는것을 느낄 수 있을것입니다.
depth를 더 늘릴수록 에디터 화면 바깥으로 까지 코드가 길어질 수 있기에,
스크롤도 해야하는 불편함도 있을것입니다.

이 코드를 early return으로 개선하려면 어떻게 해야할지 살펴보겠습니다.
먼저, if문이 있고 if문 안의 내용이 길다면 early return을 고려해봄직한 상황입니다.
특히 중첩으로 block이 있으면 더욱 고려를 해볼만 합니다.

이 코드를 early return으로 개선하겠다라고 생각하고
맨 바깥쪽의 if문을 살펴봅시다.
그러면 아래 코드와 같습니다.


public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    int retval = SUCCESS;
    if (someCondition)
    {
  //상세코드..
    }
    return retval;
}


early return은 조건이 맞지 않을경우 빨리 리턴해주는 것이므로, someCondition을 반전시켜줍니다.
그러고 난 후, 반전시켰을 때의 조건은 어떤값을 return을 하는지를 살펴봅시다.
그러면 retval을 바로 리턴해주는것을 알 수 있고, 아래와 같이 개선할 수 있습니다.


public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    int retval = SUCCESS;
    if (!someCondition)
    {
  return retval;
    }
 //상세코드..
    return retval;
}



"상세코드.." 부분을 다시 풀어서 전체코드를 보면, 아래와 같습니다.


public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    int retval = SUCCESS;
    if (!someCondition)
    {
  return retval;
 }
 if (name != null && name != "")
 {
  if (value != 0)
  {
   if (perms.allow(name)
   {
    // Do Something
   }
   else
   {
    retval = PERM_DENY;
   }
  }
  else
  {
   retval = BAD_VALUE;
  }
 }
 else
 {
  retval = BAD_NAME;
 }
    return retval;
}



아직까지는 별차이가 없는것 같습니다.
다음의 개선된 if문은 제외하고, 다음 if문의 틀을 봅시다.
그러면 아래와 같은 코드를 볼 수 있습니다.



public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    int retval = SUCCESS;
    if (!someCondition)
    {
  return retval;
 }
 if (name != null && name != "")
 {
  //상세코드
 }
 else
 {
  retval = BAD_NAME;
 }
    return retval;
}



if~else문으로 구성되어 있는것을 확인할 수 있고,
if문을 early return방식으로 개선하면 (== 조건이 맞지않을때 리턴한다)
아래와 같이 개선이 됩니다.


if(!(name != null && name != ""))
{
 retval = BAD_NAME;
 return retval;
}
//상세코드


여기서 !(name != null && name != "")부분은 분배법칙에 의해,
괄호를 풀어쓴다면 다음과 같이 작성될 수 있습니다.
(name == null || name == "")

이를 적용하고 상세코드를 풀어쓰면 아래와 같은 코드가 됩니다.


public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    int retval = SUCCESS;
    if (!someCondition)
    {
  return retval;
 }
 if (name == null || name == "")
 {
  retval = BAD_NAME;
  return retval;
 }
 if (value != 0)
 {
  if (perms.allow(name)
  {
   // Do Something
  }
  else
  {
   retval = PERM_DENY;
  }
 }
 else
 {
  retval = BAD_VALUE;
 }
    return retval;
}



뭔가 조금씩 개선된게 보이시나요?
마찬가지로 if(value != 0) 에 대해서도 개선을 하면 아래와 같이 될것입니다.


public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    int retval = SUCCESS;
    if (!someCondition)
    {
  return retval;
 }
 if (name == null || name == "")
 {
  retval = BAD_NAME;
  return retval;
 }
 if(value == 0)
 {
  retval = BAD_VALUE;
  return retval;
 }
 if (perms.allow(name))
 {
  // Do Something
 }
 else
 {
  retval = PERM_DENY;
 }
    return retval;
}



마찬가지 방식으로 if(perms.allow(name)) 코드도 개선하면 아래와 같은 꼴이 됩니다.


public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    int retval = SUCCESS;
    if (!someCondition)
    {
  return retval;
 }
 if (name == null || name == "")
 {
  retval = BAD_NAME;
  return retval;
 }
 if(value == 0)
 {
  retval = BAD_VALUE;
  return retval;
 }
 if (!perms.allow(name))
 {
  retval = PERM_DENY;
  return retval;
 }
 // Do Something
 
    return retval;
}


지금도 충분히 간단해 보이지만,
각각의 if문에서 retval = BAD_VALUE를 선언하는 부분은
이 값을 바로 리턴해준다면 딱히 필요가 없는 구문이기에 삭제해도 됩니다.
그러면 최종 꼴은 아래 코드와 같아집니다.



public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    int retval = SUCCESS;
    if (!someCondition)
    {
  return SUCCESS;
 }
 if (name == null || name == "")
 {
  return BAD_NAME;
 }
 if(value == 0)
 {
  return BAD_VALUE;
 }
 if (!perms.allow(name))
 {
  return PERM_DENY;
 }
 // Do Something
 
    return retval;
}


총 23줄의 코드가 되었으며, 가독성이 훨씬 좋아진것을 느낄수 있을 것입니다.
잘 모르시겠으면, 원래 코드를 보겠습니다. 아래와 같았습니다.


public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    int retval = SUCCESS;
    if (someCondition)
    {
        if (name != null && name != "")
        {
            if (value != 0)
            {
                if (perms.allow(name)
                {
                    // Do Something
                }
                else
                {
                    retval = PERM_DENY;
                }
            }
            else
            {
                retval = BAD_VALUE;
            }
        }
        else
        {
            retval = BAD_NAME;
        }
    }
    return retval;
}



중첩된 if구문이 무엇이었는지 생각하지 않아도 되고,
길이도 짧아져서 코드 읽기가 쉬워졌습니다.
코드 읽기가 쉬워졌다는 뜻은 곧 유지보수를 빨리할 수 있는(=개발비용이 적게드는)효과를 낸다고 볼 수 있습니다.



 총평


개발하다보면 나도모르게 if문을 남발하다가 중첩이 되는경우가 있지 않나 싶습니다.
이게 만일 남의 코드이거나 예전에 짰던 내 코드라면 정말 읽기가 싫어질것입니다.
개인적으로는 if문을 사용할때마다 early return을 적용할 수는 있지 않은지 항상 생각을 하고 있습니다.
특히 for문과 if문 등에 있는 block 이 중첩되면 어떻게 더 개선할 수 없을지 노력합니다.
물론 코드리뷰할때도 잘 살펴보는 항목입니다.
간단한 방법으로 코드 가독성을 크게 개선할 수 있기에,
저처럼 if문이 있을때 마다 ealry return으로 개선할 수 없는지 생각하는것을 습관화 하는것을 적극 추천합니다.


#리팩토링,#code,#bad,#smell,#badsmell,#codesmell,#refactor,#refactoring,#early,#return,#earlyreturn,#빠른리턴,#얼리리턴

 

https://devscb.com/post/130

 

code bad smell - refactoring technique using early return

Code bad smell - refactoring technique using early return Reason for introducing early returnNested if statements are usually difficult to read.One way to improve this is called early return. What is

devscb.com

 

728x90
반응형

댓글