# Golang Patterns
## defer + named return error handling
> [!ai]+ Claude
>
> The "defer + named return" error handling pattern in Go is a convenient and robust way to handle errors in functions. Let's break it down:
>
> 1. **Named Return Values**: In Go, you can name the return values of a function. When named, these variables are treated as defined at the top of the function and are returned automatically when the function exits.
>
> 2. **Defer Statement**: The `defer` statement in Go is used to schedule a function call (the deferred function) to be run immediately before the function executing the `defer` returns.
>
> 3. **Error Handling Pattern**: Combining these two features, you can create an error handling pattern where you `defer` a function that handles the error. This deferred function can check if an error occurred (by checking the named error return value) and handle it accordingly. This approach ensures that the error handling is done right before the function exits, making the code cleaner and more maintainable.
>
> Here's an example to illustrate this pattern:
>
> ```go
> func doSomething() (result int, err error) {
> defer func() {
> if err != nil {
> // Handle error
> // Log, clean up resources, etc.
> // 'err' is the named return value, so it's in scope here
> }
> }()
>
> // Do some work
> // If an error occurs, set 'err'
> // The deferred function will handle it
>
> return 42, nil // Example return value
> }
> ```
>
> In this example, the function `doSomething` has named return values `result` and `err`. The `defer` statement schedules a function that checks `err` and handles it if it's not `nil`. This pattern is useful because it centralizes error handling, reducing the risk of missing error checks and making the main logic of the function cleaner.
## **Singleton Pattern**:
> [!ai]+ Claude
>
> ```go
> type singleton struct {}
>
> var instance *singleton
> var once sync.Once
>
> func GetInstance() *singleton {
> once.Do(func() {
> instance = &singleton{}
> })
> return instance
> }
> ```
## **Factory Method Pattern**:
> [!ai]+ Claude
>
> ```go
> type Animal interface {
> Speak() string
> }
>
> func NewAnimal(t string) Animal {
> switch t {
> case "dog":
> return &Dog{}
> case "cat":
> return &Cat{}
> default:
> return nil
> }
> }
>
> type Dog struct {}
> func (d *Dog) Speak() string { return "Woof" }
>
> type Cat struct {}
> func (c *Cat) Speak() string { return "Meow" }
> ```
>
## Functional Options Pattern
> [!ai]+ Claude
>
> ```go
> type Server struct {
> host string
> port int
> }
>
> type ServerOption func(*Server)
>
> func WithHost(h string) ServerOption {
> return func(s *Server) {
> s.host = h
> }
> }
>
> func WithPort(p int) ServerOption {
> return func(s *Server) {
> s.port = p
> }
> }
>
> func NewServer(opts ...ServerOption) *Server {
> s := &Server{}
> for _, opt := range opts {
> opt(s)
> }
> return s
> }
> ```
>
## **Middleware Pattern**:
> [!ai]+ Claude
>
> ```go
> type Middleware func(http.HandlerFunc) http.HandlerFunc
>
> func LoggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
> return func(w http.ResponseWriter, r *http.Request) {
> // Log request
> next(w, r)
> }
> }
>
> func main() {
> http.HandleFunc("/", LoggingMiddleware(MyHandler))
> }
>
> func MyHandler(w http.ResponseWriter, r *http.Request) {
> // Handler logic
> }
> ```
>
## **Concurrency Patterns (Worker Pools)**:
> [!ai]+ Claude
>
> ```go
> func worker(jobs <-chan int, results chan<- int) {
> for job := range jobs {
> results <- job * 2 // Example work
> }
> }
>
> func main() {
> jobs := make(chan int, 100)
> results := make(chan int, 100)
>
> for w := 0; w < 3; w++ {
> go worker(jobs, results)
> }
>
> for j := 0; j < 5; j++ {
> jobs <- j
> }
> close(jobs)
>
> for a := 0; a < 5; a++ {
> <-results
> }
> }
> ```
>
## **Error Group Pattern**:
> [!ai]+ Claude
>
> ```go
> func main() {
> var g errgroup.Group
> var urls = []string{
> "http://www.golang.org/",
> "http://www.google.com/",
> "http://www.somestupidname.com/",
> }
> for _, url := range urls {
> // Launch a goroutine to fetch the URL.
> url := url // https://golang.org/doc/faq#closures_and_goroutines
> g.Go(func() error {
> // Fetch the URL.
> return nil // Replace with real error handling
> })
> }
> // Wait for all HTTP fetches to complete.
> if err := g.Wait(); err == nil {
> fmt.Println("Successfully fetched all URLs.")
> }
> }
> ```
>
## **Context Pattern**:
> [!ai]+ Claude
>
> ```go
> func main() {
> ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
> defer cancel()
>
> go func() {
> select {
> case <-time.After(2 * time.Second):
> fmt.Println("overslept")
> case <-ctx.Done():
> fmt.Println(ctx.Err()) // prints "context deadline exceeded"
> }
> }()
>
> time.Sleep(5 * time.Second)
> }
> ```