Go Learning Resources
Tags: go, learning
Published: 2023-01-24 15:53:52

---
title: Go Learning Resources
published: true
date: 2017-08-07 00:00:00 UTC
tags: golang, go, learning
canonical_url: https://www.rocky.dev/go-learning-resources
---

I've only dabbled with Go in my spare time, but compiled this list of resources I found helpful.

## Getting Started

- Take [A Tour of Go](https://go.dev/tour/welcome/1)
- `brew update && brew install golang`
- Install the extension for [VS Code](https://github.com/golang/vscode-go)
  - Add these to your User Settings (⌘ + ,):

```json
"go.testOnSave": true,
"go.coverOnSave": true,
"go.addTags": {
  "tags": "json",
  "options": "json=omitempty",
  "promptForTags": false,
  "transform": "camelcase"
}
```

- Work through [How to Write Go Code](https://go.dev/doc/code)
- Fall in love with the tooling, watch [Go Tooling in Action](https://www.youtube.com/watch?v=uBjoTxosSys)
- Take a codewalk written by the creators, [First-Class Functions in Go](https://go.dev/doc/codewalk/functions/)

## First impressions

### Pros

- ⚡ Feedback cycle is fast, feels like a dynamic language
- 🔨 Tooling is excellent, [here's what I mean](https://go.dev/blog/cover)
- 🤓 Encourages you to look at source code since it's all pulled down, which is an excellent way to learn new tricks
- 📖 Automatic, simple, offline documentation with `godoc`. It can even have [testable examples](https://go.dev/blog/examples)! More info, [Godoc](https://go.dev/blog/godoc)
- 📏 In Scala, seemingly simple bits of code can be written many different ways. In code review, comments relate to formatting or refactoring into something easier to read. In Go, there's one way to code most things and one way to format, `gofmt`. Reviewers can concentrate on [other things](https://github.com/golang/go/wiki/CodeReviewComments#go-code-review-comments)

### Cons

- ❌ No generics ([here's why](https://go.dev/doc/faq#Why_doesnt_Go_have_feature_X)), though it's under consideration
- 😫 Mocking can get verbose
- 💣 `signal SIGSEGV: segmentation violation` brings back memories, painful memories
- 😭 `gofmt` uses tabs

## Dependency Injection

Create structs that define their dependencies as interfaces so they can be mocked in tests,

```go
type HTTPClient interface {
  Get(string) (*http.Response, error)
}

type Handler struct {
  Client HTTPClient
}

func (h *Handler) Handle(url string) (string, error) {
  res, err := h.Client.Get(url)
  ...
}
```

In `main()`,

```go
func main() {
  // http.Client from standard library implicitly satisfies HTTPClient interface
  handler := Handler{Client: &http.Client{}}
  ...
}
```

And in your test,

```go
type httpMock struct{}

// Satisfy HTTPClient interface, modify to return whatever you need
func (m *httpMock) Get(url string) (resp *http.Response, err error) {
  return &http.Response{}, nil
}

func TestGetError(t *testing.T) {
  handler := Handler{Client: &httpMock{}}
  ...
}
```

## Testing

Table-driven tests are common and made simple with existing Go constructs.

```go
func TestIsValidRtn(t *testing.T) {
  cases := map[string]struct {
    input string
    expected bool
  }{
    "zero value": {"", false},
    "< 9 digits": {"00000000", false},
    "valid": {"010000003", true},
  }

  for k, c := range cases {
    actual, _ := IsValidRtn(c.input)
    if actual != c.expected {
      t.Errorf("IsValidRtn(%q) == %v, expected %v. %v", c.input, actual, c.expected, k)
    }
  }
}
```

Even if you have one test case, consider writing it like this to easily add more later. More info, [Table Driven Tests](https://github.com/golang/go/wiki/TableDrivenTests), [Advanced Testing with Go](https://www.youtube.com/watch?v=yszygk1cpEc), [Testify](https://github.com/stretchr/testify).

## Errors

Always handle errors, do not ignore them,

```go
// 😎
result, err := couldReturnError()
if err != nil {
  ...
}

// 🙁
result, _ := couldReturnError()
```

If you're worried about code riddled with error checks, [read this](https://go.dev/blog/errors-are-values). Prefer errors over panics, [more info](https://go.dev/blog/defer-panic-and-recover)

## Channels

Identify separate pieces of work and compose their interactions with channels. Separating processes makes programs simple to follow and leads to better design. More info, [Pipelines](https://go.dev/blog/pipelines), [Concurrency Is Not Parallelism](https://www.youtube.com/watch?v=oV9rvDllKEg)

## Up your game

- The [Go Blog](https://go.dev/blog/all) has great articles in general, a few in particular follow
- [Arrays and Slices in Go](https://go.dev/blog/slices)
- [Strings, bytes, runes and characters in Go](https://go.dev/blog/strings)
- [Go Best Practices](https://peter.bourgon.org/go-best-practices-2016/)
- [Functional Options for Friendly APIs](https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis)
- [The Go Programming Language Specification](https://go.dev/ref/spec)
- [Effective Go](https://go.dev/doc/effective_go)