본문 바로가기
백엔드 개발/백엔드 일기

#006. 백엔드 성장일기: 안티패턴 return await

by iamjoy 2022. 4. 19.

챙겨보는 연사 중 조용민 작가님이 있다. 해주신 말 중 요즘 글을 쓰며 자주 생각나는 부분이 "이불킥을 하세요"이다.

매일 하는 루틴이 있냐는 질문에, "자기 전에 이불킥을 한 날은 그만큼 부끄러운 일을 한 것이다. 헛소리를 했거나, 바보같은 이야기를 했거나, 점수를 잃을 일을 했거나 하는 건데. 이불 킥을 한다는 건 성장하는 날이었다는 뜻이다. 자꾸 부딛히고 실수해야 성장을 하기 때문이다."라고 말하신다. 

 

최근에 코드리뷰를 받고 동료 개발자 분들께 질문을 많이 하다보니 부끄러운 일들이 정말 많다. 그런데 그런 감정이 드는 만큼 마음에 남고 다시 그 코드를 볼 때 이전에는 안보이던 게 보이는 경험을 하면서 성장했다는 기분을 느꼈다. 그래서 저 말씀이 기억났던 것 같다. 

 

https://youtu.be/Nvt6RvE6BTQ?t=1895 


최근에 리뷰 받은 내용 중에 이런 것이 있었다.

async func(){
	return await {DB에서 뭔가를 retreieve하는 함수}
}

결론부터 말하자면 이 코드 중 return await 부분이 잘못되었다.

왜냐하면 async 함수는 Promise 객체를 리턴하기 때문이다.

 

Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타낸다. (출처) 쉽게 말하자면, 어떤 작업이 끝나기를 기다리지 않고 "나중에 어떻게 되겠지"하고 넘어가는 것이다. 함수의 결과 어떤 값을 리턴 받기는 해야하는데 그 값을 바로 알 수 없으니 나중에 어떤 시점에는 알게되겠지 하고 약속(Promise) 하는 것이다.

 

그래서 Promise 객체는 다음 세 가지의 상태를 가진다.

성공하면(fulfilled) settled되었다고 하고 .then으로 처리하고, 실패하면(rejected) .catch로 처리한다.

( settled라는 단어를 잘 기억해두면 이후에 Promise 객체가 가지는 매서드 (Promise.allSettled)를 사용하기에 좋을 것 같다. )

  • 대기(pending): 이행하지도, 거부하지도 않은 초기 상태.
  • 이행(fulfilled): 연산이 성공적으로 완료됨.
  • 거부(rejected): 연산이 실패함.

만약에 이 Promise 객체에 무엇이 들었는 지 확인 후에 진행하고 싶다면 이미 많이 알려진 대로 async-await을 통해 Promise의 결과를 확인할 때 까지 기다리면(await)된다.

 

다시 위의 코드로 돌아가보면 async 함수를 정의하고 있는데, async 함수는 암시적으로 Promise를 사용하여 결과를 반환한다. 그런데 이 코드에서는 결과를 return 하는 것이 목적이지, Promise의 결과를 기다려야하는 이유가 없다. 따라서 return await을 할 필요 없이, return + 결과를 해주면 Promise 객체가 리턴이 되고 그 결과를 확인하고 싶은 곳에서 await을 해서 열어주면 된다. 따라서 다음과 같은 코드로 바꾸면 된다.

 

async func(){
	return {DB에서 뭔가를 retreieve하는 함수}
}

 

위의 내용을 코드로 확인해보면 다음과 같다.

async를 붙인 함수가 리턴하는 결과를 찍어보면 다음과 같이 Promise.resolve()로 래핑 되어서 리턴되는 것을 확인할 수 있다.