Live data from Hacker News

Spectral Contexts in Go

hypirion.com

11–20 of 41 posts

Re: Spectral Contexts in Go

#11
We use strongly typed contexts for:

- Request-scoped parameters like user ID, request ID, etc.

- Dependency injection (database connection and other IO)

- Cancellation

It works great. The one hairy part is when you need to change the context, for example when logging in you take an anonymous context and end up with a logged-in context. We use linters to ensure that stuff is right, but it still takes some thought in the edge cases.

Still, I think those issues are exposing problems in our codebase rather than problems with typed contexts.

Re: Spectral Contexts in Go

#12
post #9
post #2

I'm not a big fan of context variables: they're basically a super clunky kind of goroutine-local global variable, with all the problems you might get with these kinds of mutable global variables. I would argue that if you're having to pass dependencies down, you should be explicitly dependency injecting them instead rather than implicitly via context.

How would you do that with standalone functions? You'll need at least one parameter for cancelation, and one parameter for the logging context, and perhaps one more parameter for tracing. Even passing the single context variable increases clutter a lot.

[deleted]

Re: Spectral Contexts in Go

#13
There's no need to put any dependencies in the context, ever. For HTTP servers, the easiest way is just to use a struct to hold the dependencies:

    type Server struct {
      logger *Logger
      users *UserService
      // etc.
    }
Assuming we use a router like Chi or similar:

    router.Get("/users", srv.HandleUsers)
...where HandleUsers is a method on Server.

Some people like to spread handlers in different packages. You can of course declare handlers as functions with no receiver struct, and pass the data as an argument:

    router.Get("/users", func(w io.ResponseWriter, r *http.Request) {
      userroutes.HandleUsers(srv, w, r)
    })
For middlewares, e.g. something that parses a session cookie and fetches the current user, do exactly the same thing.

Re: Spectral Contexts in Go

#14
post #11

We use strongly typed contexts for: - Request-scoped parameters like user ID, request ID, etc. - Dependency injection (database connection and other IO) - Cancellation It works great. The one hairy part is when you need to change the context, for example when logging in you take an anonymous context and end up with a logged-in context. We use linters to ensure that stuff is right, but it still takes some thought in t…

Why do you use it for dependency injection? Why can you not pass those parameters directly when instantiating your service?

Re: Spectral Contexts in Go

#15
post #2

I'm not a big fan of context variables: they're basically a super clunky kind of goroutine-local global variable, with all the problems you might get with these kinds of mutable global variables. I would argue that if you're having to pass dependencies down, you should be explicitly dependency injecting them instead rather than implicitly via context.

[deleted]

Re: Spectral Contexts in Go

#16

There's no need to put any dependencies in the context, ever. For HTTP servers, the easiest way is just to use a struct to hold the dependencies: type Server struct { logger *Logger users *UserService // etc. } Assuming we use a router like Chi or similar: router.Get("/users", srv.HandleUsers) ...where HandleUsers is a method on Server. Some people like to spread handlers in different packages. You can of course decl…

Exactly this. Your dependencies are not request scoped, so there is no reason for them to be included in a per-request context. Instead, dependencies should be passed in to and stored in the struct that uses them.

The data you store in the context should be specific to the current request. Think: request ID, user ID, auth info, etc.

Re: Spectral Contexts in Go

#17
post #11

We use strongly typed contexts for: - Request-scoped parameters like user ID, request ID, etc. - Dependency injection (database connection and other IO) - Cancellation It works great. The one hairy part is when you need to change the context, for example when logging in you take an anonymous context and end up with a logged-in context. We use linters to ensure that stuff is right, but it still takes some thought in t…

Do you use a single context key with a struct or iota keys for each value?

Re: Spectral Contexts in Go

#18
I tend to put the logger in the context as it becomes request-scoped when you bind the request ID to it in middleware. Zerolog has a useful method to get the logger from the context, which is really handy.

Re: Spectral Contexts in Go

#19

There's no need to put any dependencies in the context, ever. For HTTP servers, the easiest way is just to use a struct to hold the dependencies: type Server struct { logger *Logger users *UserService // etc. } Assuming we use a router like Chi or similar: router.Get("/users", srv.HandleUsers) ...where HandleUsers is a method on Server. Some people like to spread handlers in different packages. You can of course decl…

are one-character variables common in Go? every time that i think "maybe i should pick up Go," and then i see the syntax... it gives me pause. seems really ugly!

Re: Spectral Contexts in Go

#20

There's no need to put any dependencies in the context, ever. For HTTP servers, the easiest way is just to use a struct to hold the dependencies: type Server struct { logger *Logger users *UserService // etc. } Assuming we use a router like Chi or similar: router.Get("/users", srv.HandleUsers) ...where HandleUsers is a method on Server. Some people like to spread handlers in different packages. You can of course decl…

are one-character variables common in Go? every time that i think "maybe i should pick up Go," and then i see the syntax... it gives me pause. seems really ugly!

Yes but every time I've seen it, it's in a small scope, it's very obvious the type of the variable and what it's doing. It's really not as bad as it seems once you spend some time in go.
Post reply on HN