Golang: struct inside an interface? - go

So I have an interface, called UserService inside a package service
I have two simple structs representing the body and response of a HTTP call. I have another struct implementing the UserService interface.
I want to put these structs, call them UserResponse and UserRequest inside the interface so other services can use them to make the HTTP call. Furthermore, the request and response should be available (struct UserReponse, not struct userResponse) so other parts of the code can use them.
I define a function in the interface called GetUser(request UserRequest) UserResponse
However, whenever I reference UserRequest I have to use service.UserRequest and not service.UserService.UserRequest. This is bad because I don't want user-related objects to go into the service namespace. I want each service related data to organized under its own interface, file, etc. Unfortunately, I get an error if I put UserResponse inside the UserService interface. So I put it at the same level as UserService, which is why they are showing up as service.UserResponse. How do I go about accessing UserResponse as service.UserService.UserResponse?

Here is a suggestion to organize your code in more "idiomatic" Go way:
package user
type Request struct {
...
}
type Response struct {
...
}
type Service interface {
GetUser(r Request) Response
}
Outside of user package the code will look like:
s := user.NewService()
var req user.Request
var resp user.Response
resp = s.GetUser(req)
As you can see the code uses much shorter names and still remains very readable.
Package names like service shows that you organize the code in your app by layers instead of by features. I wouldn't recommend it. Here is interesting article about it: http://www.javapractices.com/topic/TopicAction.do?Id=205. It uses Java but the principle applies to any programming language.

Go is not Java; Go is even not C++. You should think of Go as "C with interfaces".
In particular, you cannot do as you want, as you cannot nest struct definitions in interface definitions. Note that you can nest structs inside structs, but you cannot instantiate a nested struct directly.
The closest you can do is to move each logical group of objects to its own package.

Related

Interface management in Go

I know this has been asked in various forms many times before but I just can't seem to implement what I'm learning in the way that I need. Any help is appreciated.
I have a series of exchanges which all implement roughly the same APIs. For example, each of them have a GetBalance endpoint. However, some have one or two unique things which need to be accessed within the functions. For example, exchange1 needs to use a client when calling it's balance API, while exchange2 requires both the client variable as well as a clientFutures variable. This is an important note for later.
My background is normal OOP. Obviously Go is different in many ways, hence I'm getting tripped up here.
My current implementation and thinking is as follows:
In exchanges module
type Balance struct {
asset string
available float64
unavailable float64
total float64
}
type Api interface {
GetBalances() []Balance
}
In Binance module
type BinanceApi struct {
key string
secret string
client *binance.Client
clientFutures *futures.Client
Api exchanges.Api
}
func (v *BinanceApi) GetBalance() []exchanges.Balance {
// Requires v.client and v.clientFutures
return []exchanges.Balance{}
}
In Kraken module
type KrakenApi struct {
key string
secret string
client *binance.Client
Api exchanges.Api
}
func (v *KrakenApi) GetBalance() []exchanges.Balance {
// Requires v.client
return []exchanges.Balance{}
}
In main.go
var exchange *Api
Now my thought was I should be able to call something like exchange.GetBalance() and it would use the GetBalance function from above. I would also need some kind of casting? I'm quite lost here. The exchange could either be Binance or Kraken--that gets decided at runtime. Some other code basically calls a GetExchange function which returns an instance of the required API object (already casted in either BinanceApi/KrakenApi)
I'm aware inheritance and polymorphism don't work like other languages, hence my utter confusion. I'm struggling to know what needs to go where here. Go seems to require loads of annoying code necessary for what other languages do on the fly 😓
using *exchanges.Api is quite weird. You're wanting something that implements a given interface. What the underlying type is (whether it's a pointer or a value receiver) is not important, so use exchanges.Api instead.
There is another issue, though. In golang, interfaces are implicit (sometimes referred to as duck-type interfaces). Generally speaking, this means that the interface is not declared in the package that implements it, but rather in the package that depends on a given interface. Some say that you should be liberal in terms of what values you return, but restrictive in terms of what arguments you accept. What this boils down to in your case, is that you'd have something like an api package, that looks somewhat like this:
package api
func NewKraken(args ...any) *KrakenExchange {
// ...
}
func NewBinance(args ...any) *BinanceExchange {
}
then in your other packages, you'd have something like this:
package kraken // or maybe this could be an exchange package
type API interface {
GetBalances() []types.Balance
}
func NewClient(api API, otherArgs ...T) *KrakenClient {
}
So when someone looks at the code for this Kraken package, they can instantly tell what dependencies are required, and what types it works with. The added benefit is that, should binance or kraken need additional API calls that aren't shared, you can go in and change the specific dependencies/interfaces, without ending up with one massive, centralised interface that is being used all over the place, but each time you only end up using a subset of the interface.
Yet another benefit of this approach is when writing tests. There are tools like gomock and mockgen, which allow you to quickly generate mocks for unit tests simply by doing this:
package foo
//go:generate go run github.com/golang/mock/mockgen -destination mocks/dep_mock.go -package mocks your/module/path/to/foo Dependency
type Dependency interface {
// methods here
}
Then run go generate and it'll create a mock object in your/module/path/to/foo/mocks that implements the desired interface. In your unit tests, import he mocks package, and you can do things like:
ctrl := gomock.NewController(t)
dep := mocks.NewDependencyMock(ctrl)
defer ctrl.Finish()
dep.EXPECT().GetBalances().Times(1).Return(data)
k := kraken.NewClient(dep)
bal := k.Balances()
require.EqualValues(t, bal, data)
TL;DR
The gist of it is:
Interfaces are interfaces, don't use pointers to interfaces
Declare interfaces in the package that depends on them (ie the user), not the implementation (provider) side.
Only declare methods in an interface if you are genuinely using them in a given package. Using a central, overarching interface makes this harder to do.
Having the dependency interface declared along side the user makes for self-documenting code
Unit testing and mocking/stubbing is a lot easier to do, and to automate this way

