Live data from Hacker News

Spectral Contexts in Go

hypirion.com

31–40 of 41 posts

Re: Spectral Contexts in Go

#31

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!

I felt like you did and I totally get it it. It isn’t what it seems like, though.

It’s actually very pragmatic and once you embrace it, it makes writing and reasoning about Go much easier than you’d expect.

The way you write Go isn’t like most languages I’ve encountered. You write a lot of local variables which typically come from well-named structs and functions, so keeping track of what’s what is extremely low effort. Tracing what something is happens very naturally, and arguably easier because there’s less data to parse.

It’s counter intuitive, but I was extremely resistant to it and now I like it (when writing Go) quite a bit. I don’t do this in other languages I write (like TypeScript or Rust); it’s definitely a Go-ism.

Re: Spectral Contexts in Go

#33

https://blog.khanacademy.org/statically-typed-context-in-go/ i found this to be a good approach for injecting dependencies, especially when the methods implement an interface

Don't create a custom context type. This will make it more difficult to interop with any other library that uses the normal context.Context.[0]

Furthermore, why is that code using string keys for the context? It's recommended in the context package documentation that context keys should always be an unexported type, so that the key can never collide with a different key.[1] It's common to define accessor functions which are type safe

[0] https://google.github.io/styleguide/go/decisions.html#custom...

[1] https://pkg.go.dev/context#WithValue

Re: Spectral Contexts in Go

#34
Maintaining Go Code at scale, I can tell you decisively that using the context as opaque bag for all-the-values is a bad idea in terms of maintainability and code comprehensibility. And I write this agnostic to Go as well; I’d feel exactly the same about using thread local storage for dependency injection purposes.

The advice to use the context as the article proposes is a recipe for a regretted design. I guarantee it. It’s a fun, clever thought experiment but should not be applied to production code.

Re: Spectral Contexts in Go

#35

https://blog.khanacademy.org/statically-typed-context-in-go/ i found this to be a good approach for injecting dependencies, especially when the methods implement an interface

Don't create a custom context type. This will make it more difficult to interop with any other library that uses the normal context.Context.[0] Furthermore, why is that code using string keys for the context? It's recommended in the context package documentation that context keys should always be an unexported type, so that the key can never collide with a different key.[1] It's common to define accessor functions wh…

Agreed, custom context types don’t work for libraries.

But, i am finding them useful in building a pipeline composer similar to https://www.reddit.com/r/RedditEng/comments/z137m3/from_serv...

Re: Spectral Contexts in Go

#36
post #5
post #4

Earlier quoted context omitted.

They are not "goroutine local", they are essentially (at least the way they are used) a request-local variable. Which in itself is useful tool. My only real issue with them is lack of type safety so you have to remember which contest var is what. For example I'd like to have User context variable that is set somewhere early if user is authenticated but now at every subsequent call there needs to be a bit of fluff to…

I think it always a mistake to start a goroutine without passing a context to it, since you are no longer able to cancel the goroutine unless you build your own mechanism to do so. Given that, I think you can handwave it a bit and regard context variables as goroutine local.

Passing some state into it from outside makes it the opposite of "local".

Re: Spectral Contexts in Go

#37
post #5
post #4

Earlier quoted context omitted.

They are not "goroutine local", they are essentially (at least the way they are used) a request-local variable. Which in itself is useful tool. My only real issue with them is lack of type safety so you have to remember which contest var is what. For example I'd like to have User context variable that is set somewhere early if user is authenticated but now at every subsequent call there needs to be a bit of fluff to…

I think it always a mistake to start a goroutine without passing a context to it, since you are no longer able to cancel the goroutine unless you build your own mechanism to do so. Given that, I think you can handwave it a bit and regard context variables as goroutine local.

>I think it always a mistake to start a goroutine without passing a context to it, since you are no longer able to cancel the goroutine unless you build your own mechanism to do so

Not really a problem. If you pass a channel you can close the channel. And cancel isn't magical, still need to handle it from within a goroutine and adding a timeout isn't any more or less complex than handling context cancellation

> Given that, I think you can handwave it a bit and regard context variables as goroutine local.

That's extremely wrong way to handle it, especially if it is in a bigger app. There is nothing stopping from changing the values in it in other goroutines for example, and one of designed uses of ctx is scatter-gather pattern of spawning multiple parallel tasks that need to be done to respond to request, and other is using ctx to pass data between middlewares (as is often used in web frameworks in Go at least). So you have to at least take care about variable naming across the project and parallel access to them might happen so you need to take care about not running 2 goroutines wanting to write into same variable.

Re: Spectral Contexts in Go

#38
post #27

Earlier quoted context omitted.

When people mention type safety in this context, they are talking about compiler guarantees. Application code that uses type assertions will never be "type safe" in the way that a compiler can ensure. So while you're correct that if the application code that does the type checking is bug free then the type safety is implied, but is not certain in all cases.

Sure but the interface is typesafe and usually that’s good enough. The two methods of the API (NewContext and FromContext) are typesafe from the perspective of the user.

We're talking about context variables which are of type any so you need to check them runtime.

Re: Spectral Contexts in Go

#39

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!

There's a convention to prefer short (1-3 characters) abbreviated identifiers for trivial things. For example, a loop variable:

    i := 0
But a more complex thing might get a fuller name:

    producer := NewProducer()
In the earlier case with the HTTP handlers, "r" and "w" are conventions. They appear so often that it's counterproductive to give them full names. People who read the code would be confused.

Before Go, I did a lot of Java and Ruby, and felt like you did, and went against the conventions. But the code I wrote back when I started with Go now looks foreign to me.

Post reply on HN