How to design an interface returning another interface type which could only be fulfilled emergent - go

Short premise:
I try to design a package which holds several types fullfilling the same set of interfaces and another package working with these interfaces. Now I'm puzzled how to fulfill an interface returning another interface type.
longer:
To be more specific: I've got two protocol / message types (broadcast / direct) which I want to be able to package to be transported by http/json and amqp/rabbit. My "transport"-packages (json and amqp) require my message-packages (dm/broadcast) to fulfill / present some information: e.g. GetAddress or NewResponse. For NewResponse my message format generates, out of it's metainformation,a ResponseMessage. My transporter knows how to translate GetAddress to a useful routing information. There is my interface problem: Now I'm puzzled how to fulfill an interface returning another interface type.
type Addresser interface {
GetRecipientAddress() string
}
type Responder interface {
NewResponse() (Responder, error)
}
type DM struct {
}
func (dm *DM) GetRecipientAddress() string {
return ""
}
func (dm *DM) NewResponse() (*DM, error) {
return dm, nil
}
As long as my (dm *DM) NewResponse returns Responder the Responder interface is fulfilled. When I return *DM, which fulfills Responder, *DM doesn't fulfill Responder.
I kind of see that this seems to be an chicken or the egg problem, as long as I return *DM, *DM doesn't fulfill Responder, but "de facto" it fulfills it.
That leeds my to my assumption: I try to implement a bad design for the use of interfaces. Can somebody point me in the direction golang-gurus would solve this problem?
I thought maybe this could be a solution, but it seems to be just as flawed
type AddressResponder interface {
Addresser
Responder
}
func (dm *DM) NewResponse() (AddressResponder, error) {
return dm, nil
}

See Type identity:
Two interface types are identical if they have the same set of methods with the same names and identical function types. Non-exported method names from different packages are always different. The order of the methods is irrelevant.
Two function types are identical if they have the same number of parameters and result values, corresponding parameter and result types are identical, and either both functions are variadic or neither is. Parameter and result names are not required to match.
Try this:
// NewResponse returns (Responder, error)
func (dm *DM) NewResponse() (Responder, error) {
return dm, nil
}

type DM can only fill Responder if and only if it has the methods described in Responder. I understand what you are saying, but this is how Golang works!
In other words, DM must have the method of signature NewResponse() (Responder, error) or else it does NOT implement Responder.
Thus perhaps you must change the definition to:
type DM struct {
}
func (dm *DM) NewResponse() (Responder, error) {
return dm, nil
}

Related

How do I improve the testability of go library methods

I'm writing some code that uses a library called Vault. In this library we have a Client. My code makes use of this Client but I want to be able to easily test the code that uses it. I use only a couple methods from the library so I ended up creating an interface:
type VaultClient interface {
Logical() *api.Logical
SetToken(v string)
NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
}
Now if my code is pointed at this interface everything is easily testable.. Except let's look at the Logical() method. It returns a struct here. My issue is that this Logical struct also has methods on it that allow you to Read, Write, ex:
func (c *Logical) Read(path string) (*Secret, error) {
return c.ReadWithData(path, nil)
}
and these are being used in my project as well to do something like:
{{ VaultClient defined above }}.Logical().Write("something", something)
Here is the issue. The Logical returned from the call to .Logical() has a .Write and .Read method that I can't reach to mock. I don't want all the logic within those methods to run in my tests.
Ideally I'd like to be able to do something similar to what I did above and create an interface for Logical as well. I'm relatively new to Golang, but I'm struggling with the best approach here. From what I can tell that's not possible. Embedding doesn't work like inheritance so it seems like I have to return a Logical. That leaves my code unable to be tested as simply as I would like because all the logic within a Logical's methods can't be mocked.
I'm sort of at a loss here. I have scoured Google for an answer to this but nobody ever talks about this scenario. They only go as far as I went with the initial interface for the client.
Is this a common scenario? Other libraries I've used don't return structs like Logical. Instead they typically just return a bland struct that holds data and has no methods.
package usecasevaultclient
// usecase.go
type VaultClient interface {
Logical() *api.Logical
SetToken(v string)
NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
}
type vaultClient struct {
repo RepoVaultClient
}
// create new injection
func NewVaultClient(repo RepoVaultClient) VaultClient {
return &vaultClient{repo}
}
func(u *vaultClient) Logical() *api.Logical {
// do your logic and call the repo of
u.repo.ReadData()
u.repo.WriteData()
}
func(u *vaultClient) SetToken(v string) {}
func(u *vaultClient) NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
// interfaces.go
type RepoVaultClient interface {
ReadData() error
WriteData() error
}
// repo_vaultclient_mock.go
import "github.com/stretchr/testify/mock"
type MockRepoVaultClient struct {
mock.Mock
}
func (m *MockRepoVaultClient) ReadData() error {
args := m.Called()
return args.Error(0)
}
func (m *MockRepoVaultClient) WriteData() error {
args := m.Called()
return args.Error(0)
}
// vaultClient_test.go
func TestLogicalShouldBeSuccess(t *testing.T) {
mockRepoVaultClient = &MockRepoVaultClient{}
useCase := NewVaultClient(mockRepoVaultClient)
mockRepoVaultClient.On("ReadData").Return(nil)
mockRepoVaultClient.On("WriteData").Return(nil)
// your logics gonna make this response as actual what u implemented
response := useCase.Logical()
assert.Equal(t, expected, response)
}
if you want to test the interface of Logical you need to mock the ReadData and WriteData , with testify/mock so u can defined the respond of return of those methods and you can compare it after you called the new injection of your interface