How to write idiomatic constructor

I'm confused about the constructors in Go. Most constructors I've seen return a struct, but 'Effective Go' suggests that an interface can be returned in some cases, according to the rule of 'Generality'.
I trust 'Effective Go' to provide good ideas, but this doesn't seem to follow the principle of 'accept interfaces, return structs'. I guess that many types implement an interface and nothing more than that, so in that case it would be common to see constructors which return interfaces.
Another related statement is that interfaces should be defined by the consumer, but 'Generality' means that the interface is defined by the producer.
Can someone clarify?
As it has already been mentioned, returning an interface should be considered something exceptional.
Returning errors of type error which is an interface is one of those exception.
Returning an interface that represents an unexported type is the other exception. But why would you have an exported interface that describes an unexported struct instead of just having an exported struct?
The reason is simple, that allows you a higher degree of control on how that struct is constructed.
Compare this two pieces of code:
type MyType struct {
MyField string
}
func NewMyType(value string) MyType {
return MyType{value}
}
func (t MyType) MyMethod() string {
return t.MyField
}
type MyType interface {
MyMethod() string
}
type myType struct {
MyField string
}
func NewMyType(value string) MyType {
return myType{value}
}
func (t myType) MyMethod() string {
return t.MyField
}
In the first case I would be able to do: myVar := MyType{} while in the second case I won't be able to do so, I am forced to use the provided constructor. The first case also allows to modify the field value after creation which is not allowed in the second case. Making the field unexported will solve the second part but not the first.
This example is obviously trivial, but being able to construct invalid structs may have a horrible impact. By having specific constructors you can ensure that the object is in a valid starting state and you will only need to make sure it always stays in a valid state. If you can't ensure that, you may need to check that it is in a valid state at the start of every method.
For example consider a DB request. It needs a DB connection. If the user is able to create a DB request without a DB connection you will have to check that it is valid in every method. If you enforce him to use a constructor you can check at creation time and done.
It depends a bit on your preference and how you view things. Coming from OOP background my take is: there is no point in the constructor if you cannot enforce it. Adding the constructor means - you must supply these values when instantiating this item. If your struct is public, it will be misused and instantiated bypassing the constructor. So it makes sense that the constructor returns the public interface and the struct is private (lowercase). If the struct is public, there is no point in the constructor, because you cannot enforce it. Writing code is a dialogue between writer and reader, making a struct public and having a constructor would tell the reader - here you have the constructor, but you also have a public struct and that would mean that constructor usage is arbitrary. If that is the case, go with that setup
In most cases constructor functions return concrete types (or pointer to a type).
The situations in which returning interfaces might be a good idea is when calling factory functions or builder functions in which underlying concrete type satisfies that interface.
Consider error interface for example, when you call http.NewRequest underlying concentrate error type can be of net.Error, net.DNSError etc. Now try to think how are you going to create an api like this without an error interface if function returns concrete type? Only solution to it I can think of is to create a massive error type for net package and add fields for extra information, but its most probably much harder to maintain, test that kind of error type and not to mention memory bloat.
Whether you choose to return concrete type or an interface is a design choice, some guidelines exists to give solution to common scenarios.

Can I subclass and redefine a method in Golang?

