Preemptive abstractions make systems complex

All problems in computer science can be solved by another level of indirection, except of course for the problem of too many indirections. - David J. Wheeler

Interfaces abstract away from structures in Go and this indirection has a non zero level of embedded complexity. A common reason to return interfaces from function calls is to let users focus on the API emitted by a function. This isn’t needed with Go because of implicit interfaces.

type Database struct{}
func (d *Database) AddUser(s string) {...}
func (d *Database) RemoveUser(s string) {...}
func NewUser(d *Database, firstName, lastName string) {
	d.AddUser(firstName+lastName)
}

Just like a recipe with too many ingredients, NewUser takes a Database object that can do too many things. It only needs AddUser, but takes something that also has RemoveUser. Interfaces allow us to create the function that only depends upon what we need.

type DatabaseWriter interface {
	AddUser(string)
}
func NewUser(d DatabaseWriter, firstName, lastName string) {
	d.AddUser(firstName+lastName)
}

Dave Cheney wrote about this point when he described Interface Segregation Principle. He also describes other advantages of limiting input that’s worth reading. The summary goal that drives home the idea is:

the results has simultaneously been a function which is the most specific in terms of its requirements-it only needs a thing that is writable-and the most general in its function.

Summarize the reasons and examine exceptions

The primary reasons listed are:

Practices:

  1. Let the consumer define the interfaces it uses
  2. Producers should return concrete types