Getting started with Go.

The Go branding

Lately, it seems like Go (or sometimes, Golang) is having a bit of a moment.

Developed by Google, Go has been around for just over a decade now but over the last year it seems to have been steadily gaining in popularity on social media and Github. Given its versatility, It's perhaps easy to understand why - Go has been used for everything from CLI tools to building high-profile devops software like Docker and Kubernetes.

One thing that might be less immediately obvious though, is that Go is also equally well suited to building web apps and APIs. In fact, as a JavaScript (or TypeScript) developer, Go has a lot to love:

  • Simple syntax - Go was designed in a way that, once you know the core syntax, you should be able to read anyone's code. In fact, there's officially only one way to write Go code, and the excellent language tooling will keep you on the straight and narrow. There'll be no time wasted deciphering someone else's "clever" one-liners!
  • Statically-typed, compiled language - As with a language like TypeScript, typed variables mean that it's easier to manage bugs. The compiler does a lot of heavy lifting here too - you can't even compile your code if you have any unused variables knocking about in your codebase.
  • Asynchronous code and concurrency - Go was built with concurrency in mind and features 'go routines' to manage multi-threaded, asynchronous code
  • Cross-platform - The Go compiler allows you to build cross-platform applications which are easy to deploy pretty much anywhere. You don't need even to deploy your sourcecode, just the compiled binary.

As for me though, all of that stuff is kinda secondary.

You see, Go comes with a very powerful standard library (stdlib) that means that you can really do a lot without needing to reach for a framework. Coming into the language from the JS world, which often relies heavily on third-party packages from NPM, it can initially seem really counter-intuitive to be writing so much low-level code. On the contrary though, I've found that writing Go has led me to better understand certain concepts that other languages and frameworks such as Express or Rails have let me 'magic away' in the past.

The Go way of doing things feels very considered and deliberate; it makes me feel like I'm learning more deeply about how the web works in general, and I love that.

For me, writing Go is just – dare I say it – fun.

Let's build something. permalink

Ok, enough about why I like Go. If any of the above sounds appealing but you're not sure where to start, then this post is for you.

That said, this tutorial isn't intended for anyone who's already started writing Go - it's going to deliberately be very bare bones. For the sake of brevity, I also won't be spending much time covering core programming concepts too much. Prior to learning Go my primary language was JavaScript and I suspect that many of you who will be reading this will be somewhat familiar with that language. When I do make comparisons with other languages, it will be to JavaScript.

With all of that out of the way, let's go.

(I'm not even sorry for that pun)

Preparing to work with Go. permalink

Thankfully, getting set up for Go development is not as complicated as some other languages. Before we start, I'd suggest completing the following three steps:

  • If you're not already using it, I'd strongly recommend downloading and using VS code
  • Download and run the Go installer. At the time of writing the latest Go version is 1.16
  • Install the Go VS code extension to enable intellisense, auto-imports, linting and more.

Starting a Go project. permalink

If you've done any JS development, you're probably familiar with using third-party code from NPM.

Go uses the concept of packages in a similar way, but for quite a while Go didn't have an official means of managing project dependencies. Several package management solutions popped up to try and make development easier but, in my experience, having a wide range of package managers made things a lot more confusing.

Thankfully though, Go 1.13 introduced go modules as the de facto means of managing your application's dependencies. Coming from the JS world, Go modules uses the go mod command in a way that might be familiar.

Let's initialise a go modules project. Create a folder for your project and from the root open your terminal and run the go mod command, replacing <PACKAGENAME> with the desired project name:

go mod init <PACKAGENAME>

You can choose whatever you want for this name, but be aware that it needs to be unique.

Later on we'll be importing external packages, so we will need to make sure that our application's package name doesn't clash with any future dependencies. Understandably, seeing into the future is a big ask. To mitigate name-clashes there's a Go convention of using your project's github path or a website url as the package name.

Let's try it. You can use whichever name you want, but I might run something like:

go mod init robbowen.digital/go-intro

When the command has finished, we will now have a go.mod file in our project root. Inside, it will look a little something like this:

module robbowen.digital/go-intro

go 1.16

We don't need to worry about this too much for now, but this file specifies the name of our root module (our application) and the version of go that it requires. If you know JS, the go.mod file functions like a package.json.

Our first file, and the main package. permalink

Go uses the concept of packages to group code and all Go applications start with a package called main. You can think of it a bit like the entrypoint of a JS bundle - the main package runs first, and everything else branches out from there.

We can declare which package a particular file belongs to with the package keyword. Let's create a file in our project root called app.go. Inside the file, let's declare that this code belongs to main.

package main

The package declaration is the first step, but we will also need to tell the go compiler where our application actually starts. Inside of our main package, we will need to declare a function, also called main. Functions in Go look a lot like they do in JavaScript and use the func keyword.

In our app.go file, let's prepare a main function for our application.

package main

func main() {
// application code will go here
}

Nice, that's everything we need to get started.

At this point you might have noticed that we're not calling main() anywhere, and you'd be correct. Go will automatically call main() when our application runs. To see that in action we'll need to update our code so that it actually does something.

Let's write a message to the terminal. For that we're going to need to use the fmt a package from the Go standard library. The name fmt stands for format and, in case you were wondering how to say it out loud, is usually pronounced like "fumt". Inside of this package there's a handy function called Println that we can use to print a message to the console.

Let's update our main function:

package main

import (
"fmt"
)

func main() {
fmt.Println("Aw yiss")
}

If you're coding along in VS code, you might have noticed that you don't actually need to add that import line to the top of the file. Typing fmt. should prompt intellisense to show you the available functions and, whenever you save a Go file, VS Code's language server should automatically add all of the appropriate imports.

Let's build and run our application.

From your terminal, you can run your new program with

go run main.go

Hell yeah, you're now officially a Go developer 🎉

Variables and types. permalink

At the moment we've hardcoded that message, so let's move it to a variable.

Variable definition in Go will be familiar to a JS dev, and even moreso if you've dabbled with TypeScript:

var myString string = "Aw yiss"
var someNumber int32 = 37
var mmmPie float32 = 3.14159
var myBool bool
myBool = false

The var keyword followed by a name defines a new variable. Being a typed language, the variable's type definition comes next (there's a full list of the available types in the Go documentation).

