This commit is contained in:
wagslane
2023-05-01 15:25:27 -06:00
parent f8912668b8
commit 9be3074de6
868 changed files with 58698 additions and 2 deletions

View File

@@ -0,0 +1,8 @@
{
"question": "Interfaces should have as _ methods as possible",
"answers": [
"Few",
"Many",
"Complex"
]
}

View File

@@ -0,0 +1,59 @@
# Clean Interfaces
Writing clean interfaces is *hard*. Frankly, anytime youre dealing with abstractions in code, the simple can become complex very quickly if youre not careful. Lets go over some rules of thumb for keeping interfaces clean.
## 1. Keep Interfaces Small
If there is only one piece of advice that you take away from this article, 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 thats a good example of defining minimal behavior:
```go
type File interface {
io.Closer
io.Reader
io.Seeker
Readdir(count int) ([]os.FileInfo, error)
Stat() (os.FileInfo, error)
}
```
Any type that satisfies the interfaces behaviors can be considered by the HTTP package as a *File*. This is convenient because the HTTP package doesnt need to know if its dealing with a file on disk, a network buffer, or a simple `[]byte`.
## 2. Interfaces Should Have No Knowledge of Satisfying Types
An interface should define what is necessary for other types to classify as a member of that interface. They shouldnt be aware of any types that happen to satisfy the interface at design time.
For example, lets assume we are building an interface to describe the components necessary to define a car.
```go
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:
```go
type firetruck interface {
car
HoseLength() int
}
```
Which inherits the required methods from `car` and adds one additional required method to make the `car` a `firetruck`.
## 3. Interfaces Are Not Classes
* Interfaces are not classes, they are slimmer.
* Interfaces dont have constructors or deconstructors that require that data is created or destroyed.
* Interfaces arent hierarchical by nature, though there is syntactic sugar to create interfaces that happen to be supersets of other interfaces.
* Interfaces define function signatures, but not underlying behavior. Making an interface often wont DRY up your code in regards to struct methods. For example, if five types satisfy the `fmt.Stringer` interface, they all need their own version of the `String()` function.
## Optional: Further reading
[Best Practices for Interfaces in Go](https://blog.boot.dev/golang/golang-interfaces/)