Why to call private function from a public one, instead of implemente code in public one? - go

I see a lot of codes like this in the golang src:
func Open(path string) (*Plugin, error) {
return open(path)
}
func open() {
// etc
}
A private function been called from a public. Why not just:
func Open(path string) (*Plugin, error) {
// code of open here
}
ref: https://golang.org/src/plugin/plugin.go?s=1065:1104#L21
I do understand that sometimes it makes sense, especially if there are more functions using open. But that's not the case.
Is this some kind of Golang way of organizing things?

In this case, it appears to be because the actual implementation is OS dependent.
The plugin implementation plugin_dlopen.go is used only for OSX and Linux, and the alternative plugin_stubs.go is for everything else(which just contains dummy functions as there is no implementation for other systems yet.)
This allows you to keep OS dependent code in one file using build tags, while keeping general code, the public API and documentation for the public API in a single place.

Related

GoDoc Example function for type/struct functions

Problem
I have written some example functions located in a *_test.go file to help clarify context for standalone public functions without issue. The problem on displaying comes when writing example functions for functions tied to a type.
Example
Here's a basic example of what I'm encountering.
Say we have a function in main.go like below:
type Client struct {
user string
ip string
}
func (c *Client) SendNotification(message string) error {
return nil
}
I want to create an example function for such in main_test.go, like below
func ExampleSendNotification() {
//Showoff code here
}
VSCode throws an error for that specific example, saying "ExampleSendNotification refers to unknown identifier: SendNotification". Also, it just does not appear as an example when running the godoc.
I've also tried this format:
func (c *Client) ExampleSendNotification() {
//Showoff code here
}
But then it just removes it as a test in VSCode, and doesn't appear
I found the answer just as I was finishing writing this. Thought I would still post for anybody else.
The trick is writing Example[Type]_[Method], so practically in my example, that would look like:
func ExampleClient_SendNotification() {
//Showoff code here
}

A repository/store for database as interface or per table interface?

