/goat

🐐

Primary LanguageGo

🐐

👀 Lint 🛶 Dev 🛶 Prod

🐳 Docker things

We're using multi-stage-builds here to trim the crap out of the final artifact.

  1. dev - this stage is used for local development.
  • docker build --target dev --tag goat:dev && docker run --env PORT=9000 goat:dev
  • docker-compose run goat
  • docker-compose up
  • make up

All do (appx) the same thing:

  • create a dev image with a code mounted volume
  • runs container with cmd air.
  1. prod - this stage is used for deployment.

It takes the built binary from dev and puts it in a minimal alpine image. That's it.

📁 Interesting files

.air.conf

https://github.com/cosmtrek/air

Live reloading configuration for Go apps.

.golangci.yml

Master linter for Golang. Runs a lot of checks right now which I thought might be helpful. If it becomes to opinionated we can tone down the settings in this file.

Makefile

  • up
  • shell

Go stuff

main.go is always the main entrypoint in Go, it exists by itself, has the line package main in it, and has a single func main() defined.

Dependencies

This service uses FX as the dependency injection framework. Convention is packages that are wrapped in FX-compatible packages are suffixed with fx. For example, I wrapped the zap package in an FX compatible package and called it zapfx (same with envfx).

FX compatible packages have a single file called module.go, in which, a single exported variable called Module is defined. This allows very clean dependency management in main.go:

app := fx.New(
    zapfx.Module,
    envfx.Module,
    ...
)

Dependencies added to the app lifecycle are long-lived, which means they are shared by all requests concurrently. This is very good use of resources, but means you should be careful about dependency-owned variables, and keep anything dangerous allocated in thread scope (just make new stuff in the function call and everything will be ok).

Logging

The logging framework we use here is zap. It is purpose built for structured backend logging which allows it to be not magical, thus fast.

Linting / Formatting

golangci-lint is an awesome meta linter, if a lint rule is obnoxious, you can find examples of how to ignore it in [./.golangci.yml].

Use goimports -local github.com/banditml ./... to format the source code.

Other nice things

I really like pretty formatting, if you do too:

brew tap kyoh86/tap
brew install richgo

then replace every go command with richgo, like:

richgo test ./...