Start your first Go project
Marco Franssen

Loading...
Marco Franssen

A couple of months ago, I started coding in Go, also known as Golang. Not just because it has an awesome logo ;-). I wanted something that ran as close to bare metal as possible on my Raspberry Pi, with executables that were easy to install on different platforms. I was also drawn to asynchronous code using Go in front of functions and the channel-based approach to coordinating goroutines. I'd been reading about Go since its release in 2012, but it was time to get my hands dirty and try it myself. In this post, we'll set up a first project, write tests, and compile it for different platforms.
Curious? Keep reading…
Go is an open-source programming language that makes it easy to build simple, reliable, and efficient software. It originated at Google and was one of the fastest-growing and most widely adopted programming languages of 2018. Go was first released in March 2012. The recent Go 1.11 release added module support, making dependency management more convenient.
First, we need to set up our development environment. As you might have noticed in the bonus section of my last article, I use Chocolatey to install my tooling easily.
On Windows, we'll use Chocolatey in PowerShell to install Go and vscode.
cinst -y go vscodeWith Go and vscode installed, we have everything we need to get started.
I prefer Git Bash for the rest of my scripting, so I run the following Visual Studio Code command from there to install the Go extension. You can also install the extension from Visual Studio Code itself.
code --install-extension ms-vscode.goWith the Go extension installed in Visual Studio Code, we have everything in place for a nice coding experience.
You can find Go's documentation here and the standard library packages available to your Go programs here. There's also an online playground where you can experiment or share examples with a fellow programmer.
To start a Go project, create an empty folder. Then run go modules init in that folder to initialize Go modules, which we'll use to manage our dependencies. The commands are shown below.
mkdir hello-world
cd hello-world
go mod init github.com/marcofranssen/hello-worldIn Go we define a function using the func keyword.
func main() {
// our code
}The closest thing Go has to a class from other languages is a struct. You can define one like this.
type Envelope struct {
Message string
}In Go, variables, functions, and structs whose names start with an uppercase letter are exported. Those starting with a lowercase letter are private to the package. Types come after variable names, as you may have noticed in the struct example above. To import another package, put an import statement near the top of the file. Finally, every executable Go program needs a main package.
package main
import "fmt"
func SayHi(person string) string { //public function
return fmt.Sprintf("Hi %s", person)
}
func sayHi(person string) string { //private function
return fmt.Sprintf("Hi %s", person)
}The fmt package provides handy string formatting functions, which let you build strings from variables. Notice that the function's return type comes after its parameters. For more details on the fmt package, see the documentation.
Now that we have an empty project and know a bit about the syntax, let's open the folder in vscode.
code .First, add a file called main.go to the folder. Then let's add some of the code we discussed above.
package main
import "fmt"
func main() {
fmt.Println(sayHi("Marco"))
}
func sayHi(person string) string {
return fmt.Sprintf("Hi %s", person)
}With this code in place, we can run the application from the command line.
go run main.goYou can also test it out in the Go playground.
To add tests in Go, create a file called main_test.go. In it, we can add a function to test our sayHi method. Test functions must use the signature TestXxx(t *testing.T), where the first X is uppercase.
package main
import "testing"
func TestSayHi(t *testing.T) {
expected := "Hi Marco"
greeting := sayHi("Marco")
if greeting != expected {
t.Errorf("Greeting was incorrect, got: '%s', want: '%s'", greeting, expected)
}
}We've covered a few new things here. We use the shorthand := to declare a variable and assign its value. If the sayHi function doesn't return what we expect, the test reports an error with a clear message.
To run the test, use the following command. I use ./... to run tests in all packages and subfolders of the project.
go test ./...Try changing the implementation and running the test again to see it fail. To measure code coverage, run the tests like this.
go test -coverage -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.htmlFor more information, check the testing package documentation.
The easiest way to build an executable is with the following commands.
go build .
./hello-world.exeSince we're on Windows, this creates a Windows executable. Run it to see the same result as with go run main.go. To get more verbose output and see what's happening behind the scenes, use the -x option with go build. But how do we compile the same code for Linux or a Raspberry Pi?
GOOS=linux GOARCH=amd64 go build .To run this binary on Linux, don't forget to use chmod +x, then launch it with ./hello-world.
A Raspberry Pi 3 uses the ARM v7 architecture, so we can compile for it like this. Note that we can do all of this from our Windows machine.
GOOS=linux GOARCH=arm GOARM=7 go build .Run the binary as you would on any other Linux machine: use chmod +x, then ./hello-world to launch the application.
I know this application is super simple and not very useful, but you now have a development environment set up and some hands-on experience writing Go. You also know how to test your code, which is a good basis for writing high-quality software. I'll save the cooler stuff, like go routines, for another post, as we'll also need to cover channels.
Finally, take a look at my first application in Go: an integration with the Nest thermostat that runs on my Raspberry Pi. It collects temperature data and plots it in a React web application. Don't forget to sign up for the Gophers Slack workspace too.
Feel free to ask questions or leave feedback in the comments.
Marco Franssen
Explore Go concurrency with practical goroutine and channel examples, including buffered channels, GOMAXPROCS, and the difference between concurrency and parallelism.
Marco Franssen
Explore Go's defer with practical examples of execution order, panic and recover, recursive calls, and closing a file after reading its contents.
Marco Franssen
Find your Ethernet driver, add it to a Windows 10 PE image with DISM, and start Windows setup from a network share on a laptop without an optical drive.
Marco Franssen
Combine separate Git repositories into a multi-module Gradle project while preserving commit history, then consolidate build and CI configuration.