Lastly, you're free to specific an initial value but Go is statically typed, so bear in mind that the type of a variable cannot change type.

var someNumber int32 = 37
// this won't work
someNumber = "thirty seven"

Shortform variables. permalink

Writing var and the type out every time you need a new variable can get a bit tedious, so Go also provides a handy shortform syntax. This shortform doesn't include a type definition and instead assigns a type by inference. If that last sentence meant nothing to you, don't worry. The shortform allows us to set a variable and let the compiler worry about what type it is.

message := "Aw yiss"

Most of the time, you're going to be using this syntax. There are two caveats to be aware of though: Firstly the := is only used when you first define a variable. Reassignment the value is done with =.

message := "Aw yiss"
message = "some new value"
// this won't work as the variable is already defined
message := "yet another value"

The second caveat is that the short syntax can only be used within a function. Defining package-scoped variables must use the var syntax. We don't really need to worry about this one for now, though.

Ok. Let's update our application to pass the message as a variable.

package main

import (
"fmt"
)

func main() {
message := "Aw yiss"
fmt.Println(message)
}

Functions. permalink

We've already written a main function but before we finish let's take a closer look at how to define our own functions in Go. Here's a simple function that adds two numbers:

func addNumbers(a int, b int) int {
return a + b
}

The func keyword is used the same way as our main function above, however within the parentheses we've defined some input parameters and their types. After the closing bracket we define the function's return type.

It's worth noting that, though it is generally frowned upon in the JavaScript world, there is something of a convention in Go for naming a function's input parameters with a single letter such as a or b. Not everybody does this, and it's perfectly fine to use something more descriptive, but you'll see it in the stdlib so it's good to be aware.

Ok, now we know a little bit more about functions, let's finish our application with a custom greeting.

package main

import (
"fmt"
)

// where n stands for the name of a programming language
func sayYiss(n string) string {
return "Aw yiss, I know " + n
}

func main() {
message := sayYiss("Golang")
fmt.Println(message)
}

If all goes well, running go run app.go should print "Aw yiss, I know Golang" to your console. That's it, we're finished. From your terminal, you can compile a distributable binary of your application by running:

go build main.go

Wrapping up for now. permalink

What is essentially a riff on a "Hello World" might not seem like the most exciting application ever, but we've actually covered quite a few core concepts of building Go applications.

We've learned how to start a go modules project. We've learned about packages and how the main package acts as an entrypoint for Go applications. We've learned a little bit about variables and functions and, to finish, we learned how to compile and run our application.

Hopefully this tutorial has given you a taste for what it's like to write Go and, if you're coming from JS or TypeScript background, then it should be clear that learning Go will be building on top of common concepts that you already know.

If you've found this useful, then I'm hoping to make this into a small series. Next time we'll take a look at structuring your Go applications and keeping things tidy with custom packages.

Hi, my name is Robb.

I'm a freelance creative developer helping awesome people to build ambitious yet accessible web projects.

Hire me
© MMXXI. Gwneud yn Ne Cymru.