5 ms·
> If you use ctx.Value in my (non-existent) company, you’re fired This is such a bad take. ctx.Value is incredibly useful for passing around context of api ca
by kalekold 2y ago
> If you use ctx.Value in my (non-existent) company, you’re fired
This is such a bad take.
ctx.Value is incredibly useful for passing around context of api calls. We use it a lot, especially for logging such context values as locales, ids, client info, etc. We then use these context values when calling other services as headers so they gain the context around the original call too. Loggers in all services pluck out values from the context automatically when a log entry is created. It's a fantastic system and serves us well. e.g.
log.WithContext(ctx).Errorf("....", err)
- b1-88er 2y agoMaybe he doesn't have a company because he is too dogmatic about things that don't really matter.
- PUSH_AX 2y ago100% People who have takes like this have likely never zoomed out enough to understand how their software delivery ultimately affects the business. And if you haven't stopped to think about that you might have a bad time when it's your business.
- daviddever23box 2y agoBingo. Everything that can be wrongly used or abused started out its existence within sane constraints and use patterns.
- pm90 2y agoSomeone has to question the status quo. If we just did the same things there would be a lot less progress. The author took the time to articulate their argument, and publish it. I appreciate their effort even if I may not agree with their argument.
- frankie_t 2y agoThe author gave a pretty good reasoning why is it a bad idea, in the same section. However, for the demonstration purposes I think the they should have included their vision on how the request scoped data should be passed. As I understand they propose to pass the data explicitly, like a struct with fields for all possible request-scoped data. I personally don't like context for value passing either, as it is easy to abuse in a way that it becomes part of the API: the callee is expecting something from the caller but there is no static check that makes sure it happens. Something like passing an argument in a dictionary instead of using parameters. However, for "optional" data whose presence is not required for the behavior of the call, it should be fine. That sort of discipline has to be enforced on the human level, unfortunately.
- rubenv 2y ago> As I understand they propose to pass the data explicitly, like a struct with fields for all possible request-scoped data. So basically context.Context, except it can't propagate through third party libraries?
- frankie_t 2y agoIf you use a type like `map[string]any` then yes, it's going to be the same as Context. However, you can make a struct with fields of exactly the types you want. It won't propagate to the third-party libraries, yes. But then again, why don't they just provide an explicit way of passing values instead of hiding them in the context?
- skywhopper 2y agoPrecisely because you need to be able to pass it through third party libraries and into callbacks on the other side where you need to recover the values.
- lawrjone 2y agoYeah most people talking here are unlikely to have worked on large scale Go apps. Managing a god-level context struct with all the fields that ever could be relevant and explaining what they mean in position independent ways for documentation is just not scalable at all. Import cycles mean you’re forced into this if you want to share between all your packages, and it gets really hairy.
- eadmund 2y ago> why don't they just provide an explicit way of passing values instead of hiding them in the context? Hiding them in a context is the explicit way of passing values through oblivious third-party libraries. In some future version of Go, it would be nice to just have dynamic scoping. But this works now, and it’s a good pattern. The only real issue is the function-colouring one, and that’s solvable by simply requiring that every exported function take a context.
- sluongng 2y agoLet me try to take the other side: `ctx.Value` is an `any -> any` kv store that does not come with any documentation, type checking for which key and value should be available. It's quick and dirty, but in a large code base, it can be quite tricky to check if you are passing too many values down the chain, or too little, and handle the failure cases. What if you just use a custom struct with all the fields you may need to be defined inside? Then at least all the field types are properly defined and documented. You can also use multiple custom "context" structs in different call paths, or even compose them if there are overlapping fields.
- smarkov 2y ago> `ctx.Value` is an `any -> any` kv store that does not come with any documentation, type checking for which key and value should be available. On a similar note, this is also why I highly dislike struct tags. They're string magic that should be used sparingly, yet we've integrated them into data parsing, validation, type definitions and who knows what else just to avoid a bit of verbosity.
- homebrewer 2y agoMost popular languages support annotations of one type or another, they let you do all that in a type safe way. It's Go that's decided to be different for difference sake, and produced a complete mess.
- saghm 2y agoIMO Go is full of stuff like this where they do something different than most similar languages for questionable gains. `iota` instead of enums, implicit interfaces, full strings in imports (not talking about URLS here but them having string literal syntax), capitalization as visibility control come to mind immediately, and I'm sure there are others I'm forgetting. Not all of these are actively harmful, but for a language that touts "simplicity" as one of its core values, I've always found it odd how many different wheels Go felt the need to reinvent without any obvious benefit over the existing ones.
- elAhmo 2y agoWe effectively use this approach in most of our go services. Other than logging purposes, we sometimes use it to pass stuff that is not critical but highly useful to have, like some request and response bodies from HTTP calls, tenant information and similar info.