Today I have started a new journey, I have been “pretend” coding for a long time, VBScript, Bash, PowerShell and lately Terraform. I say pretend coding because colleagues who code in “proper” language, like C#, Python and Golang (or Go as the trendy folk say), say I am only a glorified scripter. So today I am taking up the challenge to become a “proper” coder.
This is a first for me as I am not formally trained. My degree is in Law, not Computer Science, and my formal maths training finished at ‘O’ Level (UK formal testing taken in the final year of standard education at 16yrs of age). I do not expect this to be easy, but it is something I think I need to do. Over the next few months as I walk, stumble, and maybe fall on my face on this self-imposed journey of discovery, I will be documenting what I have learned,
By now, I hope you are asking what Language I will attempt to master. Is it C#, Ruby, Rust, Python, Java, or COBOL? No, I will attempt to learn Golang. Why?, It is the language that underpins Terraform. It is used to write Terratest’s Tests. So, as a language to learn, I would say it is crucial to my daily role as a DevOps lead.
A little bit of History
Robert Griesemer, Rob Pike, and Ken Thompson began sketching out the concept and goals for a new programming language in 2007. The result was Go (or Golang), which was released to the public in 2010 as an open-source project. Since then, its popularity has skyrocketed, and many people use it for various purposes. Despite having both supporters and detractors, the Go language is rapidly expanding.
The language’s designers, all Google employees, wanted to create a simple programming language that addressed the company’s sophisticated systems’ biggest challenges:
The initial value proposition of GoLang was to speed up and scale Google’s software development process which was being slowed down by the complexities of managing different Code languages. Golang solved these difficulties by taking the best qualities of the core languages it was built upon C, Pascal and Oberon and complimented them with an overlay of simplicity and progressivity. As a language, it reached critical mass in 2015 when the Complier was migrated the Go from C. this has allowed language enhancements to focus on Libraries, frameworks and tooling, enhancing and expanding the features of the language.
Currently, at the time of writing the Golang stable release is running at 1.20.1, this that in mind, let’s start to set up the new Development environment.
Setting up the dev environment.
Even though I run a windows 10 machine daily, I tend to do all my coding against on a WSL2 image running Ubuntu 20.04. so this article will focus on installing and configuring for that platform.
To start download the latest version of golang for your environment. For this, we use the wget command to download it to our home directory.
Before you start to install or upgrade your environment, remember to remove any previous Go Installation by deleting the /usr/local/go folder (if it exists) if not then just download and extract the archive /usr/local, creating a fresh Go tree in /usr/local/go:
$ rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.1.linux-amd64.tar.gz
Now depending on the privileges you hold on your system, these commands may need to be elevated using sudo to run correctly.
DO NOT attempt to install your environment over a pre-existing Go environment as it can result in a broken environment.
Finally, add /usr/local/go/bin to the PATH environment variable.
This is done by adding the following line to your $HOME/.profile or /etc/profile (for a system-wide installation):
export PATH=$PATH:/usr/local/go/bin
One thing to note is that a change to the profile file may not apply until the next time you log into your environment, if you need to apply the changes immediately, just run the shell commands directly or execute them from the profile using a command such as source $HOME/.profile.
To finally verify that Go has been correctly installed, open a command prompt and type the following command:
My first Go Program.
I am a traditionalist, so the first program will be “hello world”. Before writing the program, let’s start with the bare minimum structure to make a valid program. Every Go program will contain at its base minimum the following.
- Package Declaration: – The first statement in any Go Source file must be package “name”, where name is the name of the package or function. If it is the core package is should be titled “package main”
- Import Packages: – to import Go packages for use in your code you use import “package name” for example import “fmt”, this package implements formatted I/O for those that are familiar with C think printf() and scanf() .
- Functions: – These are what preform a task your program is built for. There are several built in functions that can be called to prevent having to re-invent the wheel. For example, println, this function formats its inputs/arguments and writes the result to your terminal prompt, it will automatically add spaces arguments and a newline is appended. println is useful for bootstrapping and debugging. Every Go program has at least one function; if it is the core or root function it should be called “func main ()”.
- Variables: variables store inputs exactly like those we know and love in terraform. You declare a variable with var; for example, var a = “Hello World”
- Statements and Expressions: Put simply an expression represents a value and a statement represents an operation. There is a lot more here; we will discuss this later.
- Comments: like all good languages, Go has the ability to have comments in your code, to advise the reader as to what is happening. In terraform we are used to using the “#” for single line comments and /* */ for multi line comments. In Go comments are defined with a double forward slash //. There is no option for multiline comments; these are defined by each line being defined with a //.
I appreciate that the above is a very abridged synopsis, we will be delving deeper into those concepts, but for the benefit of this article, they should give enough understanding for the “Hello World” programme.
OK so time for the main course, the traditional first programme that everybody writes in a new language is the ubiquitous “Hello World” programme. Who am I to buck tradition?
Hello World
Open up “vi” or your favourite editor, later we will be coding in vscode, but this is simple. Enter the code shown below. Save your code as “helloWorld.go”.
package main import "fmt" func main() { // This is the ubiquitous first sample program. The great and awesome Hello World fmt.Println("Hello, World!") }
This is perhaps the simplest program that can be written in any language, functionally useless, but it does show most of the principles of Go in action.
We have our package titled main, as it is the primary component of the programme. We have imported the package “fmt”. Next we create our function, in this case “func main ()” as it is the first and in this case only function of the program. The “doing” part of our “Go” function is enclosed in “{}” (curly brackets or to give them their proper name “Braces”). We have a comment explaining how great our code is and finally the payload. This simply prints the content between the Parentheses or Round Brackets. To run your first program at the command line enter the following:
go run helloWorld.go
You will see that this code has no variables, so let’s add a few enhancements to make our code funkier.
package main import . "fmt" func main() { // This is the ubiquitous first sample program. The great and awesome Hello World Println("Hello, World!") }
Here you will notice that I have placed a period between “import” and “fmt”. This simplifies our code by importing “fmt” into the same namespace that our code is running in, this means that we can remove the explicit reference to “fmt” on the “Println” line. It does not look much, but as we continue our journey, it helps keep our code legible.
Next we will add a couple of variables
First a few rules surrounding variable declaration.
A variable can have a short name (like x and y), not great for code clarity; or a more descriptive name (userName, rawCost, surName, etc.) – I think this will be my preferred method.
Go has some variable naming rules:
- A variable name must start with a letter or an underscore character (_)
- A variable name cannot start with a digit
- A variable name can only contain alpha-numeric characters and underscores (a-z, A-Z, 0-9, and _ )
- Variable names are case-sensitive (age, Age and AGE are three different variables)
- There is no limit on the length of the variable name
- A variable name cannot contain spaces
- The variable name cannot be any Go keywords
When declaring multi-word variables, you can use Camel Case (thisIsMyVariable) all words except for the first are capitalised, Pascal Case (ThisIsMyVariable) every word is capitalised, or Snake Case (this_is_my_variable) here each word is separated by an underscore. Choose your poison, my particular favourite is Camel Case. Just be consistent as it will cause confusion moving forward.
When adding variables, there are two distinct concepts, Constants and Variables. The only functional difference between the two is that a Constant is immutable (cannot be changed once defined).
To declare a constant use the following code block:
const ( firstWord = "Hello" secondWord = "World!" )
Adding this to our code will result in the following changes
package main import . "fmt" const ( firstWord = “Hello” secondWord = “World!” ) func main() { // This is the ubiquitous first sample program. The great and awesome Hello World Println("firstWord, secondWord") }
To date, we have not actually used any of the enhanced functionality of “fmt” in our code. So let’s introduce some basic formatting capabilities from the package. Edit your “Println” line to read:
Printf("%v %v\n", Hello, world)
This gives more precise control over how your parameters are displayed. Running this will show no difference in output.
Now change the line to read
Printf("%v\n %v\n", Hello, world)
After rerunning your code again, you will notice that “Hello” and “World!” are displayed on separate lines. The placement of the “\n” construct has forced a new line to be put between the first and second words.
OK now let’s show the power of a variable, remember a variable is not immutable.
Reopen “vi” and edit the “const” block to remove the “secondWord” constant and enter it as a variable.
const ( firstWord = "hello" ) var ( secondWord = "world!" )
Also remove the “\n” from between the two “%v” in the “Printf” line, so that everything back on one line.
This will not change anything in the output of the programme. However, let’s now change the variable in the function. We are going to add modify “secondWord” with something called an “augmented assignment” operator. In this case “:=” This is a convenience that allows a variable’s value to be modified and assigned to the same variable. This is called “redeclaration”
To carry this sorcery simply add the following line after the first brace, but before the payload.
secondWord := secondWord + " bang"
Your code should not look like this.
package main import . "fmt" const ( firstWord = "Hello" ) var ( secondWord = "World!" ) func main () { // This is the ubiquitous first sample program. The great and awesome Hello World secondWord := secondWord + " Bang" Printf("%v %v\n",firstWord,secondWord ) }
Running this code will now result in the following response.
Summary
We installed go, wrote our first program, and created some constants and a variable. We have modified the variable to change the value. Although it may not seem much because the programme we have written does not do anything useful, we have covered a lot of the basics, together with more advanced concepts like augmented assignments. As we continue on this journey we will delve deeper into the world of Go.