Skip to content

Harmelodic/init-microservice-go

Repository files navigation

init-microservice-go

I'm mostly from a Java background, so you can find most of my development/design thinking in init-microservice.

However, a bunch of the world now is built in other languages. For me, Go and Rust are the other languages that I would consider using to develop services.

This repo represents a frame for how I'd go about building services in Go.

Showcases

Project configuration:

Application configuration:

  • Dependency Injection (Plain old root DI, could have used go.uber.org/fx)
  • Application Configuration (CLI + Flags with urfave/cli, could have used spf13/cobra or spf13/viper)
  • Being a web service (gin, could have used net/http or chi)
  • Unit Testing (Built-in Go Unit Testing + stretchr/testify)
  • Logging Config (Built-in slog, could have used go.uber.org/zap?)
  • Tracing configuration (OpenTelemetry)
  • Metrics configuration (OpenTelemetry + Prometheus Registry/Endpoint)
  • Health checks (Custom Liveness and Readiness endpoints)
  • Database migration deployments (golang-migrate/migrate)
    • Migrations are numbered by timestamp (yyyymmddhhMM) to keep them ordered, prevent migration collisions from libraries that also do migrations, and provide a little context to when the migration was written.

Build / CI:

  • Test & Build automation (Make, GitHub Actions)
  • Uses reusable workflows for ease of CI maintenance.
  • Go Project + Container image specific build process:
    • Lint/Scan/Generate Go code (Go CLIs + golangci-lint)
      • go mod verify - Ensures dependencies haven't been modified since last downloaded.
      • go mod tidy (no diff) - Fixes go.mod file to meet requirements for building module (should always be the case)
      • go fmt (no diff) - Formats the code according to Go canonical style (should always be the case)
      • go vet - Lints the code for common Go mistakes, etc.
      • golangci-lint - Run more linters to lint the code.
      • go generate (no diff) - Run //go:generate scripts to ensure up-to-date generations exist (should always be the case)
    • Testing (go test).
    • Compilation with (go build).
    • Automated publishing of Contract Testing Contracts and Results (PACT Broker, ???)
    • Packaging and pushing a container image (Dockerfile)

Deployment / CD:

  • Not covered, but would use Kubernetes Deployment (or Argo Rollout, or similar)
  • Expected that an external CD system would deploy to Kubernetes (e.g. Argo CD)
  • See init-microservice for examples.

Infrastructure as Code:

  • Not covered, but would use Terraform
  • Expected that an external CD system would apply Terraform (e.g. Atlantis)
  • See init-microservice for examples.

Reference implementation examples (production):

  • Application Structure Example (account)
    • Reasonably decoupled layers/components
    • Domain-driven
    • Scoped explicit exception handling
    • Simple reusable model, mapping done in layers (if needed)
    • Dependency Injection used
    • Basic CRUD (as other implementations covered in other reference implementations)
  • DB Client (sqlx)
    • Could have used database/sql but sqlx had built-in struct marshalling/row mapping.
    • Could have used SQLC but compiling & generating a client from SQL is needless complexity.
    • Could have used GORM but I don't like ORMs.
  • HTTP Client (Built-in net/http?)

Reference implementations (testing):

  • Provider Contract Testing the Controller (PACT)
  • Consumer Contract Testing the HTTP Client (PACT)
  • Integration Testing the Repository (Testcontainers)
  • Integration Testing the Event Publisher (Testcontainers)
  • Integration Testing the Event Subscriber (Testcontainers)

Documentation

Uses mkdocs to handle documentation, which requires Python (hence the requirements.txt).

Run docs locally by doing:

python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
mkdocs serve

Then open at http://localhost:8000

Local development

Prerequisites:

  • Go is installed
  • golangci-lint is installed

Running tests

make test

Building an executable

make build
# or just
make

Running the app

go run ./internal
# or
make build && ./app

About

How I build microservices (in Go).

Topics

Resources

License

Stars

Watchers

Forks

Contributors 2

  •  
  •