What I designed first was to have a Store interface as follow:
// store.go
type Store interface {
CreateUser(user model.User) (string, error)
GetProfile(userId string) (model.User, error)
CreateHouse(user model.House) (string, error)
}
And in another file, mongo_store.go, its implementation codes:
type mongoStore struct {
store *mongo.Client
}
func (mc *mongoUserStore) CreateUser(user model.User) (string, error) {
}
// And so on...
In mongo_store.go I have another method that returns an instance of MongoStore:
func NewMongoDBStore() Store {
// Some code to connect to MongoDB and finally
s := &mongoStore{
store: client,
}
return s
}
I've gone this way to abstract away DB layer. So in code we pass store around and call let's say CreateUser as an example.
My team members had the object of creating Store interface per table. So we should have UserStore interface with their methods or HouseStore with their own methods.
First question is that is this a best practice to change the code this way? I could not come up with a good argument to reject their change request. It's been said that this way we can mock less code in tests and also it is not polluted, all in one place for all methods that work with DB.
My Second Question is if we go the second approach, how NewMongoDBStore should return different store types. So instead of Store as return type we have to have different store types like UserStore, HouseStore, etc.
I always try to stick to one rule when designing new interfaces in Go: keep interfaces as small as possible. You can see that stdlib also tries to follow that rule, see for example fmt.Stringer, http.Handler or json.Marshaler. Look how in the json library they even separated json.Marshaler and json.Unmarshaler (same for the io.Reader and io.Writer), which, you can say, seem to be very connected together.
Coming back to your example, I think that your team makes a good point - I would go for the separation of the storages interfaces. The only situation in which I wouldn't do that is if you are sure that this interface will never expand and will always stick to this very limited number of methods. But I think this is very unlikely for the storage-like interfaces. For example in the near future you could like to add some more-grained filtering methods, or e.g. a method to insert storage objects in a batch.
In my opinion you can only benefit from separating the interfaces and here is why:
It's true that it is easier to mock an interface with a 1-2 methods than an interface with, let's say, 10 methods.
It's always better to separate functionalities into smaller pieces as you may not need to use all of them at once in every place. To give you a better picture you can have one service which would use your UserStore and your HouseStore implementations, but you can also have a second service that wouldn't need a HouseStore and would only use a UserStore implementation. Thanks to that it would be much easier to mock the second service (as it uses only a UserStore) and if you later add any methods to the HouseStore there is no possible way it could affect the second service anyhow as it knows nothing about this interface.
I think the above answers your first question. Coming to the second question you can solve it in two ways I think:
First way is something I usually do. You can simply create separate implementations for separate interfaces. So if you have, following your example, a file store.go containing interfaces:
type UserStore interface {
CreateUser(user model.User) (string, error)
// Rest of the methods ...
}
type HouseStore interface {
CreateHouse(house model.House) (string, error)
// Rest of the methods ...
}
I would make a user_mongo_store.go with MongoDB implementation for the UserStore ...
type userMongoStore struct {
store *mongo.Client
}
func (s *userMongoStore) CreateUser(user model.User) (string, error) {
// CreateUser method implementation ...
}
func NewUserMongoStore() UserStore {
// Some code to connect to MongoDB and finally
s := &userMongoStore{
store: client,
}
return s
}
// Rest of the UserStore methods implementations ...
... and I would also make a house_mongo_store.go file with MongoDB implementation for the HouseStore:
type houseMongoStore struct {
store *mongo.Client
}
func (s *houseMongoStore) CreateHouse(house model.House) (string, error) {
// CreateHouse method implementation ...
}
func NewHouseMongoStore() HouseStore {
// Some code to connect to MongoDB and finally
s := &houseMongoStore{
store: client,
}
return s
}
// Rest of the HouseStore methods implementations ...
You could ask here if will not feel inconvinient to keep two MongoDB storages implementations separated as they could contain the same MongoDB-related operations. Answer to that question is no: you can always create e.g. mongo_store.go to keep all the common functions that will be shared by all the MongoDB storages implementations.
The only disadvantage I can see here is a little bit more code in general, but in the end it gives you much cleaner, better separated and more modular code.
Second way, which I would recommend less, is to use the (in my opinion) very powerful Go feature which is a fact that you don't declare implementing an interface (unlike in e.g. Java), you just have to implement all the interfaces methods in your struct and you can use it as all these interfaces implementations. In your case you could stick to the single mongoStore struct and make it implement both the UserStore and the HouseStore interfaces methods. That way you would end up with something like this:
type mongoStore struct {
store *mongo.Client
}
func (s *mongoStore) CreateUser(user model.User) (string, error) {
// CreateUser method implementation ...
}
func (s *mongoStore) CreateHouse(house model.House) (string, error) {
// CreateHouse method implementation ...
}
// Rest of the UserStore and HouseStore
// interfaces methods implementations ...
but this solution leaves us with a problem: how to create a function to create UserStore and HouseStore interfaces implementations. Well, in this situation you could either make mongoStore struct exported and use it directly as both a UserStore and HouseStore implementations or, which looks a little bit more exotic but is still a valid piece of code, you could make a function that would return this single struct as both implementations, e.g.:
func NewMongoStores() (UserStore, HouseStore) {
s := &mongoStore{
store: client,
}
return s, s
}
I think I gave you some options, but to sum up, I would encourage you to keep your interfaces and their implementations separated.

How can an external package implement an interface implicitly?