I'm using a Github Client that allows me to call github API methods more easily.
This library allows me to provide my own *http.Client when I initialize it:
httpClient := &http.Client{}
githubClient := github.NewClient(httpClient)
It works fine but now I need something else. I want to customize the Client so that every request (i.e. the Do method) gets a custom header added.
I've read a bit about embedding and this is what I've tried so far:
package trackerapi
import(
"net/http"
)
type MyClient struct{
*http.Client
}
func (my *MyClient)Do(req *http.Request) (*http.Response, error){
req.Header.Set("cache-control","max-stale=3600")
return my.Client.Do(req)
}
But the compiler does not let me use my custom MyClient in place of the default one:
httpClient := &trackerapi.MyClient{}
// ERROR: Cannot use httpClient (type *MyClient) as type
//*http.Client.
githubClient := github.NewClient(httpClient)
I'm a bit of a golang newbie so my question is: Is this the right way to do what I want to and, if not, what's the recommended approach?
Can I subclass ... in Golang?
Short answer: No. Go is not object oriented, therefore it has no classes, therefore subclassing is categorically an impossibility.
Longer answer:
You're on the right track with embedding, but you won't be able to substitute your custom client for anything that expects an *http.Client. This is what Go interfaces are for. But the standard library doesn't use an interface here (it does for some things, where it makes sense).
Another possible approach which may, depending on exact needs, work, is to use a custom transport, rather than a custom client. This does use an interface. You may be able to use a custom RoundTripper that adds the necessary headers, and this you can assign to an *http.Client struct.

Why Go design not to mark as error when assign a variable to whatever interface that has same signature

