본문 바로가기
Coding

Context-less Go — 쉽게 HTTP 서비스 작성하는 방법

by Emily Blunt 2022. 4. 14.
반응형

Context-less Go — 쉽게 HTTP 서비스 작성하는 방법

 

컨텍스트를 IoC로 사용하지 않고 HTTP 서비스 작성을 좋아하는 방법

많은 Go 개발자, 특히 새로운 개발자가 명확하지 않다고 생각하는 것 중 하나는 다음과 같습니다. 내가 필요한 모든 것을 핸들러에 전달하는 방법은 무엇입니까?

Java 또는 C#과 같은 멋진 Inversion of Control 시스템이 없습니다. http.Handlers 정적 서명이므로 내가 정말로 원하는 것을 전달할 수 없습니다. 3가지 옵션만 있는 것 같습니다.

  • use globals
  • wrap handlers in a function
  • 또는 물건을 전달 context.Context!

이 세 가지 옵션을 모두 살펴보겠습니다.

말장난 확실히 의도

우리가 작성하는 핸들러는 일상적인 일반 전자 상거래 상점에서 볼 수 있는 것입니다.

우리의 임무는 특정 카테고리 ID가 주어지면 해당 카테고리의 항목 목록을 반환하는 끝점을 작성하는 것입니다.

이 끝점은 우리의 items.Service실제 조회를 수행하려면 logging.Service 일이 잘못될 경우, 그리고 metrics.Service 그들에게 달콤한 마케팅 지표를 얻기 위해!

— 전화 미스터 월드와이드

핸들러에 물건을 가져오기 위한 첫 번째 시도는 전역입니다. 이것은 많은 초보자들이 하는 경향이 있는 상당히 자연스러운 방법입니다.

우리 모두는 한 번쯤은 이와 같은 코드를 작성해 본 적이 있습니다. 그런 다음 우리 모두 전역은 유연하지 않고 테스트할 수 없는 코드를 만들기 때문에 나쁘다는 것을 빠르게 배웠습니다.

이것은 자연스럽게 "당신의 의존성을 주입하십시오!"라고 말하는 책, 기사, 비디오 등의 토끼 구멍으로 이어집니다. 이 코드는 작동하지 않습니다. 약간의 주입을 시도해 보겠습니다.

— 부스터 얻기

글쎄, 우리는 전역을 사용하고 싶지 않지만 http.Handler 고정 서명이 있습니다. 어떻게 해야 할까요? 당연히 포장해 드립니다!

이것은 더 나은 우리는 더 이상 글로벌 상태에 의존하지 않기 때문에 여전히 원하는 것이 많이 남아 있습니다. 주로, 그것은 모든 핸들러를 작성하기에 크고 길고 성가신 혼란으로 만듭니다. 몇 가지 서비스를 더 추가하면 이 서명이 2~3배 더 길어질 것이라고 상상하기 쉽습니다.

그래서 우리는 주변을 읽고 우리의 *http.Request 가지고있다 context.Context 그 안에! 미들웨어를 만들고 모든 종속성을 주입하면 핸들러가 필요한 것만 가져올 수 있습니다! 이것은 분명히 우리의 모든 문제를 해결할 것입니다!

이제 컬러로!

먼저, 우리가 이야기했던 미들웨어를 만들어 봅시다. 우리는 모든 의존성을 설정한 후에 이것을 인라인으로 할 것입니다.

이제 모든 것이 추가되었으므로 핸들러를 다시 한 번 실행할 수 있습니다.

멋지고 쉽습니다! 여기에는 아무 것도 잘못될 수 없습니다. 글쎄, 3개월 후 누군가가 코드 줄을 앱의 다른 곳으로 옮기고 이러한 서비스 중 하나가 컨텍스트에 더 이상 존재하지 않는 경우를 제외하고.

“글쎄요, 스마트 미디엄 작가님, 제가 확인해 보겠습니다!” 당신은 말할 수 있습니다.

작고 단순하며 인위적인 예에서도 볼 수 있듯이 안전한 방식으로 이 작업을 수행하는 것은 약간 엉망이 됩니다.

Go를 사용하는 이유 중 하나는 이러한 모든 유형의 검사 혼란을 피하기 위함입니다! 컨텍스트를 의존성을 위한 일종의 잡기 가방으로 사용함으로써 우리는 효과적으로 안전을 포기합니다. 또한 런타임까지 사물이 존재하는지 알 수 없습니다. 이 문제를 해결하기 위해 우리는 모든 곳에서 긴 오류 검사 문자열로 끝납니다.

이것은 좋지 않다. 우리의 세 가지 옵션은 모두 각자의 방식으로 빨려들어갑니다. 의존성을 주입하고 싶다면 장황한 지옥에서 벗어날 수 없는 것 같습니다. 물론 이러한 문제를 해결하고 이것의 많은 부분을 감싸는 멋진 기능을 만들 수 있지만 실제로 문제를 해결하는 것은 아닙니다.

네번째 방법이 없다면....?

핸들러에 구조 추가 중…

여러분 중 일부는 이미 이 문제를 해결하기 위해 저에게 소리를 지르셨을지 모르지만 이 주제를 몇 번 잘 가르쳤으면 다른 솔루션을 먼저 보는 것이 정말 도움이 됩니다.

우리가 고려하지 않은 "네 번째 방법"은 실제로 매우 간단합니다.

  1. 필요한 종속성을 보유하는 구조체를 만듭니다.
  2. 해당 구조체의 메서드로 핸들러를 추가합니다.

예제를 살펴보겠습니다.

이 솔루션에는 다음과 같은 몇 가지 큰 이점이 있습니다.

  1. 우리가 의존하는 모든 것은 빌드 시간에 알려지며 유형이 안전합니다(컨텍스트와 달리)
  2. 래퍼 함수와 달리 최소한의 추가 상용구가 있습니다.
  3. 테스트 가능성 유지(글로벌과 달리)
  4. 관련 핸들러를 단위로 "그룹화"할 수 있습니다.

4는 아직 다루지 않았지만 이제 이 구조체가 있으므로 공통 종속성을 공유하거나 논리적으로 함께 가는 처리기 그룹을 만들 수 있습니다.

예를 들어 여기에 새 카테고리를 추가하기 위해 핸들러를 추가할 수 있습니다. 우리는 만들 수 있습니다 MetricsHandler 메트릭과 관련된 모든 엔드포인트를 함께 그룹화합니다. 원하는 만큼 세분화하거나 광범위하게 사용할 수 있습니다(세분화된, 아마도 대부분의 경우 더 좋습니다.).

누가 여기까지 읽었습니까?

드디어 목표가 생겼습니다. 완전히 고안된 전자 상거래 상점의 우리 상사는 끝점이 준비되어 기뻐할 것입니다(일부 테스트 제외). 다음 작업으로 넘어갈 수 있습니다.

이것은 새롭거나 새로운 아이디어가 아닙니다. https://pace.dev/blog/2018/05/09/how-I-write-http-services-after-eight-years.html 및 https://pace.dev/blog/2018/05/09/how-I-write-http-services-after-eight-years.html과 같은 고전적인 go 예제 게시물을 보면 /github.com/benbjohnson/wtf/ 이러한 아이디어가 실제로 실행되는 것을 볼 수 있습니다.

그것은 훌륭하고 분명하지 않은 해결책이라고 생각합니다.

물론 인터페이스 등을 사용하여 이것을 훨씬 더 테스트하기 쉽게 만들 수 있지만 그건 또 다른 기사입니다!

반응형

댓글