I'm writing a piece of code that relies on some implementation.
I want to decouple the implementation from my code, and make the implementation as independent as possible.
I thought of achieving this approach by using interfaces instead of concrete types, like so:
package mypackage
type MyType interface {
Title() string
Price() int
}
type TypeGetter interface {
GetType() MyType
}
func MyHandler(tg TypeGetter) {
t := tg.GetType()
fmt.Printf("Title: %s, Price: %d", t.Title(), t.Price())
}
And an implementation might be something like this:
package external
// CustomType implicitly implements the MyType interface
type CustomType struct {
title string
price int
}
func (t CustomType) Title() string { return t.title }
func (t CustomType) Price() int { return t.price }
// CustomTypeGetter implicitly implements the TypeGetter interface. Or is it???
type CustomTypeGetter struct {
}
func (g CustomTypeGetter) GetType() CustomType {
return CustomType{"Hello", 42}
}
Then, the code would do something like this:
package main
import "mypackage"
import "external"
func main() {
tg := external.CustomTypeGetter{}
mypackage.MyHandler(tg) // <--- the compiler does not like this
}
I hope the example speaks for itself: I have no coupling between "mypackage" and the "external" package, which may be replaced, substituted my mocks for testing, etc.
The problem: the compiler complains that the call to MyHandler has an object that implements:
func GetType() CustomType, instead of:
func GetType() MyType
The only solution I found is to move the interface declarations (MyType and TypeGetter) to a third package, and then both "mypackage" and "external" packages can use it.
But I want to avoid that.
Isn't Go's concept of implicit implementation of interfaces contradict the idea of a third common package?
Is there a way to implement such thing, without binding the two packages together?
Isn't Go's concept of implicit implementation of interfaces contradict the idea of a third common package?
I think it does. Go authors introduced an implicit interface implementation to eliminate unnecessary dependencies between packages. That works well for simple interfaces like io.Reader, but you cannot apply it everywhere.
One of the language creators, Rob Pike, says that the non-declarative satisfaction of interfaces is not the essential part of the idea behind interfaces in Go. It's a nice feature, but not all elements of the language are practical or possible to use every time.
For complex interfaces, you need to import a package where the interface is defined. For example, if you want to implement an SQL driver that works with the sql package from the standard library, you must import the sql/driver package.
I would recommend not introducing interfaces at the beginning of your project. Usually, it leads to situations where you need to solve artificial problems like rewriting the interface each time you updates your understanding of the domain model. It is hard to come up with a good abstraction from the first attempt, and, in many cases, it is unnecessary, in my opinion.
I need to query external source for products. I don't care how the external sources store the data (db, file, network). I just need a "product" type. So it's either I define a Product type, forcing the external implementations to import and use it, or the Go way - define a Product interface and let the implementations implicitly implement this interface. Which apparently doesn't work
I see two loosely related goals here:
Define an interface to swap implementations of the product source.
A package that implements the product source should not import the package that defines the interface.
From my experience, I would recommend doing point 1 only when you have at least one working implementation of the product source service.
Point 2 is not always possible to achieve, and it is fine; please see the example from the standard Go library above.
P.S.
Please, consider not creating Product interface. While it does makes sense to come up with the PorductSource interface eventually, Product is most probably just a set of data; struct is a perfect way to represent such information. Please, see this very relevant code smaple and this article for inspiration.
The problem with your approach is that you want someone to implement an interface that refers to your type (MyType). This obviously cannot be done without the implementation referring to your type. This is the only thing that prevents the above code from working.
If you get rid of the MyType:
type TypeGetter interface {
GetType() interface {
Title() string
Price() int
}
}
And the implementation:
func (g CustomTypeGetter) GetType() interface {
Title() string
Price() int
} {
return CustomType{"Hello", 42}
}
Then this code will work:
func main() {
tg := external.CustomTypeGetter{}
mypackage.MyHandler(tg)
}
Yes, this requires repetition, but only because you don't want an unknown / future implementation to refer to your type (to not depend on it).
In this case you may change MyHandler() to take a value of type MyType (get rid of the "factory"):
func MyHandler(t MyType) {
fmt.Printf("Title: %s, Price: %d", t.Title(), t.Price())
}
And any value that implements MyType may be passed. Add a "factory" to the external package:
func NewCustomType(title string, price int) CustomType {
return CustomType{
title: title,
price: price,
}
}
And use it like this:
func main() {
t := external.NewCustomType("title", 1)
mypackage.MyHandler(t)
}
If you truly require the factory pattern, then yes, creating a 3rd package that will hold MyType is the way to go. Then both your app and the implementations may refer to this 3rd package.

