Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This seems like an issue caused by registration at a distance. I'm new to go and it is one of the things that felt most wrong.

I'm used to a router where you define a big list of routes all in one place, maybe in some DSL. That's very easy to refactor, and doesn't have any ambiguity. If a library wants a route registered it puts a snippet in the docs for users to copy.

Go in general seems to value clarity over magic at the expense of verbosity, and this is a puzzling exception.



It’s not an exception. There is no magic.

Large code bases are large, and not every program is your simple crud app with a handful of endpoints that can be meaningfully managed a single function.


Hard panic in a "not simple app with large codebase" app because you couldn't match a route is amateur hour.


I think you're assuming that the panic happens when a request is received, but it actually happens when a conflicting route is registered.

To me, that's reasonable behavior and is consistent with other things such as https://pkg.go.dev/regexp#MustCompile


I think you are vastly oversimplifying what has been said or why it works the way that it does. I really recommend you read the design document and reasoning, as it is rather clear why they are doing it the way that they are. If you have a cogent contribution to the discussion, please do share.


Others have already contributed more than enough.

People's willingness to defend any and all of go's dubious decisions is really baffling.


Registering handlers is a startup activity ... Practically the only time I allow a panic in my code. I also have unit tests for the entire startup sequence so theoretically code with ambiguous handlers would never be committed.


Go's flag, log, image, and sql packages all work this way, so it's not just the HTTP router. I sort of see both sides. Having implicit registration makes it very easy to have different teams working on different packages and you just import the package and it registers itself. But it also makes the behavior of the resulting final binary hard to understand and based on implicit code instead of explicit. I personally try to just have one big routes() http.Handler function that returns everything all in one place, but I get why that isn't always practical.


It doesn't feel to me like much of a gain over having said team expose a specific default self registration function. Then that act can be explicit rather than action at a distance on some dependency defined global state.

I think this pattern in the standard library is a mistake.


Yeah, the trade-off is literally:

   import _ "thing"
Vs:

   import "thing"
   thing.Register()
But one uses a strange construct to save a single line, loses the ability to control order, and encourages people to use globals that they can't control.


I very much dislike import side effects in any language. Im a lot happier where thing.Register() is still forced to happen in the main function.

Still, I can understand it for some components like loggers to not add boiler plate to every library. However, I was very uneasy to see that enabling gzip decompression in a gRPC server is done through a magic _ import. You have to initialize the server anyways, so why not just make it an explicit function argument?


thing.Register() may register a route that conflicts with yours and it will never be matched in this case if declaration order was taken into account. You may discover this too late when you either have missed important calls on that thing or when requests intended for that thing are causing unintended effects on your first declared route.


That is all also true when doing the same thing in an init func.


Well, yeah, with the "implicit registration" model you can either split it up or do it in a central place, whereas if they would require you to do it in a central place, you wouldn't have that choice. It probably boils down to "library" vs. "framework" - Go's standard library doesn't want (as much as possible) to be a framework that forces you to do things its way, and as far as I'm concerned that's ok...


How is this new to Go? Almost all Java frameworks that rely on Annotations do registration at a distance. Controllers are Routinely declared on different packages and even injected from dependency libraries.


I agree with most of this post. The one exception in my experience: Vertx. I never saw any annotations for routing. It is a very verbose library, but that means there is no black magic.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: