# 13년 후 Go로 HTTP 서비스를 작성하는 방법

> Clean Markdown view of GeekNews topic #13288. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=13288](https://news.hada.io/topic?id=13288)
- GeekNews Markdown: [https://news.hada.io/topic/13288.md](https://news.hada.io/topic/13288.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2024-02-10T09:57:02+09:00
- Updated: 2024-02-10T09:57:02+09:00
- Original source: [grafana.com](https://grafana.com/blog/2024/02/09/how-i-write-http-services-in-go-after-13-years/)
- Points: 2
- Comments: 1

## Topic Body

### GrafanaCON 2024: 오늘 등록하고 자리를 예약하세요!

- GrafanaCON 2024는 올해 최대 커뮤니티 이벤트로, 등록이 공식적으로 시작됨.
- 이 행사는 4월에 암스테르담에서 직접 참여할 수 있는 생생한 경험을 제공함.

#### GN⁺의 의견
- GrafanaCON 2024는 데이터 시각화와 모니터링에 관심 있는 사람들에게 중요한 이벤트임. 이 행사는 Grafana 사용자 및 개발자 커뮤니티가 모여 최신 트렌드와 기술을 공유하는 장이 될 것임.
- 암스테르담에서 진행되는 이번 행사는 참가자들에게 네트워킹과 학습의 기회를 제공하며, 데이터 분석 및 시각화 툴에 대한 심도 있는 이해를 돕는 세션들이 마련될 것으로 기대됨.
- 이벤트의 등록 개시는 Grafana 사용자들에게 흥미로운 소식이며, 이 분야에 종사하는 전문가들에게는 새로운 지식을 습득하고 업계 동료들과 교류할 수 있는 좋은 기회가 될 것임.

## Comments



### Comment 22976

- Author: neo
- Created: 2024-02-10T09:57:02+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=39318867) 
- > _The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value._

  - **유효성 검사 방법**: 선택적인 컨텍스트를 받아 문제가 있는 필드를 키로 하고 문제 설명을 값으로 하는 맵을 반환함. 이 방식은 과거에 유용했음을 언급함.
  
- > I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," I've found validators to be much more error-prone than leveraging Go's built-in type checker.

  - **유효성 검사 대신 파싱**: Lexi Lambda의 "Parse, Don't Validate"를 읽은 후, Go의 내장 타입 검사기를 활용하는 것이 유효성 검사보다 오류 가능성이 낮다고 느낌.

- > For example, imagine you wanted to defend against the user picking an illegal username. Like you want to make sure the user can't ever specify a username with angle brackets in it.

  - **사용자 이름 유효성 검사 예시**: 사용자가 꺾쇠 괄호가 포함된 불법적인 사용자 이름을 선택하지 못하도록 방어하는 상황을 상상함.

- > With the Validator approach, you have to remember to call the validator on 100% of code paths where the username value comes from an untrusted source.

  - **유효성 검사기 접근법의 문제점**: 불신할 수 있는 출처에서 온 사용자 이름 값에 대해 모든 코드 경로에서 유효성 검사기를 호출해야 하는 부담이 있음.

- > Instead of using a validator, you can do this:

  - **유효성 검사 대안 제시**: 유효성 검사기를 사용하는 대신, 다른 방법을 제안함.

- > That guarantees that you can never forget to validate the username through any codepath. If you have a Username object, you know that it was validated because there was no other way to create the object.

  - **객체 생성을 통한 유효성 보장**: Username 객체를 생성하는 과정에서 유효성 검사가 이루어지므로, 어떤 코드 경로를 통해서도 유효성 검사를 잊을 수 없게 됨.

- > I really like Mat Ryer's work, and I've applied most of the ideas in the 2018 version of this article to all of my Go projects since then.

  - **Mat Ryer의 작업 선호**: Mat Ryer의 작업을 매우 좋아하며, 2018년 버전의 기사에 나온 대부분의 아이디어를 자신의 Go 프로젝트에 적용함.

- > The one weak spot for me is this aspect:

  - **약점 지적**: 문제가 되는 부분에 대해 언급함.

- > This has always felt wrong to me, but I've never been able to figure out a better solution.

  - **문제에 대한 해결책 부재**: 잘못된 것 같지만, 더 나은 해결책을 찾지 못함을 표현함.

- > It means that a huge chunk of your code has a huge amount of unnecessary shared state.

  - **공유 상태의 문제**: 코드의 큰 부분이 불필요한 공유 상태를 가지고 있음을 지적함.

- > I often end up writing HTTP handlers that only need access to a tiny amount of the shared state.

  - **HTTP 핸들러와 공유 상태**: HTTP 핸들러가 매우 적은 양의 공유 상태에만 접근해야 하는 경우가 많음을 언급함.

- > Nothing against Mat Ryer, as his pattern is the best I've found, but I still feel like there's some better solution out there.

  - **Mat Ryer의 패턴에 대한 존중**: Mat Ryer의 패턴이 지금까지 찾은 것 중 최고라고 하면서도, 여전히 더 나은 해결책이 있을 것 같다는 느낌을 표현함.

- > one of my biggest pet peeves is when people take a Config object, which represents the configuration of an entire system, and pass it around mutably.

  - **Config 객체 사용에 대한 불만**: 전체 시스템의 설정을 나타내는 Config 객체를 변경 가능하게 전달하는 것에 대한 큰 불만을 표현함.

- > When you do that, you're coupling everything together through the config object.

  - **Config 객체를 통한 결합 문제**: Config 객체를 통해 모든 것을 결합시키는 문제점을 지적함.

- > I've worked on systems where you had to configure the parts in a specific order in order for things to work, because someone decided to write back to the config object when it was passed to them.

  - **Config 객체의 순서 의존성 문제**: Config 객체를 전달받은 사람이 그것에 다시 쓰기를 결정함으로써, 부품을 특정 순서로 구성해야만 시스템이 작동하는 경우에 대해 경험을 공유함.

- > Or another case was where I've seen it such that you couldn't disable a portion of the system because it wrote data into the config object that was read by some other subsystem later.

  - **Config 객체와 시스템 부분의 비활성화 문제**: Config 객체에 데이터를 쓰고, 그것이 나중에 다른 하위 시스템에 의해 읽혀져서 시스템의 일부를 비활성화할 수 없는 경우를 목격함.

- > The pattern of "your configuration is one big value, which is mutable" is one of the more annoying patterns that I've seen before, both in Go and in other languages.

  - **변경 가능한 단일 대형 설정 패턴에 대한 비판**: Go와 다른 언어 모두에서 본 "설정이 하나의 크고 변경 가능한 값"이라는 패턴에 대해 불편함을 표현함.

- > I agree with a lot of this, I'll add my own opinions:

  - **의견 동의 및 추가**: 많은 부분에 동의하며 자신의 의견을 추가함.

- > I would pass a waitgroup with the app context to service structs.

  - **Waitgroup과 앱 컨텍스트 전달 제안**: 서비스 구조체에 앱 컨텍스트와 함께 waitgroup을 전달하는 것을 제안함.

- > This way the interrupt can trigger the app shutdown via the context and the main goroutine can wait on the waitgroup before actually killing the app.

  - **앱 종료를 위한 인터럽트와 waitgroup 활용**: 인터럽트가 컨텍스트를 통해 앱 종료를 트리거할 수 있고, 메인 고루틴이 앱을 실제로 종료하기 전에 waitgroup에서 대기할 수 있음을 설명함.

- > If writing a CLI program, then testing stdout, stdin, stderr, args, env, etc. is useful.

  - **CLI 프로그램 테스트의 유용성**: CLI 프로그램을 작성할 때 stdout, stdin, stderr, args, env 등을 테스트하는 것이 유용함을 언급함.

- > But for an http server, this is less true.

  - **HTTP 서버에 대한 다른 접근**: HTTP 서버의 경우 위의 테스트가 덜 유용함을 지적함.

- > I would pass structured config to the run function to let those tests be more focused.

  - **구조화된 설정 전달을 통한 테스트 집중**: 더 집중된 테스트를 위해 구조화된 설정을 run 함수에 전달할 것을 제안함.

- > I disagree with parsing templates using sync.Once in a handler because I don't think handlers should do template parsing at all.

  - **핸들러에서의 템플릿 파싱에 대한 반대**: 핸들러가 템플릿 파싱을 전혀 하지 않아야 한다고 생각하기 때문에 sync.Once를 사용한 템플릿 파싱에 동의하지 않음.

- > I would do this when the app starts: if the template cannot be parsed, the app should not become ready to receive any requests and should rather exit with a non-zero exit code.

  - **앱 시작 시 템플릿 파싱 제안**: 앱이 시작될 때 템플릿 파싱을 수행하고, 파싱할 수 없다면 앱이 요청을 받을 준비가 되지 않아야 하며, 0이 아닌 종료 코드로 종료해야 함을 제안함.

- > I found fx to be a super simple yet versatile tool to design my application around.

  - **fx 도구의 간단함과 다재다능함**: fx를 매우 간단하면서도 다재다능한 도구로 찾아 애플리케이션 설계에 활용함.

- > All the advice in the article is still helpful, but it takes the "how do I make sure X is initialized when Y needs it" part completely out of the equation and reduces it from an N*M problem to an N problem.

  - **기사의 조언과 fx의 이점**: 기사의 모든 조언이 여전히 도움이 되지만, fx는 "Y가 필요할 때 X가 초기화되었는지 어떻게 확실히 할 것인가"라는 문제를 완전히 제거하고 N*M 문제를 N 문제로 줄임.

- > I've used quite a few dependency injection libraries in various languages over the years (and implemented a couple myself) and the simplicity and versatility of fx makes it my favorite so far.

  - **fx의 선호도**: 여러 언어에서 다양한 의존성 주입 라이브러리를 사용해왔고 몇 가지를 직접 구현하기도 했지만, fx의 단순성과 다재다능함이 지금까지 가장 좋음.

- > I've recently been playing with ogen:

  - **ogen 사용 경험**: 최근에 ogen을 사용해봄.

- > Write openapi definition, it'll do routing, definition of structs, validation of JSON schemas, etc.

  - **openapi 정의와 ogen의 기능**: openapi 정의를 작성하면 ogen이 라우팅, 구조체 정의, JSON 스키마 유효성 검사 등을 수행함.

- > All I need to do is implement the service.

  - **서비스 구현의 단순화**: 서비스를 구현하는 것만 필요함을 언급함.

- > Validating an integer range for a querystring parameter is just too boring. And too easy to mistype when writing it manually.

  - **쿼리스트링 파라미터의 정수 범위 유효성 검사의 단점**: 쿼리스트링 파라미터에 대한 정수 범위 유효성 검사가 지루하고, 수동으로 작성할 때 오타가 나기 쉬움을 지적함.

- > Anyways, so far only been playing, so haven't found the bad parts yet.

  - **ogen에 대한 초기 평가**: 아직까지는 ogen을 실험적으로 사용하고 있으며, 나쁜 점을 발견하지 못함.

- > Great article with lots of interesting ideas. Can't believe I didn't know about signal.NotifyContext. Finally I'll be able to actually rememeber how to respond to signals instead of copy-pasting that between projects.

  - **기사와 signal.NotifyContext에 대한 긍정적 평가**: 많은 흥미로운 아이디어가 담긴 훌륭한 기사라고 평가하며, signal.NotifyContext에 대해 알지 못했던 것에 놀라움을 표현함. 프로젝트 간에 복사-붙여넣기를 하지 않고 신호에 어떻게 반응해야 하는지 기억할 수 있게 됨.

- > I like a lot of what they've done here. My testing looks a bit different however.

  - **기사의 접근 방식에 대한 호감과 테스트 방식의 차이**: 기사에서 한 많은 것들을 좋아하지만, 자신의 테스트 방식은 조금 다름을 언급함.

- > srv, err := newTestServer()

  - **테스트 서버 생성 코드 예시**: 새로운 테스트 서버를 생성하는 코드 예시를 제시함.

- > require.NoError(t, err)

  - **에러 검사 코드 예시**: 에러가 없는지 검사하는 코드 예시를 제시함.

- > defer srv.Close()

  - **서버 종료 코드 예시**: 테스트가 끝난 후 서버를 닫는 코드 예시를 제시함.

- > resp, err := http.Post(fmt.Sprintf("http://localhost:%d/signup/json", srv.Port()), "application/json", strings.NewReader(`
 { "email": "test@example.com", "password": "p@55Word", "password_copy": "p@55Word" }
 `))

  - **HTTP POST 요청 코드 예시**: HTTP POST 요청을 보내는 코드 예시를 제시함.

- > In my newTestServer, I spin up a server with fakes for my dependencies.

  - **의존성을 위한 가짜 서버 생성**: 의존성을 위한 가짜 서버를 생성하는 방식을 사용함.

- > If I want to test a dependency error, I replace that property with a fake that will return an error.

  - **의존성 에러 테스트 방법**: 의존성 에러를 테스트하고 싶을 때, 에러를 반환할 가짜로 해당 속성을 교체함.

- > I can validate my error paths. I can validate my log entries. I can validate my metric emission. I can validate timeouts and graceful shutdowns.

  - **다양한 검증 가능성**: 에러 경로, 로그 항목, 메트릭 발생, 타임아웃, 그리고 우아한 종료 등을 검증할 수 있음.

- > After the server starts, I inspect to determine which port it is running on (default is :0 so I have to wait to see what it got bound to).

  - **서버 시작 후 포트 검사**: 서버가 시작된 후 어떤 포트에서 실행되고 있는지 검사함 (기본값은 :0이므로 어떤 포트에 바인딩되었는지 확인하기 위해 대기해야 함).

- > My "unit" tests can test at the handler level or the http level, making sure that I can fully test the code as the users of my system will see it, exercising all middleware or none.

  - **단위 테스트의 범위**: "단위" 테스트는 핸들러 수준이나 HTTP 수준에서 수행할 수 있으며, 시스템 사용자가 보게 될 코드를 완전히 테스트할 수 있도록 모든 미들웨어를 사용하거나 사용하지 않음.

- > I can spin up N instances and run my tests in parallel.

  - **병렬 테스트 실행**: N개의 인스턴스를 생성하고 테스트를 병렬로 실행할 수 있음.

- > I don't write go, but I like these patterns. Feels fairly universal for testable code.

  - **Go 작성 경험 부재와 패턴 선호**: Go를 작성하지 않지만, 이러한 패턴을 좋아하며, 테스트 가능한
