Logo

dev-resources.site

for different kinds of informations.

Golang - How a Chef and Waiter Teach the Single Responsibility Principle

Published at
1/16/2025
Categories
go
webdev
programming
oop
Author
dzungnt98
Categories
4 categories in total
go
open
webdev
open
programming
open
oop
open
Author
9 person written this
dzungnt98
open
Golang - How a Chef and Waiter Teach the Single Responsibility Principle

Welcome to the first post in my SOLID principles series for Golang! In this series, I’ll break down each principle of the SOLID design philosophy, helping you write more maintainable and scalable Go applications. We’re starting with the Single Responsibility Principle (SRP) — a foundational concept that promotes cleaner code by ensuring every module does just one thing. 🚀


🏛️ What is the Single Responsibility Principle?

The Single Responsibility Principle states:

A class, module, or function should have only one reason to change.

In simple terms, each component should focus on a single responsibility. If one piece of code is handling multiple tasks, it’s harder to maintain and extend without introducing bugs. Following SRP improves modularity, reusability, and testability.

SRP Image

👨‍🍳 A Real-World Example of SRP: The Chef and the Waiter

Imagine a busy restaurant. In this restaurant, two key people are responsible for ensuring customers have a great experience:

  • The Chef: Prepares delicious meals.
  • The Waiter: Takes orders, serves food, and handles customer requests.

Now, think about what would happen if one person had to do both jobs. If the chef had to stop cooking every time a customer arrived to take an order and serve the meal, it would:

  • Slow down the process.
  • Cause delays in food preparation.
  • Increase the chances of mistakes.

This situation is chaotic and inefficient because the same person is handling multiple unrelated responsibilities.

Applying SRP in the Restaurant

When following the Single Responsibility Principle:

  • The Chef focuses only on preparing food.
  • The Waiter focuses only on managing orders and serving customers.

By separating these roles, each person can do their job well without unnecessary interruptions. This leads to a smoother, faster, and more enjoyable dining experience for customers. 🍴✨

💻 SRP in Programming

Just like in a restaurant, where each person has a single, focused role, your code should also be structured so that each class or function handles only one responsibility. This makes your application easier to maintain, faster to change, and less prone to errors.

SRP in Action with Golang

Let’s look at an example to see how violating SRP can make code fragile and difficult to manage.

❌ Example Violating SRP

Imagine a simple order management system for a coffee shop:

package main

import "fmt"

// Order contains coffee order details.
type Order struct {
    CustomerName string
    CoffeeType   string
    Price        float64
}

// ProcessOrder performs multiple responsibilities.
func (o *Order) ProcessOrder() {
    // Handle payment processing
    fmt.Printf("Processing payment of $%.2f for %s\n", o.Price, o.CustomerName)

    // Print receipt
    fmt.Printf("Receipt:\nCustomer: %s\nCoffee: %s\nAmount: $%.2f\n", o.CustomerName, o.CoffeeType, o.Price)
}

func main() {
    order := Order{CustomerName: "John Doe", CoffeeType: "Cappuccino", Price: 4.50}
    order.ProcessOrder()
}
Enter fullscreen mode Exit fullscreen mode

Here, the Order struct is responsible for storing data, processing payments, and printing receipts. This violates SRP because it performs multiple unrelated tasks. Changes to any of these responsibilities will affect ProcessOrder, making the code less maintainable.

🛠️ Refactoring for SRP

Let’s separate the responsibilities into distinct components:

package main

import "fmt"

// Order contains coffee order details.
type Order struct {
    CustomerName string
    CoffeeType   string
    Price        float64
}

// PaymentProcessor handles payment logic.
type PaymentProcessor struct{}

func (p *PaymentProcessor) ProcessPayment(order Order) {
    fmt.Printf("Processing payment of $%.2f for %s\n", order.Price, order.CustomerName)
}

// ReceiptPrinter handles receipt printing.
type ReceiptPrinter struct{}