Difference in a function implementation when instantiating an object with different function signatures

Came across the following differences a function implementations. What is the reasoning behind Example 1 returning a pointer and Example 2 returning an actual object?
type MyInterface interface {
Func (param int) float64 //just random signature
}
//MyInterfaceImpl implements MyInterface
type MyInterfaceImpl struct {
}
//actual implementation
func (myObj *MyInterfaceImpl) Func(param int) float64 {
return float64(param)
}
Example 1: the pointer to the MyInterfaceImpl is returned when function returns an interface
func NewMyInterface() MyInterface {
return &MyInterfaceImpl{}
}
Example 2: actual object of MyInterfaceImpl is returned when function returns the object
func NewMyInterfaceImpl() MyInterfaceImpl {
return MyInterfaceImpl{}
}
UPDATE: This piece of code compiles and runs
func main() {
myIf := NewMyInterface()
fmt.Printf("Hi from inteface %f\n", myIf.Func(1000))
myImpl := NewMyInterfaceImpl()
fmt.Printf("Hi from impl %f\n", myImpl.Func(100))
}
UPDATE2: Question clarification.
This sounds weird (for me) to have a declaration of func NewMyInterface() MyInterface and a valid implementation of return &MyInterfaceImpl{} where a pointer is returned. I would expect to return an object of MyInterfaceImpl with return MyInterfaceImpl{}
If the language allows such types of constructs, there must be a reason for that. Eventually, I am looking for a following answer: "The function declaration returns an interface. Because the interface has a property X it is does not make sense to return an object, but the only valid option is a pointer".
Even though I'm not sure which part of the code the question is about, let me explain what the code does:
MyInterface is implemented by anything having a Func(int)float64 method.
*MyInterfaceImpl has such a method. However, MyInterfaceImpl does not (the method has a pointer receiver).
NewMyInterface() thus has to return a pointer. MyInterfaceImpl{} wouldn't implement MyInterface.
Does this answer your question?
Another question might be why the call myImpl.Func(100) works, despite the above. This is because Go automatically takes the address of the receiver when calling its methods with pointer receivers.
This is explained in more detail for example here.

Implementing interface type to function type in Golang

