packagemain.tech

packagemain.tech

Mastering SOLID Principles with Go Examples

The SOLID principles are a set of design guidelines that help developers write more maintainable, scalable, and testable code.

Alex Pliutau's avatar
Alex Pliutau
Jul 09, 2024
∙ Paid

Building software is an ever-shifting challenge. To navigate this complexity, developers rely on proven design principles to craft code that's robust, adaptable, and easy to manage. One such set of principles is SOLID (first introduced by Robert C. Martin).

SOLID stands for: Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion. Each principle plays a vital role in fostering maintainability, scalability, and testability in your programs.

Although Golang is not a purely object-oriented language, we can still apply SOLID principles to improve our Go code. Throughout this post, we'll delve into each principle, explore its meaning, and discover how to leverage it effectively within Go.

S - Single Responsibility Principle

The Single Responsibility Principle (SRP) dictates that a struct/package should focus on a single well-defined area of functionality. Imagine each struct as a specialist with a specific expertise. This keeps your code organized and reduces complexity. Changes to the struct's functionality are isolated, making maintenance and future updates a breeze.

“A class should have one, and only one, reason to change.”

Robert C. Martin

Go excels with structs, not classes. But fear not, the SRP still applies here. Imagine each struct as a tightly-knit module responsible for a single, well-defined task. This modular approach keeps your code clean, reduces complexity, and promotes maintainability.

The magic of SRP extends to Go packages as well. Ideally, a package should focus on a single area of functionality. This minimizes dependencies and keeps things organized. By embracing SRP in both structs and packages, you create a foundation for clean, maintainable, and scalable Go applications.

Some examples of good packages:

  • encoding/json - provides encoding/decoding of JSON.

  • net/url - parses URLs.

Not so good examples:

  • utils - dumping ground for miscellany?

Let’s see an example in Go where we have a struct Survey with some properties and few methods, GetTitle(), Validate() and Save():

You can find the source code in our Github repository.

package survey

type Survey struct {
	Title string
	Questions []string
}

func (s *Survey) GetTitle() string {
	return s.Title
}

func (s *Survey) Validate() bool {
	return len(s.Questions) > 0
}

func (s *Survey) Save() error {
	// saves the survey to the database
	return nil
}

Our current Survey struct seems to be designed well, except for the Save() method. Its presence introduces a violation of the SRP. With both data storage and survey logic residing in the same struct, maintenance, testing, and extension become more challenging.

User's avatar

Continue reading this post for free, courtesy of Alex Pliutau.

Or purchase a paid subscription.
© 2026 Aliaksandr Pliutau · Privacy ∙ Terms ∙ Collection notice
Start your SubstackGet the app
Substack is the home for great culture