Function as argument, access inner parameter

The package valyala/fasthttp implements the following function type:
type RequestHandler func(ctx *RequestCtx)
It is used in buaazp/fasthttprouter like this:
func (r *Router) Handle(method, path string, handle fasthttp.RequestHandler) {
//...
}
I am trying to wrap these like this (open for suggestions on implementation):
//myapp/router
type Request struct {
fasthttp.RequestCtx
}
type RequestHandler func(*Request)
func Handle(method string, path string, handler RequestHandler) {
//I need to access the fasthttp.RequestCtx stuff in here...
}
How can I achieve this? Or, if this is not the way to go at all, how can I achieve my goal as mentioned below for a router package?
BACKGROUND
Goal: My wish is to wrap tooling packages (sessions, database, routing, etc.) in order to make my app agnostic to the implementation of these packages. I wish to do this primarily for the purpose of being able to extend these with domain-specific functionality, and being able to switch one 3rd party lib for another, if I ever would need to do so. It also makes debugging and logging easier.
Method: I create native types and functions, which map to the functionality of the imported packages.
Problem: I am stuck on how to wrap a foreign (i.e. imported) function type properly.
At all your idea looks very good. Some things you could change:
//myapp/router
// Using a composition is idiomatic go code
// this should work. It can't get better.
type Request struct {
fasthttp.RequestCtx
}
// I would make the RequestHandler as a real Handler. In go it would be
// a interface
type RequestHandler interface{
Request(*Request)
}
// If you have a function, which needs to access parameters from `Request`
// you should take this as an input.
func Handle(method string, path string, req *Request) {
//Access Request via req.Request ...
}
Because if you pass a function or an interface into your function, which needs also Request as input the caller needs to create that before he calls your Handle function. Why not change that function just for the input you really need?

Golang code structuring

Is it worth to group methods in structs:
For example:
type UserManager struct {
DB *sql.DB
}
func (m UserManager) Insert (u User) error {...}
func (m UserManager) Delete (u User) error {...}
...
Or is it simpler support just separate functions.
func InsertUser (u User, db *sql.DB) error {...}
While second approach looks simpler at first, in future this way, there may be to many functions in package. Should I make separate package for every domain aggregate? In examples, I've seen so far, there is just model package.
I've been working mainly with OO languages so need some advice for go best practices here.
Your second suggestion is not good go code! Why? Because in the best case a function should take interfaces as an input.
So a InsertUserfunction should look something like that and it would combine your first with your second suggestion:
type Inserter interface {
Insert(User)error
}
func InsertUser(i Inserter) error {...}
In that case testing of your function is easy, because you can easy mock the inserter.
Either, or neither - it really doesn't matter in my opinion because the idiomatic approach would be to organize these concepts using interfaces:
package user
type User ...
type Inserter interface { Insert(User) error }
type Deleter interface { Delete(User) error }
type Manager interface { Inserter, Deleter } // bloated interface
User in this case is probably a concrete row type like in your example, but one could make the case for making it too into an interface that doesn't mention those types.
If you write functions that reference these interfaces, then you can quickly glue together using embedding & promoted fields.
In your case it's obvious that sticking to the first implementation style is much simpler:
type userManager struct { ... }
func (userManager) Insert(u User) error { ... }
func (userManager) Delete(u User) error { ... }
userManager is a private type, so it can be changed without concern, as long as it keeps satisfying the public interfaces.
Keeping the interfaces decoupled from the implementation makes it much easier to make them narrow, so instead of just having a "user manager" or something, you can find out which interfaces you really need for the tasks. Incidentally, this approach has the nice property that it fits well with the object capability model, which helps to simplify things like role based access control.

Resources