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.