Modern Go Application example

Overview

Modern Go Application

Mentioned in Awesome Go Go Report Card go.dev reference

GitHub Workflow Status CircleCI Gitlab

Go application boilerplate and example applying modern practices

This repository tries to collect the best practices of application development using Go language. In addition to the language specific details, it also implements various language independent practices.

Some of the areas Modern Go Application touches:

  • architecture
  • package structure
  • building the application
  • testing
  • configuration
  • running the application (eg. in Docker)
  • developer environment/experience
  • telemetry

To help adopting these practices, this repository also serves as a boilerplate for new applications.

Features

First steps

To create a new application from the boilerplate clone this repository (if you haven't done already) into your GOPATH then execute the following:

chmod +x init.sh && ./init.sh
? Package name (github.com/sagikazarmark/modern-go-application)
? Project name (modern-go-application)
? Binary name (modern-go-application)
? Service name (modern-go-application)
? Friendly service name (Modern Go Application)
? Update README (Y/n)
? Remove init script (y/N) y

It updates every import path and name in the repository to your project's values. Review and commit the changes.

Load generation

To test or demonstrate the application it comes with a simple load generation tool. You can use it to test the example endpoints and generate some load (for example in order to fill dashboards with data).

Follow the instructions in etc/loadgen.

Inspiration

See INSPIRATION.md for links to articles, projects, code examples that somehow inspired me while working on this project.

License

The MIT License (MIT). Please see License File for more information.

Comments
  • Some violations of CodeReviewComments

    Some violations of CodeReviewComments

    1. Repeatation
      • Package helloworld contains a function NewHelloWorld.
      • So the client would initialize the HelloWorld type as helloworld.NewHelloWorld which is simply repeatation of the fact that helloworld package contains a HelloWorld and is not recommended Package Names
      • This should instead be helloworld.New()
    2. Interfaces
      • Package helloworld contains an interface HelloWorld and function NewHelloWorld returns this interface type instead of concrete type. Interfaces on implementor side as an abstraction has no meaning
      • Package helloworld should contain a concrete type HelloWorld which is returned by helloworld.New function as recommended here
      • Clients who need to use features of HelloWorld type can define interfaces with only the features they really need and inject instance of HelloWorld as an implementation.
    opened by spy16 17
  • Windows support

    Windows support

    This PR allows applications to run on Windows.

    The application will not support graceful restart, since TableFlip doesn't have Windows support, but it is still adequate for users who use Windows machines for development and Linux for production.

    It extracts the tableflip code into internal/platform/reloader with conditional compilation depending on which platform is being used.

    I have not finished testing it yet, but I wanted to get it out here to see if you want any changes to it.

    opened by kohenkatz 6
  • Logo Proposal for go service project boilerplate

    Logo Proposal for go service project boilerplate

    Hi @sagikazarmark I am an open source enthusiast and I am looking to expand my work portfolio. I would like to collaborate with your project for free, I can provide you with a logo for your project

    Good day Skull C.

    opened by candyskull920 6
  • How to use OpenAPI

    How to use OpenAPI

    There is a folder .gen/api/openapi with generated code. I do not see it's used somewhere. What it is for? Could you please suggest a way how to use it ?

    opened by atomicleads 4
  • [Makefile] Support reproducible builds

    [Makefile] Support reproducible builds

    Embedding build times is generally poor form as it introduces undeterministic builds. To ensure the binaries are reproducible, we should be looking for SOURCE_DATE_EPOCH in the build environment as specified by the reproducible builds project.

    https://reproducible-builds.org/docs/source-date-epoch/

    opened by Foxboron 3
  • Is there any tutorial or more detailed document for gokit beginner?

    Is there any tutorial or more detailed document for gokit beginner?

    Thanks for this awesome project.

    Before I came into this project, I have no experience of gokit. I want to use this project to learn gokit and start my first gokit project. Is there any tutorial or more detailed document for gokit beginner to do things like steps of creating new service etc.

    Best regards.

    opened by leopku 3
  • Make sure that application imports are always in a separate group

    Make sure that application imports are always in a separate group

    When running the init script in the boilerplate, import name might break alphabetical order.

    This has been fixed for now in #50 , but we should make sure it continues to work in the future as well.

    • [x] Check IDE settings
    • [x] Write some test/lint rule?
    opened by sagikazarmark 3
  • Sync dependencies fails

    Sync dependencies fails

    The application was generated with

    ? Package name (/home/dima/develop/go-app1) github.com/dmdv/go-app1
    ? Project name (go-app1) 
    ? Binary name (go-app1) 
    ? Application name (go-app1) 
    ? Friendly application name (Go App1) Modern Go Application
    ? Update README (Y/n) Y
    ? Remove init script (y/N) n
    

    When I tried to sync dependencies, I got the following error

    go: finding module for package github.com/dmdv/go-app1/internal/app/go-app1
    go: finding module for package github.com/dmdv/go-app1/internal/app/go-app1/todo/tododriver
    github.com/dmdv/go-app1/cmd/go-app1 imports
    	github.com/dmdv/go-app1/internal/app/go-app1: no matching versions for query "latest"
    github.com/dmdv/go-app1/cmd/go-app1 imports
    	github.com/dmdv/go-app1/internal/app/go-app1/todo/tododriver: no matching versions for query "latest"
    github.com/dmdv/go-app1/internal/app/mga imports
    	github.com/sagikazarmark/todobackend-go-kit/todo/tododriver imports
    	github.com/sagikazarmark/todobackend-go-kit/internal/.generated/api/v1/graphql: malformed import path "github.com/sagikazarmark/todobackend-go-kit/internal/.generated/api/v1/graphql": leading dot in path element
    github.com/dmdv/go-app1/internal/app/mga imports
    	github.com/sagikazarmark/todobackend-go-kit/todo/tododriver imports
    	github.com/sagikazarmark/todobackend-go-kit/internal/.generated/api/v1/rest/go: malformed import path "github.com/sagikazarmark/todobackend-go-kit/internal/.generated/api/v1/rest/go": leading dot in path element
    

    image

    And script generation completed with an error

    image

    The overall impression is that the template has never been tested and too much stuffed with the extra unnecessary functionality

    opened by Dmdv 2
  • The name of the jaeger collectorendpoint environment variable is wrong

    The name of the jaeger collectorendpoint environment variable is wrong

    The above mentioned configuration needs to be changed either in the jaeger config or the environment variable so that viper properly unmarshalls it into the application configuration ( Field name in the Config struct: CollectorEndpoint, env var name: v.SetDefault("instrumentation.jaeger.endpoint", "http://localhost:14268")

    I am happy to push the PR if this is valid ...

    opened by lpuskas 1
  • Bump github.com/cloudflare/tableflip from 1.2.0 to 1.2.1

    Bump github.com/cloudflare/tableflip from 1.2.0 to 1.2.1

    Bumps github.com/cloudflare/tableflip from 1.2.0 to 1.2.1.

    Release notes

    Sourced from github.com/cloudflare/tableflip's releases.

    Fix clearing O_NONBLOCK on upgrade

    The Go runtime has annoying behaviour around setting and clearing O_NONBLOCK: exec.Cmd.Start() ends up calling os.File.Fd() for any file in exec.Cmd.ExtraFiles. os.File.Fd() disables both the use of the runtime poller for the file and clears O_NONBLOCK from the underlying open file descriptor.

    This can lead to goroutines hanging in a parent process, after at least one failed upgrade. The bug manifests by goroutines which rely on either a deadline or interruption via Close() to be unblocked being stuck in read or accept like syscalls,. As far as I can tell we've not experienced this problem in production, so it's most likely quite rare.

    Commits
    • cae714b ensure that inherited files are nonblocking
    • 57f992b require Go 1.14
    • 5f43f42 remove go 1.12 compatibility
    • 4b4e680 migrate to github actions
    • 77aba94 Refactor some methods to take advantage of the new *WithCallback methods
    • 40abd35 Allow opening connection with callbacks
    • 4baec98 Add ListenConfig as Option to Upgrader
    • See full diff in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Suggestion: add build automation/ tooling

    Suggestion: add build automation/ tooling

    I love using https://github.com/ldez/seihon for multi-arch docker builds. Adding https://goreleaser.com might be another addition, though both are on the build, less on the code side. And golangci-lint and...

    opened by andig 2
  • configFileNotFound bug?

    configFileNotFound bug?

    I was just reviewing the code, and I found a part that looks a little suspect..

    https://github.com/sagikazarmark/modern-go-application/blob/master/cmd/modern-go-application/main.go?ts=4#L89

    if ReadInConfig does not return an error, then configFileNotFound would be false, right? since the type assert from nil to viper.ConfigFileNotFoundError would fail?

    err := v.ReadInConfig()
    _, configFileNotFound := err.(viper.ConfigFileNotFoundError)
    if !configFileNotFound {
    	emperror.Panic(errors.Wrap(err, "failed to read configuration"))
    }
    
    # more stuff, including configuring the logger
    
    if configFileNotFound {
    	logger.Warn("configuration file not found")
    }
    

    it seems like the code will either always panic, or log a warning.

    The viper shows the correct way: https://github.com/spf13/viper?ts=4#reading-config-files

    if err := viper.ReadInConfig(); err != nil {
        if _, ok := err.(viper.ConfigFileNotFoundError); ok {
            // Config file not found; ignore error if desired
        } else {
            // Config file was found but another error was produced
        }
    }
    
    // Config file found and successfully parsed
    

    Additionally, I don't think this is best practice anyway, since a configuration file should not be required if ENV variables are also an alternative. Maybe I'm also reading the code wrong...

    opened by ghostsquad 3
  • Road to 1.0?

    Road to 1.0?

    This project is a great sandbox for trying out new practices, as well as a great boilerplate for new projects.

    As for trying practices, it probably reached a point where the project is "ready", meaning adding new stuff would make it too heavy. Additional service integrations (config) should go into documentation / wiki / website.

    Using the project as a boilerplate is not too easy, so this is what I would like to focus on next.

    One of the issues is lacking documentation as pointed out in #130.

    The other issue is the lack of tooling (code generation, scaffolding).

    This is getting better every day in https://github.com/sagikazarmark/mga (especially code generation), but starting a new project is still too hard. So the next step should be a mga new command that creates a new project from the boilerplate. (And we can finally get rid of the crappy init.sh)

    Last, but not least we need a better organization of the underlying projects. Right now the boilerplate relies on a few, loosely coupled projects under my account. They need better organization (probably an organization of their own).

    Go Buffalo is an excellent example of what I would like to (ideally) achieve with this project.

    opened by sagikazarmark 0
Releases(0.3.0-dev.3)
Owner
Márk Sági-Kazár
Open Source enthusiast, Go package author and maintainer (@dexidp, @emperror, @logur, @spf13/viper). Currently hacking Kubernetes at @banzaicloud.
Márk Sági-Kazár
A set of example golang code to start learning Go

Working with Go View online at: https://mkaz.blog/working-with-go/ Working with Go is a set of examples for Go (golang) to help an experienced program

Marcus Kazmierczak 1.2k Nov 21, 2022
Go application GitHub repository template.

Go Repository Template This is a GitHub repository template for Go. It has been created for ease-of-use for anyone who wants to: quickly get into Go w

Go Repository Templates 347 Nov 18, 2022
This application is used as an example HTTP/SQLite application for Litestream tutorials.

This application is used as an example HTTP/SQLite application for Litestream tutorials. It simply maintains a count of HTTP requests and persists it to a SQLite database.

Ben Johnson 12 Apr 2, 2022
Write your SQL queries in raw files with all benefits of modern IDEs, use them in an easy way inside your application with all the profit of compile time constants

About qry is a general purpose library for storing your raw database queries in .sql files with all benefits of modern IDEs, instead of strings and co

Sergey Treinis 25 Nov 5, 2022
Search and store the best cryptos for the best scalable and modern application development.

Invst Hunt Search and store the best cryptos for the best scalable and modern application development. Layout Creating... Project Challenge The Techni

Fábio Morais 1 Nov 12, 2021
Osin-example - Example of a identity provider powered by OAuth 2.0 in Golang

go mod init github.com/bartmika/osin-example go get github.com/google/uuid go get github.com/rs/cors go get github.com/spf13/cobra go get github.com/g

Bartlomiej Mika 0 Jan 5, 2022
Go.work-workspace-example - Go1.18 workspace example

Go.work-workspace-example - Go1.18 workspace example

Andrey Burov 0 Jan 20, 2022
This example implements a basic example of how to create your own modules, and how to call them from other modules

This example implements a basic example of how to create your own modules, and how to call them from other modules. In addition, an example of how to do unit tests is developed.

null 1 Feb 1, 2022
Pulumi-k8s-operator-example - OpenGitOps Compliant Pulumi Kubernetes Operator Example

Pulumi GitOps Example OpenGitOps Compliant Pulumi Kubernetes Operator Example Pr

Christian Hernandez 3 May 6, 2022
Example repository for embedding Litestream in a Go application.

Litestream as Library This repository is an example of embedding Litestream as a library in a Go application. The Litestream API is not stable so you

Ben Johnson 39 Nov 15, 2022
An example desktop system tray application that can launch HTML5 windows. Go source with a build process for Windows, Mac and Linux.

ExampleTrayGUI An example cross-platform (Mac, Windows, Linux) system tray application that can launch HTML5 windows, developed in Go including functi

Grant Moore 50 Oct 9, 2022
An example desktop system tray application that can launch HTML5 windows. Go source with a build process for Windows, Mac and Linux.

ExampleTrayGUI An example cross-platform (Mac, Windows, Linux) system tray application that can launch HTML5 windows, developed in Go including functi

Grant Moore 50 Oct 9, 2022
An example desktop system tray application that can launch HTML5 windows. Go source with a build process for Windows, Mac and Linux.

An example cross-platform (Mac, Windows, Linux) system tray application that can launch HTML5 windows, developed in Go including functional build process. This repository is intended as a quick reference to help others start similar projects using the referenced libraries and will not be actively maintained.

Grant Moore 50 Oct 9, 2022
Example used to try a compose application with Docker Dev Environments

compose-dev-env Example used to try a Compose application with Docker Dev Environments. This example is based on the nginx-golang-mysql sample of awes

Docker Samples 88 Nov 15, 2022
Example instrumentation of Golang Application with OpenTelemetry with supported configurations to export to Sentry.

Sentry + Opentelemetry Go Example Requirements To run this example, you will need a kubernetes cluster. This example has been tried and tested on Mini

Uddeshya Singh 11 Oct 27, 2022
Example mini project golang scanner application

Golang Scanner Contoh pembuatan aplikasi Java menggunakan BlueJ cek disini, tetapi berikut ini adalah versi rebuild dari Java ke Golang, dengan menggu

Restu Wahyu Saputra 5 Jun 1, 2022
An example event-driven application using Atmo and NATS

Atmo + NATS Example Project This repo is an example of using Atmo with NATS as a streaming messaging layer. In this example, Atmo connects to NATS and

Connor Hicks 2 Oct 27, 2021
A quick introduction to how Apache Kafka works and differs from other messaging systems using an example application.

Apache Kafka in 6 minutes A quick introduction to how Apache Kafka works and differs from other messaging systems using an example application. In thi

bagher sohrabi 2 Oct 27, 2021
A web application example to work with a customer object

Wallester Task This repository contains a web application example to work with a customer object. Build in GO version 1.17.1 Live running app example

null 0 Oct 25, 2021
An example desktop system tray application that can launch HTML5 windows. Go source with a build process for Windows, Mac and Linux.

ExampleTrayGUI An example cross-platform (Mac, Windows, Linux) system tray application that can launch HTML5 windows, developed in Go including functi

Owen Moore 50 Oct 9, 2022