func (r *ReceiptPrinter) PrintReceipt(order Order) {
    fmt.Printf("Receipt:\nCustomer: %s\nCoffee: %s\nAmount: $%.2f\n", order.CustomerName, order.CoffeeType, order.Price)
}

func main() {
    order := Order{CustomerName: "John Doe", CoffeeType: "Cappuccino", Price: 4.50}

    paymentProcessor := PaymentProcessor{}
    receiptPrinter := ReceiptPrinter{}

    paymentProcessor.ProcessPayment(order)
    receiptPrinter.PrintReceipt(order)
}
Enter fullscreen mode Exit fullscreen mode

🎯 Benefits of SRP

  • Separation of Concerns: Order only stores data, PaymentProcessor handles payments, and ReceiptPrinter manages receipt generation.
  • Better Testability: You can test PaymentProcessor and ReceiptPrinter independently.
  • Easier Maintenance: Changes to receipt formatting won’t affect payment processing logic.

❓ When to Apply SRP

Look for violations like:

  • Functions or structs doing multiple unrelated tasks.
  • Modules that mix concerns, such as handling both business logic and I/O operations.

✨ Conclusion

By applying the Single Responsibility Principle, your code becomes easier to understand, maintain, and extend. This is just the beginning! Stay tuned for the next post in this series as we explore the "O" in SOLID: the Open/Closed Principle.

You can also check out my other post on Dependency Injection, which is another important technique in OOP.

Happy coding! 🎉


Follow me to stay updated with my future posts:

programming Article's
30 articles in total
Programming is the process of writing, testing, and maintaining code to create software applications for various purposes and platforms.
Favicon
What ((programming) language) should I learn this year, 2025 ?
Favicon
7 Developer Tools That Will Boost Your Workflow in 2025
Favicon
Designing for developers means designing for LLMs too
Favicon
Introduction to TypeScript for JavaScript Developers
Favicon
Filling a 10 Million Image Grid with PHP for Internet History
Favicon
When AI Fails, Good Documentation Saves the Day 🤖📚
Favicon
Is JavaScript Still Relevant?
Favicon
Daily JavaScript Challenge #JS-74: Convert Hexadecimal to Binary
Favicon
Code Smell 286 - Overlapping Methods
Favicon
Searching vs. Sorting in Java: Key Differences and Applications
Favicon
Easy Discount Calculation: Tax, Fees & Discount Percentage Explained
Favicon
Securing Sensitive Data in Java: Best Practices and Coding Guidelines
Favicon
Golang - How a Chef and Waiter Teach the Single Responsibility Principle
Favicon
[Boost]
Favicon
How to Resolve the 'Permission Denied' Error in PHP File Handling
Favicon
7 Mistakes Developers Make When Learning a New Framework (and How to Avoid Them)
Favicon
Python в 2025: стоит ли начинать с нуля? Личный опыт и рекомендации
Favicon
Cómo gestionar tus proyectos de software con Github
Favicon
2429. Minimize XOR
Favicon
Decreasing server load by using debouncing/throttle technique in reactjs
Favicon
➡️💡Guide, Innovate, Succeed: Becoming a Software Development Leader 🚀
Favicon
Debugging Adventure Day 1: What to Do When Your Code Doesn’t Work
Favicon
🚀 New Book Release: "Navigate the Automation Seas" – A Practical Guide to Building Automation Frameworks
Favicon
Build a Secure Password Generator with Javascript
Favicon
join my project semester simulator
Favicon
Как создать свой VPN и получить доступ ко всему?
Favicon
Основы изучения Python: Руководство для начинающих
Favicon
Revolutionary AI Model Self-Adapts Like Human Brain: Transformer Shows 15% Better Performance in Complex Tasks
Favicon
Breakthrough: Privacy-First AI Splits Tasks Across Devices to Match Central Model Performance
Favicon
Flow Networks Breakthrough: New Theory Shows Promise for Machine Learning Structure Discovery

Featured ones: