On Monday, 21 November 2016 17:30:21 UTC+2, Vorn Mom wrote:

> Sorry if it was asked before, but where should interfaces live?
>
>    - In the package that contains an implementation of it.
>    - In its own package.
>    - or in the package that needs it.
>
> The quick answer here is "yes to all", but most commonly it should be in 
"the package that needs it".

The interface can be seen as an evolution of indirection:

*#1 - no interface*

type memorydb struct { people []*Person }
func (db *memorydb) PersonByName(name string) (*Person, error) { ... }

type Server struct {
    db *memorydb
}

*#2 - private interface*, introduced to allow multiple db or to separate 
code more

type memorydb struct { ... }
...
type sqllitedb struct { ... }
...

type peopledb interface { PersonByName(name string) (*Person, error) }

type Server struct {
    db peopledb
}

*#3 - public interface* - introduced to allow sub-packages access/see the 
same interface, this usually happens together with moving the 
memorydb/sqllitedb into a separate package. It can also be used to break 
dependency cycles.

...
type PeopleDB interface { PersonByName(name string) (*Person, error) }

type Server struct {
    db PeopleDB
}

*#4 - common interface* - introduced to allow wide compatibility between 
things; you only end-up here when you are implementing a widely used 
package, e.g. "database/sql/driver.Driver", "io.Reader", "io.Writer", 
"context.Context".

Try to stop at the "smallest number" that solves your problem. Each step 
adds extra indirection and more artifacts, so making code harder to 
understand. Of course, you should keep in mind not to make each 
file/struct/package/interface too large, which also makes code harder to 
read. It's a balancing act . Most web applications will end up at #3... 
frameworks/libraries end up at #3 or #4. Anything else can vary from #1 - 
#4.

+ Egon

The standard library is not consistent.  For example:
>
>    - io.Writer is defined in a package that also has an implementation, 
>    io.PipeWriter.  
>    - Encoding is all interfaces, defering implementation to sub-packages.
>    - database/sql returns a DB struct on Open() instead of an interface.
>    
> Because Go interfaces are decoupled from implementation, I think it should 
> be defined where it's needed.  So I like having my own interface for DB 
> that may only define a subset of what behaviors it provides.
>
> However, doesn't defining an interface that depends on other packages 
> decrease cohesion and leaks the abstraction?  For example,
>
> type interface DbQuery {
>   QueryRow(query string, args ...interface{}) *sql.Row
> }
>
> This interface depends on sql.Row.  This decreases cohesion because the 
> interface is now defined across packages?
>
> -Vorn
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to