GoLang Development Guidelines
Welcome to the GoLang Development Guidelines! This document is here to help you write Go code that is clean, efficient, and doesn't make future-you cry.
Coding Best Practices
Formatting & Readability
Go has zero tolerance for messy code, and so should you. Since we already use go vet to verify the code quality there is no need for extra tools. If you want to check if your code is fine, just run
go vet ./...
Error Handling
-
Don't panic (literally, avoid
panic()
).- Runtime: Never use
panic()
as a form of error handling; opt for explicit error returns. - Startup: A controlled panic may be acceptable during initialization if a critical component fails and the application shouldn't start without it
- Runtime: Never use
-
Always return errors properly because Go is all about explicitness.
- This ensures all error paths are handled clearly instead of being obscured by unexpected panics.
-
Wrap errors so you know where they came from, instead of playing detective.
- Use error wrapping to attach context to errors, making later debugging straightforward.
-
Early fail.
- Check and handle errors immediately after they occur to prevent cascading failures and unintended state.
Dependency Management
- Use Go Modules (
go mod init project-name
). - Run
go mod tidy
often—nobody likes unused imports.
Try to avoid reflection
So you should still think about what you are doing, but in Go try to avoid reflections as much as possible. If there is a way to do stuff without reflections, do it without.
REST API Development
If you're building a REST API, please don’t reinvent the wheel. Follow these simple rules:
✅ Use a router – chi
or gin
(they make your life easier).
✅ Middleware – Logging, auth, rate limiting—don't let rogue users take down your app.
✅ Versioning – /v1/resource
so future-you can introduce breaking changes with dignity.
✅ Pagination – Don't return 1 million records in one go. Seriously.
r := chi.NewRouter()
r.Get("/users/{id}", getUserHandler)
http.ListenAndServe(":8080", r)
Concurrency in Go (a.k.a. The Power of Goroutines)
Goroutines are super cool, but use them wisely:
- Don't spawn goroutines like popcorn without managing them.
- Use sync.WaitGroup to keep things organized.
- Always use context.Context to avoid runaway goroutines.
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
go func() {
select {
case <-ctx.Done():
fmt.Println("Operation timed out")
}
}()
Testing & CI/CD
Even if you don't like writing tests, its required in Vyndara. Due to our auto deployments we can't just push stuff to production without proper tests.
Read more about overall testing guidelines here
Test Library
For go libraries or applications use our base Go testing library with:
go install github.com/Arematics/go-tests
What that library provides you can find in the README of this project at: https://github.com/Arematics/go-tests
If you need to do any changes to that library keep in mind, its open source
Running tests
How to run tests is up to each team/repository but should always stick to the testing guidelines. Most repositories will provide more about how to run tests our write them in their README file or own documentation.
Test Coverage
Projects should be covered as much as possible. The goal is to have a test coverage of 90% in every project. Find out more about our test coverage in SonarCloud at: https://sonarcloud.io/organizations/arematics/projects
Recommended Tools 🛠
- Code Formatting –
gofmt
,golangci-lint
- Testing –
testify
,gomock
- Logging –
log/slog
,zerolog
- Observability –
Prometheus
,OpenTelemetry
- Containerization –
Docker
,Kubernetes
Conclusion
If you follow these guidelines, your Go code will be cleaner, faster, and less likely to cause rage-quits.
Remember: Write code that future-you (and your teammates) will thank you for!
Now go forth and build awesome things with Go! 🦫💨