# My Preferred Go Stack

A few weeks ago, a friend asked how I wrote code so swiftly. The secret isn’t maintaining a template repo but having a set of preferred libraries that harmonize with my coding style. In this post, I will introduce you to these libraries, sharing insights on their benefits and providing example code snippets to illustrate their ease of use. I encourage you to explore the extended documentation linked to understand each library’s full scope and capabilities.

  • kong

    Kong allows me to parse arguments into a struct, providing features like passing state to the executing command and supporting various arguments. Its command patterns facilitate the use of global options passed to subcommands.

    package main
    
    type CLI struct {
      Filename *os.File `help:"the filename to write"`
      Write    bool     `help:"write something to the file"`
    }
    
    func (c *CLI) Run() error {
      if c.Write {
        _, err := c.Filename.Write([]byte("Hello World"))
        return err
      }
      return nil
    }
    
    func main() {
      cli := &builder.CLI{}
      ctx := kong.Parse(cli)
      err := ctx.Run()
      ctx.FatalIfErrorf(err)
    }
    
  • req

    While Go does offer a HTTP client in its standard library, req eliminates the boilerplate that comes with it. It features middleware extension, a retry mechanism, and excellent defaults, such as timeouts, providing transparency in HTTP requests through its dead mode.

    package main
    
    import (
      "fmt"
      "github.com/imroc/req/v3"
    )
    
    func main() {
      client := req.C()
      resp, err := client.R().
        SetRetryCount(3).
        Get("https://httpbin.org/uuid")
      if err != nil {
        log.Fatal(err)
      }
      fmt.Println(resp)
    }
    
  • echo

    Its ability to handle routing and extend middleware, is invaluable for those coming from a full-stack background. It resembles Sinatra in Ruby and provides a meticulously documented, excellent routing system.

    package main
    
    import (
      "github.com/labstack/echo/v4"
    )
    
    func main() {
      e := echo.New()
      e.GET("/hello", hello)
      e.Logger.Fatal(e.Start(":1323"))
    }
    
    func hello(c echo.Context) error {
      return c.String(http.StatusOK, "Hello, World!")
    }
    
  • worker

    This is my own creation to manage go routine pools and streamline parallel work, reducing the repetitive coding in starting a routine and having a sync wait group. It offers configurable go routines and a buffer channel to queue the work onto.

    package main
    
    import (
      "github.com/jtarchie/worker"
    )
    
    func main() {
      pool := worker.New[int](10, 10, func(index, value int) {
        // Processing in the background here with the value
      })
      defer pool.Close()
    
      for i := 0; i < 100_000; i++ {
        w.Enqueue(i)
      }
    }
    
  • sqlite3 driver

    SQLite integrates seamlessly and is robust, offering a reliable database schema and validation. Despite utilizing CGO, its seamless operation and built-in full text search make it indispensable.

    package main
    
    import (
        "database/sql"
        "fmt"
        "log"
        _ "github.com/mattn/go-sqlite3"
    )
    
    func main() {
        db, err := sql.Open("sqlite3", "./test.db")
        if err != nil {
            log.Fatal(err)
        }
        defer db.Close()
    
        statement, _ := db.Prepare("CREATE TABLE IF NOT EXISTS people (id INTEGER PRIMARY KEY, firstname TEXT, lastname TEXT)")
        statement.Exec()
    
        res, _ := db.Exec("INSERT INTO people (firstname, lastname) VALUES (?, ?)", "John", "Doe")
        id, _ := res.LastInsertId()
        fmt.Println("Inserted Row ID:", id)
    }
    
  • ginkgo

    Ginkgo offers a structured, BDD-style TDD framework. It’s readable and, combined with gomega, provides powerful assertion capabilities.

    package main_test
    
    import (
        . "github.com/onsi/ginkgo"
        . "github.com/onsi/gomega"
    )
    
    var _ = Describe("Calculator", func() {
        Context("Addition", func() {
            It("should add two numbers", func() {
                Expect(1 + 1).To(Equal(2))
            })
        })
    })
    
  • golangci-lint

    This tool has significantly streamlined my coding process, GolangCI-Lint. My go-to tool for all things linting. GolangCI-Lint doesn’t just stop at identifying issues; it extends its utility by offering auto-fixes for numerous detected problems, a feature that has proven invaluable time and again.

    Here’s a peek at my default configuration:

    run:
      skip-files: []
    linters:
      enable-all: true
      disable:
      - depguard
      - exhaustruct
      - paralleltest
      - gomoddirectives
      - lll
      # linters deprecated
      - deadcode
      - exhaustivestruct
      - golint
      - ifshort
      - interfacer
      - nosnakecase
      - maligned
      - scopelint
      - structcheck
      - varcheck
    

    In this configuration, I’ve activated most linters while deactivating a few that didn’t align well with my preferences. One particular linter, errcheck, stands out for its utility. It ensures that all returned errors are aptly checked with if err != nil {}, helping maintain the codebase’s robustness.

  • lo

    This is a utility library for managing different data types in Go. It uses generics, providing functions similar to those in Ruby’s enumerable library.

    package main
    
    import (
      "fmt"
      "github.com/samber/lo"
    )
    
    func main() {
      slice := []int{1, 2, 3, 4}
      mappedSlice := lo.Map(slice, func(i int) int {
        return i * 10
      })
    
      fmt.Println(mappedSlice) // Prints: [10 20 30 40]
    }
    
  • log/slog

    This structured logger is a recent addition to the Go standard library, offering message and parameter logging with exceptional JSON output, enhancing the coding experience by providing structured, understandable logs.

I am grateful to the developers behind these incredible libraries for their contribution to the Go community, making the developer experience more pleasant and efficient.

Having a preferred set of libraries that align with your coding style can significantly enhance your coding experience, streamline your workflow, and increase productivity. Each library mentioned has its unique offerings and aids in creating efficient and clean code. Whether you are a seasoned developer or a beginner exploring the Go programming landscape, I hope you find these libraries as helpful as I have.