I'm just start learning Go, most of my background came from Java, Ruby.
I just wonder that, from my example, why Go language designer intentionally design to not specify an interface type when implement an interface. So that if someone accidentally try to assign an object to an interface that match a signature but doesn't intend to implement that interface, that would lead to be a bug and cannot be catch at a compile time.
You can try at this: https://play.golang.org/p/1N0kg7m4eE
package main
import "fmt"
type MathExpression interface {
calculate() float64
}
type AreaCalculator interface {
calculate() float64
}
type Square struct {
width, height float64
}
//This implementation intend to implement AreaCalculator interface
func (s Square) calculate() float64 {
return s.width * s.height
}
func main() {
//Suppose that a developer got this object from
//somewhere without a knowledge that object is a Square struct
mysteryStruct := Square{width: 4, height: 3}
var areaCalculator AreaCalculator = mysteryStruct
fmt.Println("Area of something:", areaCalculator.calculate())
var mathExpression MathExpression = mysteryStruct
fmt.Println("This should not work:", mathExpression.calculate())
}
One advantage of "implicitly satisfied" interfaces (ones where types don't need to explicitly declare that they implement them) is that interfaces can be created after the fact. You can see several types that have a method in common, perhaps in different packages, and decide to write a function that can accept any of them by calling for a new interface that specifies that method.
Also, Go's approach to interfaces lets you write an abstraction of the behavior of a type in an existing package, without modifying the original package. The first example that comes to my mind is the File interface in the net/http package:
type File interface {
io.Closer
io.Reader
io.Seeker
Readdir(count int) ([]os.FileInfo, error)
Stat() (os.FileInfo, error)
}
It represents a file that can by served by an http.FileServer. Normally it is an os.File, but it could be anything that fulfills the interface. For example, I think someone has made an implementation that serves files out of a zip archive.
Since the net/http package is defined in the standard library, it might have been possible to explicitly declare that os.File implements http.File—but it would have made the os package depend on the net/http package. This is a circular dependency, because net/http depends on os.
In an inheritance-based language, someone who was trying to do this would probably just give up on using an interface, and make http.FileServer require that all files be subclasses of os.File. But this would be a pain, because they wouldn't need any of the implementation of an os.File; they would just be inheriting from it to satisfy the type system.
The example in the OP works because of a poorly-chosen method name. It is not at all clear what a Square's calculate method should return. Its area? Its perimeter? Its diagonal? If the method were named CalculateArea, which would be the idiomatic name for the single method in an interface named AreaCalculator, it would not be possible to confuse an AreaCalculator and a MathExpression.
Go uses implicit interfaces, it means that type implements interface if it has all functions required by interface. Note that you don't have to declare in code that type implements interface (as in Java).
Such language design have good and bad consequences:
type can implement interface by accident (this happened in your example). Actually it happens very rarely so IMO it is not a big problem.
without interface declaration in code you don't know which interfaces your type implements. This problem can be solved by using good IDEs.
you can easily create adapters and similar design patterns
you can easily create mocks
more readable code (type declaration is very simple in go)
One benefit of this approach is inversion of dependencies. In typical languages with static type systems, you have source level dependency from implementation to interface. Which means you can't deploy them separately. With implicit interfaces you have no source level dependency and implementation module can be deployed/developed/build without module containing interface. This gives you flexibility usually reserved for dynamic type systems.

Designing Go packages: when I should define methods on types?

Suppose that I have a type type T intand I want to define a logic to operate on this type.
What abstraction should I use and When ?
Defining a method on that type:
func (T t) someLogic() {
// ...
}
Defining a function:
func somelogic(T t) {
// ...
}
Some situations where you tend to use methods:
Mutating the receiver: Things that modify fields of the objects are often methods. It's less surprising to your users that x.Foo will modify X than that Foo(x) will.
Side effects through the receiver: Things are often methods on a type if they have side effects on/through the object in subtler ways, like writing to a network connection that's part of the struct, or writing via pointers or slices or so on in the struct.
Accessing private fields: In theory, anything within the same package can see unexported fields of an object, but more commonly, just the object's constructor and methods do. Having other things look at unexported fields is sort of like having C++ friends.
Necessary to satisfy an interface: Only methods can be part of interfaces, so you may need to make something a method to just satisfy an interface. For example, Peter Bourgon's Go intro defines type openWeatherMap as an empty struct with a method, rather than a function, just to satisfy the same weatherProvider interface as other implementations that aren't empty structs.
Test stubbing: As a special case of the above, sometimes interfaces help stub out objects for testing, so your stub implementations might have to be methods even if they have no state.
Some where you tend to use functions:
Constructors: func NewFoo(...) (*Foo) is a function, not a method. Go has no notion of a constructor, so that's how it has to be.
Running on interfaces or basic types: You can't add methods on interfaces or basic types (unless you use type to make them a new type). So, strings.Split and reflect.DeepEqual must be functions. Also, io.Copy has to be a function because it can't just define a method on Reader or Writer. Note that these don't declare a new type (e.g., strings.MyString) to get around the inability to do methods on basic types.
Moving functionality out of oversized types or packages: Sometimes a single type (think User or Page in some Web apps) accumulates a lot of functionality, and that hurts readability or organization or even causes structural problems (like if it becomes harder to avoid cyclic imports). Making a non-method out of a method that isn't mutating the receiver, accessing unexported fields, etc. might be a refactoring step towards moving its code "up" to a higher layer of the app or "over" to another type/package, or the standalone function is just the most natural long-term place for it. (Hat tip Steve Francia for including an example of this from hugo in a talk about his Go mistakes.)
Convenience "just use the defaults" functions: If your users might want a quick way to use "default" object values without explicitly creating an object, you can expose functions that do that, often with the same name as an object method. For instance, http.ListenAndServe() is a package-level function that makes a trivial http.Server and calls ListenAndServe on it.
Functions for passing behavior around: Sometimes you don't need to define a type and interface just to pass functionality around and a bare function is sufficient, as in http.HandleFunc() or template.Funcs() or for registering go vet checks and so on. Don't force it.
Functions if object-orientation would be forced: Say your main() or init() are cleaner if they call out to some helpers, or you have private functions that don't look at any object fields and never will. Again, don't feel like you have to force OO (à la type Application struct{...}) if, in your situation, you don't gain anything by it.
When in doubt, if something is part of your exported API and there's a natural choice of what type to attach it to, make it a method. However, don't warp your design (pulling concerns into your type or package that could be separate) just so something can be a method. Writers don't WriteJSON; it'd be hard to implement one if they did. Instead you have JSON functionality added to Writers via a function elsewhere, json.NewEncoder(w io.Writer).
If you're still unsure, first write so that the documentation reads clearly, then so that code reads naturally (o.Verb() or o.Attrib()), then go with what feels right without sweating over it too much, because often you can rearrange it later.
Use the method if you are manipulating internal secrets of your object
(T *t) func someLogic() {
t.mu.Lock()
...
}
Use the function if you are using the public interface of the object
func somelogic(T *t) {
t.DoThis()
t.DoThat()
}
if  you want to change T object, use
func (t *T) someLogic() {
// ...
}
if you donn't change T object and would like a origined-object way , use
func (t T) someLogic() {
// ...
}
but remeber that this will generate a temporay object T to call someLogic
if your like the way c language does, use
func somelogic(t T) {
t.DoThis()
t.DoThat()
}
or
func somelogic(t T) {
t.DoThis()
t.DoThat()
}
one more thing , the type is behide the var in golang.

Resources