

0 / 2 embers
0 / 3000 xp
click for more info
Complete a lesson to start your streak
click for more info
Difficulty: 7
click for more info
Not enough gems
Cost: 6 gems
1: Interfaces in Go
incomplete
2: Interface Implementation
incomplete
3: Interfaces Are Implemented Implicitly
incomplete
4: Interfaces Quiz
incomplete
5: Multiple Interfaces
incomplete
6: Name Your Interface Parameters
incomplete
7: Type Assertions in Go
incomplete
8: Type Switches
incomplete
9: Clean Interfaces
incomplete
10: Message Formatter
incomplete
11: Process Notifications
incomplete
Back
ctrl+,
Next
ctrl+.
This lesson's interactive features are locked, please to keep using them
Writing clean interfaces is hard. Frankly, any time you're dealing with abstractions in code, the simple can become complex very quickly if you're not careful. Let's go over some rules of thumb for keeping interfaces clean.
If there is only one piece of advice that you take away from this lesson, make it this: keep interfaces small! Interfaces are meant to define the minimal behavior necessary to accurately represent an idea or concept.
Here is an example from the standard HTTP package of a larger interface that's a good example of defining minimal behavior:
type File interface {
io.Closer
io.Reader
io.Seeker
Readdir(count int) ([]os.FileInfo, error)
Stat() (os.FileInfo, error)
}
Any type that satisfies the interface's behaviors can be considered by the HTTP package as a File. This is convenient because the HTTP package doesn't need to know if it's dealing with a file on disk, a network buffer, or a simple []byte.
An interface should define what is necessary for other types to classify as a member of that interface. They shouldn't be aware of any types that happen to satisfy the interface at design time.
For example, let's assume we are building an interface to describe the components necessary to define a car.
type car interface {
Color() string
Speed() int
IsFiretruck() bool
}
Color() and Speed() make perfect sense. They are methods confined to the scope of a car. IsFiretruck() is an anti-pattern. We are forcing all cars to declare whether or not they are firetrucks. In order for this pattern to make any amount of sense, we would need a whole list of possible subtypes. IsPickup(), IsSedan(), IsTank()... where does it end??
Instead, the developer should have relied on the native functionality of type assertion to derive the underlying type when given an instance of the car interface. Or, if a sub-interface is needed, it can be defined as:
type firetruck interface {
car
HoseLength() int
}
Which inherits the required methods from car as an embedded interface and adds one additional required method to make the car a firetruck.
fmt.Stringer interface, they all need their own version of the String() function.