[WHY 시리즈 1] E.008 — 서비스 추상화, Mongoose, Webhook

Mijeong (Rachel)
6 min readApr 25, 2019

--

‘코드와 서비스 만들기를 좋아하는 소프트웨어 엔지니어’로 일하고 있다. 엔지니어는 문제를 해결하는 사람이다. 문제를 해결하는 과정에는 여러 가지 선택이 존재할 수 있다. 가능한 최선의 결과를 위해, 항상 내 선택의 Why에 답할 수 있는 사람이 되고자 한다. 매주, 한 주 동안 내가 결정한 선택의 Why에 대해 정리하고자 한다.

베트남에서 프로덕트를 만든 지 벌써 4개월이라는 시간이 흘렀다. 동시에 프로덕트 오픈 일자가 정말 코앞으로 다가왔다. 실제로 다양한 종류의 테스트 기간을 거치면서 예상하지 못했던 상황들 그리고 오류들을 개선해 나가고, 프로덕트 오픈 준비를 병행하며 참 정신없는 시간을 보내고 있다. 그사이에 또 다시 나는 면 수습을 겪고, 면 수습 회고 글도 작성하며 WHY 시리즈 글을 한동안 작성할 시간이 부족했다고 핑계를 대어본다. 어쨌거나 다시 WHY 시리즈 글을 쓰며 키보드를 두드리고 있는 지금, 업무 노트를 뒤적이며 그동안 쌓아두었던 주제에 대해 역시나 Why를 던져본다.

Note: 우아한 형제들, 베트남 프로덕트 팀 3개월 회고

Why?

1. 서비스 추상화

상점 목록을 검색해서 반환하는 엔드포인트가 있다. 테스트를 진행하면서 해당 ‘엔드포인트를 사용하는 주체’에 따라 ‘상점 목록을 검색하는 필터의 조건이 달라지도록 개선’할 필요가 있었다. 사용하는 주체는 엔드포인트를 호출하는 Session의 role을 이용하여 식별할 수 있는 상황이었다. 처음에는 서비스 레이어에 존재하는 search 함수에서 role을 매개변수로 전달받고, 특정 role의 경우 필터의 조건을 변경하는 방향으로 구현을 시도했다. 하지만, 다른 방향으로 role이 아닌 flag를 매개변수로 전달받는 것으로 구현을 완성했다.

  • Why? search 함수의 역할과 책임은 상점 목록을 검색하는 일이다. role을 식별하는 것은 상점 서비스 레이어에 존재하는 search 함수의 역할을 벗어나는 일이라고 판단했다. 오히려 서비스 레이어 전, 컨트롤러 레이어에서 혹은 search 함수를 호출하기 전 단계에서 수행되어야 하는 로직이라고 판단했다.
  • Why? 특정 값(role)을 매개변수로 전달받는 것 보다, flag를 매개변수로 전달받는 것이 더 적절한 추상화라고 판단했다. role 자체를 매개변수로 전달받았을 때에는 해당 필터 조건을 오직 Session의 role에 따라서만 적용할 수 있었다. 하지만, flag를 사용한다면 추후에 role이 아닌 다른 종류의 값에도 얼마든지 기존 search 함수의 변경 없이 적용 가능하다고 판단했다.
항상 주옥같은 리드의 피드백

2. Mongoose toObject vs toJson

기능이 추가되면 자연스럽게 필요한 모델이 추가된다. 우리는 도큐먼트 기반 MongoDB와 이를 위한 ODM(Object Data Mapping)인 Mongoose를 사용하고 있다. 최근, 필요한 모델을 추가하면서 자연스럽게 Schema에 toObject와 toJson을 정의하고 있는 나를 발견했다. 그러다 문득, Mongoose model을 작성하면서 왜 toObject와 toJson을 모두 정의해야 하는지 의문이 들었다. Mongoose의 코드를 살펴보면 toObject와 toJson 모두 결국 같은 함수($toObject)를 호출하는데?

  • Why? toOjectMongoose Document 유형의 객체를 자바스크립트의 Object 유형으로 변환할 때 사용된다. 주로 비즈니스 로직을 구현할 때 MongoDB에서 조회한 결과를 자바스크립트의 Object 유형으로 변환하기 위해 사용된다. 이때 속성의 추가/수정/삭제 작업이 필요하다면 toObject의 transform 함수를 정의하여 사용하고 있다.
  • Why? toJsonMongoose Document 유형이 JSON.stringify()를 통해 변환될 때 사용된다. 즉, Mongoose Schema 모델에 toJson이 정의되어 있으면 해당 모델 객체에 대한 JSON.stringify() 호출 시 toJson에 정의된 내용을 이용하여 변환된다. 주로 express의 res.json()을 통해 MongoDB에서 조회한 결과를 응답으로 반환할 때, 내부적으로 JSON.stringify()가 호출되어 사용되고 있다.
Mongoose Document의 toObject 정의
Mongoose Document의 toJSON 정의

Note: toJSON() behavior 참고

Note: Documentation: clarify the difference between toObject() and toJSON() 이슈 참고

3. Webhook validation 제거

이전 글에서도 몇 번 언급했던 것처럼 현재 우리 프로덕트는 다양한 3rd party 서비스를 이용하고 있다. 우리가 직접 3rd party의 API 호출하여 로직을 구현하는 경우가 대부분이지만 필요에 따라 3rd party에서 전달하는 Webhook을 통해 동기화를 할 필요가 있다. 최근, 쿠폰 서비스를 제공하는 3rd party의 Webhook을 받아 처리하는 로직의 오류 로그를 발견했다. 기존에는 오류 없이 잘 사용되던 부분이었고, 코드 상의 다른 변경은 없었기 때문에 갑작스런 오류 로그에 당황했다. 결국, 3rd party에서 전달하는 Webhook 매개변수 중 반드시 필요한 속성이 아닌 경우, 검증하는 로직을 제거하기로 결정했다.

  • Why? 3rd party Webhook의 인터페이스가 사전 공지 없이 변경되었다. 기존에 문제없이 실행되던 Webhook에서 갑작스런 오류가 발생했던 이유는 Webhook에서 전달하는 매개변수 구조가 변경되었기 때문이었다. 변경 내역에 대한 공지를 내가 놓친것은 아닌지 다시 확인해 보았지만, 사전 공지 없이 기존과 다른 Webhook 매개변수 구조가 전달되었던 것이다. 3rd party 서비스는 100% 우리의 제어 아래에 있을 수는 없다. 즉, 또 다시 이런일이 발생하지 않으리라는 보장이 없었다. 약속된 인터페이스를 강하게 검증할 것인가 혹은 서비스가 유지되는 것에 더 초점을 맞출것인가에서 우리는 후자의 우선순위가 높다고 판단했다.
  • Why? 앞서 언급한 것 처럼, 이와 같은 문제는 언제든지 발생할 수 있다. 우리에게 중요한 것은, 해당 Webhook이 전달하는 매개변수 중 우리에게 반드시 필요한 매개변수만 식별하는 일이었다.
우리 팀 화났음.png

다음 주는 또 이번 주보다 더 정신없고 바쁘겠지만, 힘든 와중에도 프로덕트 오픈이 이렇게 기다려지는 건 참 오랜만인 것 같다. 문제가 발생하지 않을 수는 없지만, 문제가 생기면 또 어때. 참 좋은 동료들과 잘 해결해나갈 수 있는 자신감이 있다. 이제 WHY 시리즈 글 밀리지 말자 다짐.

--

--

No responses yet