[WHY 시리즈 1] E.005 — map/filter, 반환 유형, 비동기 호출
한국 출장과 설 연휴로 인해 오랜만에 글을 쓰고 있다. 일은 점점 바빠지고, 동료들은 점점 더 좋아지는 시간을 보내고 있다. 약 2달 동안, 서버 프로젝트에 40개 정도의 Pull Request가 오고 갔으며, 클라이언트 프로젝트는 Pull Request 100개가 넘어가면서 축하 케익을 먹기도 했다. 이번 글에서는, 동료의 Pull Request 리뷰로 수정하게 된 코드에 대해 Why를 던져본다.
Why?
1. map, filter
사용자들이 사용할 수 있는 쿠폰을 위한 개발을 한창 진행 중이다. 쿠폰은 하나를 사용할 수도 있지만, 여러 쿠폰이 사용될 수 있는 구조로 설계되었다. 자연스럽게 코드에는 for 루프와 쿠폰 유형으로 인한 if 문이 빈번하게 사용되었다. 해당 코드가 포함된 Pull Request에서 동료의 피드백을 계기로 for 루프와 if 문을 만나면 map과 filter로 변경하는 시도를 시작했다.
- Why? 코드의 가독성이 향상된다. 개인적으로는 for 루프와 if 문이 포함된 코드를 읽어가다 보면 로직이 자연스럽게 읽히지 않는 경우가 적지 않게 존재했다. 그런 나의 코드를 리뷰하는 동료는 얼마나 피곤했겠는가. map과 filter를 사용하게 되면서 코드가 하고자 하는 로직이 명확하게 읽히기 시작했다. 최소 10줄 이상으로 표현되었던 코드가 아래의 코드처럼 2줄로 표현 가능하며, 그 의도 역시 더욱 명확해지게 되었다.
const getCoupon = code => CouponService.get(code)
Promise.all(codes.map(getCoupon))
- Why? side effect를 제거할 수 있다. for 루프와 if 문을 사용하다 보면 가변적인 상태를 자주 만들게 된다. map과 filter의 사용을 통해 가변 상태로 인한 side effect를 제거할 수 있게 되었다. 아주 단순하게는 var 대신 const만 사용할 수 있는 코드가 되었다.
동료와 미래의 나와 함께 일하기 위해 코드의 가독성을 높이기 위한 시도는 언제나 옳다고 생각한다.
2. 함수 반환 유형
아직 찜찜한 상태로 존재하는 코드가 있다. 역시나 나의 동료는 Pull Request를 리뷰하면서 여러 코멘트를 남겼다. 해당 코멘트에 여러 쓰레드가 남았고, 나는 이 코멘트가 남겨진 함수에 반환 유형을 명시하지 않았다는 것을 발견했다. 즉시, 코드를 수정했다.
- Why? 역시 코드의 가독성을 위함이다. 해당 함수는 특정 값 혹은 undefined를 반환할 수 있도록 구현되었다. undefined가 반환될 수 있는 것도 의도된 작업이긴 하지만, 설계가 매끄럽지 못하여 나온 결과라고 생각한다. 그래서 여전히 찜찜한 상태의 코드이지만, 우선은 이 코드를 보게 될 동료를 위해 그리고 (분명히 의도를 까먹게 될) 미래의 나를 위해 반환 유형을 명시하는 것이 좋다고 판단했다.
사실, 반환 유형을 명시하지 않아도 자연스럽게 코드가 읽힐 수 있도록 구현하는 것이 먼저라고 생각한다. 현재는 현실과 타협하여 반환 유형을 명시하고, 단위 테스트를 작성하는 것으로 마무리한 작업이지만 곧 갖게 될 서버 정비의 시간에 더 우아한 코드가 되어있을 것이다(그래야만 한다).
3. 비동기 호출
3rd party를 이용하는 코드에서 동료는 코멘트를 남겼다. 해당 코드는 await를 통해 3rd party API 호출의 promise를 기다리는 방향으로 작성되어 있었다. 동료와의 논의를 통해 해당 코드의 await 작업을 제거하는 것으로 결정했다.
- Why? 3rd party API 호출 결과에 따른 의존성이 없다. 사용자가 회원가입을 진행할 때, 특정 3rd party 서버에도 사용자 정보 일부를 등록시키는 작업이 필요했다. ‘해당 3rd party API 호출 결과가 성공이 아니라면, 과연 우리 서비스의 회원가입 작업도 rollback 되어야 하는가?’ 에 대한 의사결정이 필요했다. 결론은, 3rd party API 호출 결과와 상관없이 우리 서비스 회원가입은 정상적으로 진행되어야 하며, 다만 3rd party API 호출의 예외 상황에 대해서는 로그를 남기는 것으로 결정했다.
- Why? 3rd party API 호출 결과를 기다리는 일로 인한 시간 지연을 제거할 수 있다. await를 사용하면 당연히 3rd party API 호출의 promise를 기다린 후, 다음 로직을 수행하기 때문에 시간 지연이 발생한다. 하지만, 우리는 위의 이유처럼 3rd party API 호출 결과에 의존성이 존재하지 않으며 굳이 시간 지연을 감수할 필요가 없다.
현재 우리의 서비스는 다양한 3rd party 서비스를 사용 중이다. 이번 일을 계기로, 동료와 함께 사용 중인 3rd party 호출에 대한 의존성과 불필요한 시간 지연에 대해 점검하기로 다짐했다.
Pull Request 100개 달성을 축하하기 위한 케익은 인생 첫 경험이었다. 이렇게나 서로의 피드백을 갈구하는 동료들과 함께 일한다는 사실은 축복이라고 생각한다. 서버 프로젝트의 Pull Request 100개 달성도 매우 기대하는 중이다.