I have created few types including interface as:
// GetProfileHandlerFunc turns a function with the right signature into a get profile handler
type GetProfileHandlerFunc func(GetProfileParams, interface{}) middleware.Responder
// Handle executing the request and returning a response
func (fn GetProfileHandlerFunc) Handle(params GetProfileParams, principal interface{}) middleware.Responder {
return fn(params, principal)
}
// GetProfileHandler interface for that can handle valid get profile params
type GetProfileHandler interface {
Handle(GetProfileParams, interface{}) middleware.Responder
}
Now in my api implementation package. I am using a logic to handle the request parameters. I am trying to assign GetProfileHandlerFunc to another type since it implements GetProfileHandler interface as you can see above.
api.ProfileGetProfileHandler = profile.GetProfileHandlerFunc(func(params profile.GetProfileParams, principal *models.User) middleware.Responder {
// contains logic to handle the request
}
Now I think I can do above logic. But I am getting type mismatch error.
cannot convert func literal (type func(profile.GetProfileParams,
*"userproj/models".User)
middleware.Responder) to type profile.GetProfileHandlerFuncgo
the point is:
if you have a function like
func A(param interface{}) {}
you can pass anything to param when you make a call to function A. like
A(10)
A(true)
A(nil)
Because interface{} means everything. So your handle func definition:
type GetProfileHandlerFunc func(GetProfileParams, interface{}) middleware.Responder
means a function GetProfileHandlerFunc which takes two params, the first is of type GetProfileParams, the second is of type interface{}. That means second param canbe anything.
But
func(params profile.GetProfileParams, principal *models.User) middleware.Responder
means a function which takes two params, the first is of type GetProfileParams, the second is of type *models.User. So, do you think they are the same? No.
I need a function can take anything as second param,not a function who can only take User as second function.
When you call your handle
GetProfileHandlerFunc(params, 10) // this is ok
So is that ok for
func(params profile.GetProfileParams, principal *models.User) middleware.Responder
No.
The right way to do this is :
api.ProfileGetProfileHandler = profile.GetProfileHandlerFunc(func(params profile.GetProfileParams, principal interface) middleware.Responder {
user:=principal.(*model.User) // watch this.
}

Composition combining data and functions with interfaces and structs

I'm wondering if this is something that's done in Go or if I'm thinking about it all wrong: composing type x interface and type x struct so my interface methods have access to specific data too:
The C programmer in my wants to do this:
type PluginHandler interface {
onLoad()
pm *PluginManager
}
func (ph PluginHandler) onLoad() {
pm.DoSomething()
}
There I have an interface defined with a function, but also some data I want to pass to those functions but this is a syntax error.
So is this something that's doable in Go through some other method or am I just thinking about the problem wrong?
You have defined onLoad incorrectly. You cannot define a function directly on interface type.
Once you have an interface, you need another type to implement methods specified in the interface. For example, if another type implements onLoad method, they automatically (implicitly) implement the interface PluginHandler.
The other thing you need to do is change the interface function type to accept the required data:
type PluginHandler interface {
onLoad(*PluginManager)
}
struct SomeType {
// ...
}
func (s SomeType) onLoad(pm *PluginManager) { // SomeType now implements
pm.DoSomething() // PluginHandler interface.
}
This way, you get to inject whichever PluginManager required by PluginHandler.
Also, you can use SomeType as a PluginHandler type whereever required.
func someFuntion(ph PluginHandler) {
// ...
ph.onLoad(pm)
// ...
}
Can be called with an input argument of type SomeType:
s := SomeType{}
someFunction(s)
TL;DR; There is no direct translation to Go.
Long answer:
Go interfaces are only methods.
Go structs are only data (with the possibility of receiver methods).
You can reference, and even embed interfaces within structs:
type Frobnicator interface {
Frobnicate() error
}
type Widget struct {
Frobnicator
WidgetName string
}
But that's not really what you're talking about.
The best answer to your dilema is, I believe: Take a step back. You're focusing on the trees, and you need to look at the forest. Go takes a different approach than C, or classical OO languages like C++ and Java.
Look at the general problem to be solved, and find solutions to that in Go. This can be a painful process (I can say from experience), but it's really the only way to learn the new way of thinking.
Just for the record, you can add extra methods to an existing type, by introducing another (indirection) type as:
type HandlerManager PluginManager
func (x *HandlerManager) onLoad() {
((*PluginManager)(x)).DoSomething()
}
And if you need to go with a more generic solution, a combination of Adapter & Strategy patterns could do:
type PluginHandlerAdapter struct{ _onLoad func() }
func (x *PluginHandlerAdapter) onLoad() {
x._onLoad()
}
Used like (public/private access ignored):
type PluginManager struct {
PluginHandlerAdapter
}
func NewPluginManager() *PluginManager {
res := new(PluginManager)
res._onLoad = res.DoSomething
return res
}

How pass different structures to function?

I have several different structures.
Here show two:
type AdsResponse struct {
Body struct {
Docs []struct {
ID int `json:"ID"`
// others
} `json:"docs"`
} `json:"response"`
Header `json:"responseHeader"`
}
type OtherResponse struct {
Body struct {
Docs []struct {
ID int `json:"ID"`
// others
} `json:"docs"`
} `json:"response"`
Header `json:"responseHeader"`
}
but i don't know how i can do for this method accepts and return both.
func Get(url string, response Response) (Response, bool) {
res, err := goreq.Request{
Uri: url,
}.Do()
// several validations
res.Body.FromJsonTo(&response)
return response, true
}
And use like this:
var struct1 AdsResponse
var struct2 OtherResponse
Get("someURL", struct1)
Get("someURL", struct2)
There are any form?
Your code example is somewhat confusing since both structs appear to be identical. I'll assume that they differ somewhere in "others".
First, I generally recommend creating a wrapper around these kinds of JSON deserializations. Working directly on the JSON structure is fragile. Most of your program should not be aware of the fact that the data comes down in JSON. So for instance, you can wrap this in an Ads struct that contains an AdsResponse, or just copies the pieces it cares about out of it. Doing that will also make some of the below slightly easier to implement and less fragile.
The most common solution is probably to create an interface:
type Response interface {
ID() int
}
You make both Ads and Others conform to Response. Then you can return Response. If necessary, you can type-switch later to figure out which one you have and unload other data.
switch response := response.(type) {
case Ads:
...
case Other:
...
}
I don't quite get why you have the reponse as a parameter and as a return. I think you dont need to return it. You should pass a pointer to the reponse and fill it with the data. Also, I'd return an Error instead of a boolean, but that is another topic.
Anyway, the solution is to use interface{} (empty interface).
You are lucky because the function you are using (FromJsonTo) accepts an empty interface as a parameter, so you can safely change your parameter type to interface{} and just pass it to FromJsonTo. Like this:
func Get(url string, response interface{}) bool {
res, err := goreq.Request{
Uri: url,
}.Do()
// several validations
res.Body.FromJsonTo(response)
return true
}
Warning: I did not compile the code.
Then you would call this function with the url and a pointer to one of the reponse structs like this:
var struct1 AdsResponse
var struct2 OtherResponse
Get("someURL", &struct1)
Get("someURL", &struct2)
The way to achieve this is through Go's interfaces.
Two options:
empty interface
Get(url string, response interface{}) (Response, bool)
This option allows any value to be given to this function.
custom interface
Creating a custom interface will allow you to narrow down the types that can be provided as arguments to your function.
In this case you'll have to create an interface that all your Response structs will need to abide by. Any struct really that abides by that interface will be able to be used as an argument of your function.
Something like this:
type MyResponse interface {
SomeFunction()
}
Then your function signature could look like
Get(url string, response MyResponse) (MyResponse, bool)
As long as AdsResponse and OtherResponse abide by the MyResponse interface, they will be allowed to be used as arguments to the function.
Follow the solution working at Go Playground
Go has no polymorphic or any other OO like behaviour, so, when you try to pass a AdsResponse or OtherResponse struct as an Response (or any interface{}), these values becomes an Response (or other param type specified), and is not possible to Go to infer the real type that originate these interface{} and correctly decode your json to these struct types as expected.
This kind of thing should works perfectly in OO languages, like Java, C# etc. There is no hierarchy generalization/specialization on structs/interfaces in Go.
You would need to do a type assertion in your Rest executor, or a switch case, but it seems that you need a generic REST executor, like a generic lib some thing like that. Would not reasonable create a switch case for each struct in your program. Maybe you have dozens or hundreds of structs soon.
I think that a reasonable solution is the rest client pass a lambda function to do the last step for your, that is just create a correct struct destination type and call json decode.
As i say above, the return type of executeRest() in my example will became an interface{}, but the rest client can securely do the type assertion of returned value after executeRest() call.

Resources