Discovering Interfaces in Go: A Practical Approach to Design
Written on
Chapter 1: Understanding Rob Pike's Influence
In the realm of Go programming, Rob Pike stands as a pivotal figure. As one of the key architects behind Go, his philosophies have significantly shaped the language's guiding principles and ongoing evolution. A particularly impactful saying of his is, "Don't design with interfaces, discover them."
This seemingly straightforward idea carries profound implications for developing high-quality Go code. Let's delve into its true essence and illustrate it with an example.
Section 1.1: The Design-First Trap
It's a frequent occurrence for programmers transitioning from languages like Java or C++ to begin their design process by outlining a comprehensive array of interfaces, often attempting to anticipate every possible feature a type might require in the future. Unfortunately, this method often results in cumbersome interfaces filled with methods that may never actually be utilized.
Subsection 1.1.1: The Go Philosophy: Discovering Interfaces
Rather than adhering to a design-first strategy, Go advocates for a more organic approach—interfaces should emerge as needed in the codebase. They should be minimalistic and concentrated, ideally encapsulating single-method functionalities.
Consider this straightforward example:
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
In this case, we see two essential interfaces from Go's standard library: Reader and Writer. Each interface features just a single method. They were not the result of an elaborate design process but were instead identified as necessary when the time arose. Consequently, they lay the groundwork for input and output operations in Go, with a myriad of types implementing these interfaces to deliver diverse functionalities.
By approaching interface discovery in this manner, we maintain their simplicity and relevance, ensuring they provide only the needed functionalities to the user.
Section 1.2: Implementing Interface Discovery in Your Work
When developing your own Go applications, it's advisable to initially refrain from implementing any interfaces and introduce them only when you identify recurring behavioral patterns.
For instance, while crafting a program to manage data from various sources, you might initially create distinct functions to handle data from each source. Over time, you may observe that these functions share many similarities—they all require opening a source, reading data, and closing the source afterward. This repeated behavior presents a perfect opportunity for creating an interface.
type DataProcessor interface {
Open() error
Read() ([]byte, error)
Close() error
}
The DataProcessor interface can now be adopted by multiple data sources, enhancing code reusability and uniformity.
Chapter 2: The Impact of Interface Discovery
The principle espoused by Rob Pike regarding the "discovery of interfaces" resonates deeply with Go's commitment to simplicity and minimalism. This philosophy guarantees that our interfaces are as intricate as necessary, fostering readability, adaptability, and maintainability. In Go, we allow the requirements of the code to dictate the emergence of our interfaces, rather than imposing them prematurely.
Video Description: In this video, "Interfaces in Go - Discovering Behavior," we explore how interfaces can streamline Go programming by focusing on behavior rather than design.
Video Description: The video "Another Go at Language Design" discusses the principles of language design and how they influence the development of programming languages like Go.