Earlier quoted context omitted.
I aware of making an interface for that. I advocate that. What I see people on r/golang saying, and even in HN, is to just pass the DB connection either explicitly or in the context. I hate this. It makes things bound to DBs.
Some people say this, but when they do, other more senior people quickly interject and say it's a bad idea.
REST Servers in Go: Part 1 – standard library
121–130 of 149 posts
Re: REST Servers in Go: Part 1 – standard library
#122Earlier quoted context omitted.
What makes something a "real" DI framework? Wouldn't go.uber.org/fx qualify?
I use "real" in quotes to indicate I am meaning something other than the general meaning of the word "real". What I mean by this is a specific type of DI that I view as effective and a type of meta-programming. Such a DI system does more than just auto-instantiate objects. It also provides a DSL that allows for configuration and ordering of the object instantiation during different phases of system execution. fx does…
Re: REST Servers in Go: Part 1 – standard library
#123Earlier quoted context omitted.
I've never understood the value proposition of a DI framework. Why would I want one when I can initialize my objects in main()? Is XML or JSON or whatever really that much more pleasant than wiring together Go objects?
You can initialize your object with main. But if you are reusing some implementation in multiple object you will start to repeat yourself a lot in the initialization. A DI framework allows you to set conventions to avoid repeating yourself in the initialization phase. (ie if a class requires a parameter 'foo', look for a class named 'FooImpl').
Re: REST Servers in Go: Part 1 – standard library
#124Earlier quoted context omitted.
I aware of making an interface for that. I advocate that. What I see people on r/golang saying, and even in HN, is to just pass the DB connection either explicitly or in the context. I hate this. It makes things bound to DBs.
A "DB connection" in Go is already several layers of abstraction. You could have real production connected to your postgres, integration tests connected to a sqlite file, and unit / functional tests via sqlmock. Everything is still 'bound to DBs' but that's because your program needs a source of data . Faking a second data source other than the DB via a higher-level shared interface is just inviting integration failu…
Re: REST Servers in Go: Part 1 – standard library
#125Earlier quoted context omitted.
A "DB connection" in Go is already several layers of abstraction. You could have real production connected to your postgres, integration tests connected to a sqlite file, and unit / functional tests via sqlmock. Everything is still 'bound to DBs' but that's because your program needs a source of data . Faking a second data source other than the DB via a higher-level shared interface is just inviting integration failu…
Would you have the DB connection be a prominent required parameter of all your functions? Would you have the bulk of your code be integration tests then?
> Would you have the bulk of your code be integration tests then?
I'm not sure if you mean the bulk of my code or just of my tests - for a REST API I would expect mostly functional tests. Do e.g. PUT+GET and make sure the result makes sense. This would be the case regardless of DB architecture.
Re: REST Servers in Go: Part 1 – standard library
#126Earlier quoted context omitted.
Interfaces absolutely express a type of polymorphism: any concrete type that satisfies the interface can be used in its place. What makes you think otherwise? > Essentially, what I am claiming is the Golang is a bad language for metaprogramming That's definitely true, and an explicit choice. Thank goodness!
There is no "either-or" data type in Golang. That's why. It can only be accomplished by inefficient functional hackery. In C, you just make a struct, have a type present in the struct, and then cast the struct pointer to extended object types to gain additional functionality. In this way you can easily accomplish all sorts of fun things like inheritance. Message passing type designs can easily be accomplished also in…
Re: REST Servers in Go: Part 1 – standard library
#127Earlier quoted context omitted.
Interfaces absolutely express a type of polymorphism: any concrete type that satisfies the interface can be used in its place. What makes you think otherwise? > Essentially, what I am claiming is the Golang is a bad language for metaprogramming That's definitely true, and an explicit choice. Thank goodness!
There is no "either-or" data type in Golang. That's why. It can only be accomplished by inefficient functional hackery. In C, you just make a struct, have a type present in the struct, and then cast the struct pointer to extended object types to gain additional functionality. In this way you can easily accomplish all sorts of fun things like inheritance. Message passing type designs can easily be accomplished also in…
It's 30 years too late to complain about three unrelated approaches to dynamic dispatch having the same name.
Re: REST Servers in Go: Part 1 – standard library
#128Earlier quoted context omitted.
I don't think it's the worst thing in the world if you test your http.Handler implementation: w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/foo", nil) ServeHTTP(w, req) if got, want := w.Code, http.StatusOK; got != want { t.Errorf("get /foo: status:\n got: %v\n want: %v", got, want) } if got, want := w.Body.String(), "it worked"; got != want { t.Errorf("get /foo: body:\n got: %v\n want: %v", got, wa…
I don't think it's poor to test http handling either, as a coarse grained integration test. The problem I've seen is over-dependence on writing unit tests with mocks instead of biting the bullet and properly testing all the boundaries. I have seen folk end up with 1000+ tests, of which most are useless because the mocks make far too many assumptions, but are necessary because of the layer coupling. This was mostly in…
Sorry to spring a mostly-unrelated question on you about this, but why do you call this an integration test? I recently interviewed three candidates in a row that described their tests in this way, and I thought it was odd, and now I see many people in this thread doing it also.
I would call this a functional or behavioral test. For me a key aspect of an integration test is that there's something "real" on at least two "sides" - otherwise what is it testing integration with? Is this some side-effect of a generation growing up with Spring's integration testing framework being used for all black-box testing?
(I will not comment about how often I see people referring to all test doubles as "mocks", as I have largely given up trying to bring clarity here...)
Re: REST Servers in Go: Part 1 – standard library
#129I would probably go with gRPC + grpc-gateway[1] instead. Declaring your services and models in proto files, annotating your services with google.api.http to help grpc-gateway scaffold your HTTP base. Then just implement your services from the interface generated by grpc-go. You can even register your gRPC services to grpc-gateway without actually bringing up a gRPC server. You finally end up having your exact data mo…
It feels like an ugly hack that grpc-gateway sits on top of gRPC to support HTTP/1 when gRPC could have been written to support HTTP/1 and HTTP/2 from the beginning. Roughly, gRPC ~= protobuf (serialization & schema enforcement) + HTTP/2 + non-standard HTTP/2 (trailers, etc), and it is hard to believe that just as they standardized the non-standard bits, they couldn't have found a way to work over HTTP/1 (or HTTP/1.1…
[0]: https://rsocket.io/
Re: REST Servers in Go: Part 1 – standard library
#130Earlier quoted context omitted.
Some people say this, but when they do, other more senior people quickly interject and say it's a bad idea.
I agree. I’ve seen more prominent figures argue against global state often. Using global state is certainly not idiomatic Go.
Unfortunately it's not this simple (and probably multi-idiomatic).
Go definitely adopts more global state than other languages; I don't know any other language that offers a default-global HTTP client and server. Now, part of that is because Go's stdlib goes out of its way to make these appear stateless even though they are not - and this is good, even if you (often rightly) don't use the default ones.
But I think a lot of people saw those carefully engineered APIs and instead ran with "globals are OK in Go!" Lots of packages have global-level configuration properties - some of this is a hacky replacement for DI e.g. most logger injection. Well, OK, I can support/tolerate some of that because DI in these cases is usually a hacky replacement for real AOP language support. But some of it just shouldn't be global. e.g. Gin debug vs. release vs. test mode should be a setting on the Engine.
And then you get into really bad stuff - I don't know why but it is common to to have a global sql.DB, or sarama.AsyncProducer, or whatnot. A lot of novice Go developers - anecodotally predominately skewed towards previous PHP users, I think because they are not used to have really global variables - use a global for anything concurrency-safe. And this has ended up in a lot of low-quality tutorials/examples/SO questions so I don't see it going away any time soon.