Design with Duck Typing

As mentioned in the previous chapter, this is known as Duck Typing. It's a powerful design pattern. A thing is defined not by its type hierarchy but by its behaviors.

Here's an example of a File interface from the github.com/couchbase/moss package:

// The File interface is implemented by os.File. App specific
// implementations may add concurrency, caching, stats, fuzzing, etc.
type
File interface {
io.ReaderAt
io.WriterAt
io.Closer
Stat() (os.FileInfo, error)
Sync() error
Truncate(size int64) error
}

Here's another example of it from Go's mime/multipart project:

// File is an interface to access the file part of a multipart message.
// Its contents may be either stored in memory or on disk.
type
File interface {
io.Reader
io.ReaderAt
io.Seeker
io.Closer
}

When composing with interfaces, keep things as simple as possible. Similarly, function signatures should be designed to only accept the smallest possible interface required to get the job done.

Note the application of the single responsibility principle and open/close principle in action: our software should be open for extension but closed for modifications.