I'm working on a project that would require some level of abstraction on some data and I would like to keep the packages that use the data as independent as possible so I can swap things out in the future.
Here are 2 possible ways that I thought of, one is having a common data interface and have all the places import it. The other is to have each package define its own interfaces and do a type assertion.
Which is the most Go/general way of doing it?
// Importing interface
// src/model
type IData interface {
myint() int
}
// src/dataextractor
import src/model
type DataExtractor struct {
foo() IData
}
// src/service
import src/model
type ServiceDataExtractor interface {
foo() IData
}
type Service struct {
extractor ServiceDataExtractor
}
func (s Service) serve() {
v = s.extractor.foo()
// do stuff with v
}
vs
// type assertion
// src/dataextractor
type DataExtractorData struct{}
func (d DataExtractorData) myint()int {}
type DataExtractor struct {
foo() interface{} {
reutrn DataExtractorData{}
}
}
// src/service
type ServiceData interface {
myint() int
}
type ServiceDataExtractor interface {
foo() interface{}
}
type Service struct {
extractor ServiceDataExtractor
}
func (s Service) serve() {
data := s.extractor.foo()
v, ok := data.(ServiceData)
// do stuff with v
}
Here's the simple rules to keep in mind. An interface type should be declared in the package that wants to receive that interface type. To satisfy an interface, you don't have to import it. All you need to do is declare the methods as are specified by the interface.
When do you use interfaces? Typically, when you have a field, or parameter, that you want to be able to accept multiple data types, and you can do all you need to do with it by calling methods. How do you determine what goes in the interface? You simply ask yourself: "What methods would I need to call on this value to make use of it?"
The only seemingly meaningful method in your example is myint() int, and the only place it seems you intend to use it is in Service.
type Service struct {
extractor interface {
myint() int
}
}
func (s Service) serve() {
s.extractor.myint()
}
Related
I would like to create a library that exports a function that defines its own dependencies without consuming types from an external package (excluding std lib).
The issue is, if my dependency is an interface type with a method that returns a struct, consumers have to use the exact struct declared in the interface.
In situations where I have two or more libraries, each sharing the same interface signature however each package defining its own interface (interface segregation), they conflict when it comes to methods that return struct types.
package mylibrary
type Result struct {
Value string
}
type IFoo interface {
Foo() Result
}
func DoFoo(f IFoo) {
f.Foo()
}
With the above code, anyone implementing this library must use the mylibrary.Result struct exactly to satisfy the IFoo interface.
In the case where I have multiple packages defining the interfaces of their own dependencies, this can become difficult and or impossible
See the following example: https://replit.com/#davidalsh/UsedCarefreeBrain#main.go
// main.go
// Creating an object that satisfies the contract roughly
import (
packagea "main/package-a"
packageb "main/package-b"
)
type Result struct {
Message string
}
type Foo struct {}
// Even though Result is the same shape, this needs to
// return either packagea.Result or packageb.Result
func (*Foo) Foo() Result {
return Result{}
}
func main() {
dep := Foo{}
packagea.DoFoo(dep) // Foo does not implement packagea.IFoo
packageb.DoFoo(dep) // Foo does not implement packageb.IFoo
}
This seems like a strange limitation. Methods on an interface can return types like string, int, []int, etc but not a struct.
Should I be returning an interface with getters/setters from IFoo.Foo, e.g.?
type IResult interface {
Message() string
}
type IFoo interface {
Foo() IResult
}
What if I would like to use a struct as an argument for a function? Should I also only accept an interface of getters?
interface IUserDetails {
FirstName() string
LastName() string
Age() int
}
func SayHello(user IUserDetails) {
fmt.Println("Hello", user.FirstName())
}
Or is there a better way?
Define a type in a third package:
common/common.go
package common
type Result struct {
Message string
}
Use this package in all other packages:
main.go
package main
import (
"main/common"
packagea "main/package-a"
packageb "main/package-b"
)
type Foo struct{}
func (*Foo) Foo() common.Result {
return common.Result{}
}
func main() {
dep := &Foo{}
packagea.DoFoo(dep)
packageb.DoFoo(dep)
}
package-a/packagea.go
package packagea
import "main/common"
type IFoo interface {
Foo() common.Result
}
func DoFoo(f IFoo) {
f.Foo()
}
Run the program on the Go Lang Playground
I would like to retype an existing type but retain its interface inheritance.
so example code:
interface interface1 {
func interfaceFunc1()
}
type basicStruct struct {
param int
}
type retyped1 basicStruct
type retyped2 basicStruct
func (basicStruct) interfaceFunc1() {
// does stuff
}
func getTyped1() retyped1 {
return basicStruct{param:0}
}
func getTyped2() retyped2 {
return basicStruct{param:1}
}
func main() {
type1 := getTyped1()
type2 := getTyped2()
// These lines do not compile
type1.interfaceFunc1()
type2.interfaceFunc1()
}
Due to a code generation library I am using I can't just have it return basic struct it has to return retyped1 and retyped2.
But I also need to use the interface functions.
Is there anyway to use the interface functions without some silly copy and paste of all the interface functions which do the exact same thing except like 1 if statement in a couple hundred lines?
As Burak Serdar pointed, in golang there is 2 different ways to define type:
type retyped1 struct {
basicStruct
}
Which inherits methods of basicStruct, and
type retyped2 basicStruct
Which creates new struct with same fields as basicStruct, but not it's methods.
For your particular situation you could use type aliases, which is actually just another name for type, so you can reuse it's methods with it:
type retyped1 = basicStruct
If you need to define a type based on an existing struct preserving its interface, use embedding:
type basicStruct struct {
param int
}
type derivedStruct1 struct {
basicStruct
}
type derivedType2 basicStruct
Above derivedStruct1 has the same methods as basicStruct and satisfies the same interfaces, but derivedType2 does not have any methods.
I have a question regarding dependency injection.
Please consider the example below.
For example, selector() is a function that select something and guarantee return an interface
In this example
bar.node.go
type NodeTemplate struct {
Name string
}
// satisfy interface declared in db.foo.go
//but never imports anything from db.foo.go
func (node *NodeTemplate) GetUuidName() string {
if node != nil {
return node.Name
}
return
}
db.foo.go
// interface declared in db.foo.go
type Node interface {
GetUuidName() string
}
Option A
// So selector receives a map of Some interface and populate a map
func SelectSomething(nodemap map[string]Node, selectFactor string) {
// selection from db and result populate in a map
}
Option B
Another pattern SelectSomething return a Node
and it Interface
So another package will depend on importing Node
and that will introduce a dependency.
func SelectSomething(seleconsomething) []*Node {
// do selection and return a slice of SomeInterface
n := &Node{} // here it need to be concret type T
return Node
}
So based on logic I've described I see the first approach is better but in that approach, select need do concrete type allocation in order to populate a map.
Consider another example
db.foo.go
type Node interface {
GetUuidName() string
}
func inserter(node *Node) error {
// do some work
node.GetUuidName()
}
For a case like in inserter case, inserter has no external dependency, inserter just needs to receive something that satisfies the interface. Declare interfaces locally and that brake a dependancy.
But in the case of selector example, it has to do memory allocation in order to return or populate a map or return something that has concrete type T. So in both case, it has to have internal re-presentation.
So here is my question can selector somehow at run time figure out a type it receives based on the interface and instantiate an object of that type and insert to a map as an interface or return a slice of the interface. ?
By doing so selector function will have no dependancy on what it receives it just guarantee it will instantiate the same object type T
and return interface.
or can selector return interface but I guess I have to have a bi-directional interface between db package and package X or dynamic dispatcher need to do some magic ?
You want a type to behave in a certain way. That is achieved via an interface. This case is no different. Simply add the desired behavior to your interface, as demonstrated below with the Foo interface.
package main
import (
"fmt"
"reflect"
)
type Foo interface {
Bar()
TypeOf() reflect.Type
}
type Baz struct{}
func (b Baz) Bar() {
fmt.Println("I am a Fooer!")
}
func (b Baz) TypeOf() reflect.Type {
return reflect.TypeOf(b)
}
func DoSomeThing(f Foo) {
f.Bar()
fmt.Println(f.TypeOf())
}
func main() {
fmt.Println("Hello, playground")
b := Baz{}
DoSomeThing(b)
}
Run on playground
Golang docs provide a clear guidance on how to name single-method interface (by appending "-er"). But what is the best practice to name a multi-method interface that has only a single struct implementing it?
In C# the interface would have "I" prefix, in Java, the class will have "Impl" suffix. Are there similar guidelines for Golang?
The point of having an interface here is to be able to mock it for unit-testing of components that depend on it.
Here is a specific example of UserManager interface. It is going to be consumed by a web api controller that will translate HTTP requests into method calls on this interface. This web api controller will use most of the methods of UserManager.
type UserManager interface { // Should it be UserManagerInterface ?
GetUser(id int) User
CreateUser(user User)
DeleteUser(id int)
ResetPassword(id int, newPassword string)
VerifyEmail(id int)
}
type UserManagerImpl struct { // -Impl, or -Struct, or something else?
}
Coming from Java/C# to Go requires a paradigm shift.
Because they are implemented implicitly, interfaces are defined where they're consumed, not where they're implemented.
Because they're implemented implicitly, smaller interfaces are preferred over larger interfaces, hence the focus on single-method "Verber" interfaces. If you have a function that needs to read bytes, it can take a io.Reader, and the function can be supplied any type that has that method (regardless what other methods it has). You probably don't have a function that calls all 5 of the methods listed in your interface (if so, that function is probably doing too much).
If you feel like naming a struct and an interface the same thing and therefore need some kind of prefix/suffix, you're probably thinking about it the wrong way and might need to reconsider your design.
DBAL is one area where there is sometimes a real case for a larger interface (though it should probably still be composed of smaller interfaces). But in this case, "Impl" doesn't tell you anything - Java and C# love to have pointless interfaces, Go does not. If you'll only ever have one implementation, the interface is probably useless.
If you will have multiple implementations, the differences between them should guide your naming. For example, you might have a PostgresUserManager, a MongoUserManager, and a MockUserManager.
Do you really need UserManagerImpl struct be public? It's kinda common to have a public interface and the corresponding private implementation. Check this and this.
type Store interface {
RunRoot() string
GraphRoot() string
...
}
type store struct {
...
}
func New() Store {
return &store{}
}
func (s *store) RunRoot() string {
return s.runRoot
}
func (s *store) GraphRoot() string {
return s.graphRoot
}
I mean, if you came up with a decent name for the interface, you still can use it for the implementation. But in general, it's good to call things reflecting what they really are regardless of the best practices of the given language. Projects are unique, it's barely possible to make a list of best practices suitable for all the use cases of the language.
The same as #Ivan Velichko I also used to make Interfaces public and struct private like so:
type Service interface {
Do() error
}
type service struct {
dependency dependencies.Dependency
}
func (s *service) Do() error {
return s.depedency.Do()
}
func NewService() Service {
return &service{}
}
However if for some reasons you have to make structs or their properties public and you don't want to write a lot of getters or setters consider examples below:
Make interface name more specific to actions it does
According this articles:
Effective Go
Is there a naming convention for interface + struct pairs?
You should:
By convention, one-method interfaces are named by the method name plus an -er suffix or similar modification to construct an agent noun: Reader, Writer, Formatter, CloseNotifier etc.
type ServiceWorker interface {
HandleMessages() error
}
type Service struct {
dependency dependencies.Dependency
}
func (s *service) HandleMessages() error {
return s.depedency.Do()
}
func NewServiceWorker() Service {
return &service{
Property: "property"
}
}
Create function for getting/modifying struct
type Service interface {
Do() error
Service() *service // this will handle getting and modifying your struct
}
type service struct {
dependency dependencies.Dependency
Property string // property to want to expose
}
func (s *service) Do() error {
return s.depedency.Do()
}
func (s *service) Service() *service {
return s
}
func NewService() Service {
return &service{
Property: "property"
}
}
//...
func main() {
s := pkg.NewService()
fmt.Println("p1:", s.Service().Property) // p1: property
s.Service().Property = "second"
fmt.Println("p2:", s.Service().Property) // p2: second
}
Define getters and setters
Define getters and setters in more Java/C# way:
type Service interface {
Do() error
Get() service
Set() *service
}
type service struct {
dependency dependencies.Dependency
Property string // property to want to expose
}
func (s *service) Do() error {
return s.depedency.Do()
}
func (s service) Get() service {
return s
}
func (s *service) Set() *service {
return s
}
func NewService() Service {
return &service{
Property: "property"
}
}
I want to compose a type of another type, but replace one of the fields (which is an interface value) with a fake. The problem I am getting is the underlying field is being used, so I can't seem to override the field.
I've demoed the problem here: https://play.golang.org/p/lHGnyjzIS-Y
package main
import (
"fmt"
)
type Printer interface {
Print()
}
type PrinterService struct {}
func (ps PrinterService) Print() { fmt.Println("PrinterService") }
type Service struct {
Client PrinterService
}
func (s Service) PrintViaMethod() { s.Client.Print() }
type FakeService struct {
Service
Client Printer
}
type SomeOtherService struct {}
func (sos SomeOtherService) Print() { fmt.Println("SomeOtherService") }
func main() {
s := FakeService{Client: SomeOtherService{}}
s.PrintViaMethod()
}
Why does it print "PrinterService"? I want it to print "SomeOtherService".
Thanks.
By s.PrintViaMethod(), you are calling the promoted method FakeService.Service.PrintViaMethod(), and the method receiver will be FakeService.Service which is of type Service, and Service.PrintViaMethod() calls Service.Client.Print(), where Service.Client is of type which PrinterService, that's why it prints "PrinterService".
In Go there is embedding, but there is no polymorphism. When you embed a type in a struct, methods of the embedded type get promoted and will be part of the method set of the embedder type. But when such a promoted method is called, it will get the embedded value as the receiver, not the embedder.
To achieve what you want, you would have to "override" the PrintViaMethod() method by providing your implementation of it for the FakeService type (with FakeService receiver type), and inside it call FakeService.Client.Print().
By doing so s.PrintViaMethod() will denote the FakeService.PrintViaMethod() method as that will be at the shallowest depth where the PrintViaMethod() exists (and not FakeService.Service.PrintViaMethod()). This is detailed in Spec: Selectors.
For example:
func (fs FakeService) PrintViaMethod() {
fs.Client.Print()
}
Then the output will be (try it on the Go Playground):
SomeOtherService
See related questions and answers with more details:
Go embedded struct call child method instead parent method
Does fragile base class issue exist in Go?
Why does it print 'PrinterService'? I want it to print 'SomeOtherService'.
Because that's what your code says to do. PrintViaMethod calls s.Client.Print(), and s.Client is a (zero value) instance of PrinterService, which outputs PrinterService.
What you probably want is to call s.Print() in main(). I don't see any reason for your PrintByMethod function at all.
As per Flimzy you are calling print s.Client.Print() which is of type PrinterService implemented as receiver to Print() function printing PrinterService. You can also change type of Client PrinterService in Service struct to Someother service
package embedded
import (
"fmt"
)
type Printer interface {
Print()
}
type PrinterService struct{}
func (ps PrinterService) Print() { fmt.Println("PrinterService") }
type Service struct {
Client SomeOtherService
}
func (s Service) PrintViaMethod() { s.Client.Print() }
type FakeService struct {
Service
Client Printer
}
type SomeOtherService struct{}
func (sos SomeOtherService) Print() { fmt.Println("SomeOtherService") }
func Call() {
s := FakeService{Client: SomeOtherService{}}
s.PrintViaMethod()
}