An API is the set of operations and conventions callers use to interact with a component. In Go, convenient APIs make those operations expressive without hiding useful type information. A common mistake is to design an interface for every implementation before any caller needs one; the extra indirection can make code harder to follow. section 1.3.5 section 2.5.3
Use an interface when a caller needs common behavior, decoupling, or a restricted set of operations. Go types satisfy interfaces implicitly, so a caller can define only the methods it needs. For example, a function accepting `io.Reader` and `io.Writer` can copy between files or other implementations, and can be tested with a string reader and byte buffer. section 2.5.1 section 2.5.2
type customerStorer interface { #1
StoreCustomer(Customer) error
}
type CustomerService struct {
storer customerStorer #2
}
func (cs CustomerService) CreateNewCustomer(id string) error {
customer := Customer{id: id}
return cs.storer.StoreCustomer(customer)
}
The service depends on the `StoreCustomer` behavior rather than a particular store. This abstraction is useful when the service needs to accept another implementation; it need not be created merely because a concrete store exists. section 2.5.2 section 2.5.3
Check an API from the caller’s side:
- Do not force every client through a broad interface defined beside the implementation. A client that only retrieves customers can define a one-method interface where it is used. section 2.6
- Usually return a concrete implementation and accept an interface where useful. Returning an interface can force one abstraction on every caller and create awkward package dependencies; `error` is a notable exception. section 2.7
- Avoid `any` unless arbitrary types are genuinely required. Use functional options when an API needs convenient options rather than choosing a creation pattern by habit. section 2.17
A signature can affect allocations
`Read(p []byte) (n int, err error)` lets the caller supply a buffer. An alternative, `Read(n int) (p []byte, err error)`, would cause the returned slice to escape to the heap. The caller-supplied form does not guarantee stack allocation, but it avoids making that escape a consequence of the signature. When allocations matter, inspect the compiler’s decision with `-gcflags`. section 12.6.1
Return values deserve the same care as parameters: returning an interface that contains a nil pointer does not give the caller a nil interface value. Return an explicit nil value when that is the intended result. section 6.7











































