Part 1: Introduction

Today I decided to learn Go in the next 30 days and document every step of my journey. How well will I know Go in 30 days? That is a difficult question and by logging the steps, I can hopefully measure progress. How much time should I spend each day? I have a theory you will learn and retain far more information by studying and practicing every day compared to once in a while cram sessions. I also have another theory that studying right before bed helps to retain even more information. I can go into a mental zone where I am totally focused on my task/subject. Time disappears. This takes between 15 and 30 minutes to get into the zone. Therefore, I will set my goal at two hours of study, practice and code writing every evening, six days per week.

What resources will I use? I don’t know yet. I am a big fan of Pluralsight and at first glance; they have 20+ courses on Go. Today, I will pick three and just get started. I will also do the classic HelloWorld example to get something running. My initial thoughts are to start with Pluralsight for 30 minutes, studying language documentation for 30 minutes and then real coding for the rest of the time. I will copy and study examples from the Internet, including my favorite StackOverflow.

Once I get beyond the basic programming stuff, I plan to focus entirely on Go with Google Cloud Platform. This means writing tools and applications designed for GCP with a sub-focus of Containers, Cloud Run and Kubernetes.

This will be a running blog article. I plan to update this article every day with notes, information, results, etc. If you are interested in learning Go, follow along.

What is my objective? To learn Go well enough to write everyday programs for the cloud. If we look at various skill levels consisting of beginner, novice, professional, expert and architect, I hope to get to the professional level in 30 days. This means that my previous skills writing software in other languages will play a big part in getting there. Today I am a beginner, in a week I should be at the novice level. By the end of 30 days at the professional level for GCP. To get to the expert level will take many years (5 – 10) of writing, testing and deploying Go applications in the real world. No better time to start than today.

Resources:

  • Pluralsight – Go: The Big Picture by Mike Van Sickle – 107 minutes – May 21, 2019
  • Pluralsight – Go: Getting Started by Mike Van Sickle – 111 minutes – July 8, 2015 – First version
  • Pluralsight – Go Fundamentals by Nigel Poulton – 216 minutes – June 8, 2015

These videos total 434 minutes or about 7 hours of training material over 30 days. This is about 15 minutes per day. However, when I watch a training video, I am constantly pausing the video, making notes, following references, etc. I often watch a section again. This can make 15 minutes of video take an hour to complete. My goal is not to complete a course, but to retain as much information as I can and be able to apply that new knowledge in my work.

Added Resources:

This section will keep track of the additional resources I am studying. My goal is not to bounce around but to be methodical learning Go, one step at a time. I have no interest in cramming. I intend to learn Go and all its nuances and this will take a consistent everyday study pattern.

Part 2: Completed Results

July 14, 2019. I finally took the Pluralsight IQ for Go. I scored 154 which is Proficient. I achieved my goal of having a good understanding of the language. However, there were questions on this IQ test that I did not know the answers to and that I did not see in my studies. I will continue studying each one of these areas. During the past month, I wrote a lot of code – several thousand lines, published several articles that included Go source code and really tried to think in Go. The language is easy to write in and I am very comfortable writing code to interface with Google Cloud Platform. I plan to continue studying the more advanced topics of the language and retake the Pluralsight IQ exam later this year.

Part 3: Daily Study

Index

Day #1 – June 11, 2019

Try to start your training time with an objective. Sometimes this means changing your objective, but for me, this usually means I stick with it until I achieve my objective each day.

My goals for today are:

  • Install Go on my Windows system.
  • Create a Hello World console application, learn how to compile and run.
  • Deploy a Hello World web application to Docker and then deploy to Cloud Run.
  • Complete 60 minutes of video training.

Go Installation

I started by downloading and installing Go to my Windows 10 Professional system. Link. I installed to C:\go. Running go version reports 1.12.5. Then I created a working directory on my system to keep track of everything I write organized by sub-folders for each day.

Hello World Application

Next, I searched the Internet for a Go Hello World example. I chose this one: link.

Copied the example program to “main.go”.

package main

import "fmt"

func main() {
	fmt.Printf("hello, world\n")
}

Next is to run the program.

go run main.go

To build the program into a binary:

go build main.go

Very simple steps. Reminds me of C programming; edit – compile – run. The source code reminds me of Python and C combined into a new language. I know both well, so this should be interesting.

Video Training

I will start with Nigel Poulton’s Go Fundamentals.

Go Fundaments Section 1

The first item that I learned from Nigel’s course is that Docker, etcd, and Kubernetes are written in Go. If I had known these little facts last year, I would have made Go my goal to master a year ago. So much is happening in our market it is hard to keep track. Very exciting times.

I like Nigel’s teaching style and course content. I have watched many of his courses. Nigel could probably motivate me to design an ice cube factory in Alaska (just kidding). Section 1 reviewed the course content and provided good motivation for learning Go.

Go Fundaments Section 2

Interesting Go Language Facts:

  • Go was created at Google by Robert Griesemer, Rob Pike and Ken Thompson. Interesting. I knew and worked with Ken Thompson back in the early days of C and Unix.
  • Rob Pike’s wife designed the Go Gopher mascot logo. Official Gopher graphics: link.
  • Work started on Go in 2007. On Rob Pike’s Twitter account (@rob_pike) he tweeted September 21, 2007: link.
  • Initial release on November 2009 as open source.
  • Version 1 (go1) released on March 28, 2012.
  • Started as a “systems” language. This includes operating systems, device drivers, etc.
  • Like C but simpler.
  • Garbage collection managed by Go.
  • ~25 keywords.
  • Cross Platform.
  • Compiled language.
  • Strongly typed.
  • Supports type inference.
  • Go is case sensitive.
  • Packages: Exported names need a capital letter otherwise they are not accessible.

Go Fundaments Section 3

In the lesson “Setting up Our Workspace”, I understood the directory structure that Nigel suggests. However, I need to study further how this affects software development as I have my programs in their own directory in a different place on my file system.

I need to become very comfortable with the Go language tools. I am setting a soft goal of practicing with five command-line options each day. Today I have seen these:

  • go run
  • go build
  • go install
  • go version
  • go env
  • go help build (etc)

A more complete list from this document:

bug         start a bug report
build       compile packages and dependencies
clean       remove object files and cached files
doc         show documentation for package or symbol
env         print Go environment information
fix         update packages to use new APIs
fmt         gofmt (reformat) package sources
generate    generate Go files by processing source
get         download and install packages and dependencies
install     compile and install packages and dependencies
list        list packages or modules
mod         module maintenance
run         compile and run Go program
test        test packages
tool        run specified go tool
version     print Go version
vet         report likely mistakes in packages

Go Language Items:

  • “package main”. By declaring package main, we are telling Go compiler to compile this code as a standalone executable and not as a shared library.
  • The program entry point is func main() {}. func is a keyword.
  • The function to print a line is fmt.Println(). This function is imported from the library fmt (link). Other functions include Printf(), Scanf(), etc. Very similar to the C library.
  • The source code is available for just about everything. For example, the package fmt is available on GitHub (link). This will be an amazing resource to learn Go, by studying the actual library source code.
  • Go is case sensitive.
  • Packages: Exported names need a capital letter otherwise they are not accessible.
  • Comments are like C: // or /* */. The first method is preferred.

Summary of Nigel Poulton’s Go Fundaments Section 1-3:

This is a good introduction to the Go language. You will quickly learn a bunch of points as shown above in my notes. This course looks good. Now to start the other courses for comparison.

Go: Getting Started

This course is by Mike Van Sickle. The table of contents appears different from Nigel Poulton’s course, so I am looking forward to several viewpoints on Go.

Go: Getting Started Section 1

Important Go Links:

Go Tools:

  • golint

Func requires the open brace on the same line.

This is supported:

func main() {
}

This will generate a compiler error:

func main()
{
}

Important points:

  • Functions are first class citizens and do not require being wrapped in a class like C# or Java.
  • Go has a built-in function println("Hello world") that is useful for debugging. This function is not intended for production use.
  • If you do not reference an import package, Go will report an error.

Go supports constants:

package main

const (
	message = "Hello world"
)

func main() {
	println(message)
}

Go supports variables. Note the difference between Go and C. In C we would declare the type first. In Go we declare the name first and then the type:

package main

var (
	message string = "Hello world"
)

func main() {
	println(message)
}

Go supports an initialization function that runs on program startup. Public variables are initialized first and then the init() function is called.

package main

var (
	message string
)

func main() {
	println(message)
}

func init() {
	message = "Hello world"
}

Summary of Mike Van Sickle’s Go: Getting Started Section 1-2:

This is also a good introduction to Go presented differently. Mike’s starting point is to explore the Go community first, which provided me a wealth of valuable information. Just learning about the Go Playground was valuable. I would watch both Nigel’s Section 1-3 and Mike’s Section 1 in series. It does not matter which course you start with. Great information from both that go together well.

Go: The Big Picture

This course is by Mike Van Sickle. From the description, I expect to learn the What, When, Where and Why of the Go Language.

Go: The Big Picture Section 1-2

Go Language Characteristics:

  • Strong, static type system.
  • C-inspired syntax.
  • Multi-paradigm: procedural; object-oriented.
  • Garbage collected.
  • Fully compiled.
  • Rapid compilation.
  • Single binary output.

Go Philosophy and Values:

  • Simplicity.
  • Network aware and concurrent apps.
  • Out-of-the-box experience.
  • Cross-platform.
  • Backward compatibility.

Who is using Go in Production Applications?

  • Google
  • IBM
  • Amazon
  • Digital Ocean
  • Twilio SendGrid
  • Facebook
  • CloudFlare
  • Netflix
  • Docker – written in Go
  • Kubernetes

Comprehensive List of Go Users: link.

Go success stories from around the web: link.

This is an excellent section that helps me understand the business part of choosing Go. Good presentation. I will move this course to my mornings, when I have my business/marketing hat on and complete this course, one section each day over coffee.

Creating a Docker Image

I learned a lot about Go, but not too much about actually writing code. I want to finish my training day applying what I already know with Go. I will start with a Go web application, create a Docker container and test locally. Then I will deploy to Cloud Run.

I need an example Go web application, as I don’t know how to write one yet. I chose this one: link. This example just happens to be for Go and Cloud Run. The article is not complete, but close enough.

The application source code:

package main

import (
    "os"
    "log"
    "fmt"
    "net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hello world")
	})

	port := os.Getenv("PORT")

	if port == "" {
		port = "8080"
	}

	log.Fatal(http.ListenAndServe(":"+port, nil))
}

The first step is to run this code in a Command Prompt:

go run main.go

Connect with a web browser and go to http://localhost:8080/

You should see “Hello world”

Next step is to create a Dockerfile:

FROM golang
WORKDIR /go/src/app
COPY . .
RUN go build -v -o /app .

ENV PORT 8080

CMD ["/app"]

Now build the Cloud Run image in Container Registry. Replace development-123456 with your Project ID:

gcloud builds submit --tag gcr.io/development-123456/go-helloworld

Now deploy this image to Cloud Run:

gcloud beta run deploy go-helloworld ^
--region us-central1 ^
--image gcr.io/development-123456/go-helloworld ^
--allow-unauthenticated

Mission accomplished. Learned some basic Go language stuff and deployed a simple Go web server to Cloud Run.

Total time spent today: three hours.

Day #2 – June 12, 2019

My goals for today are:

  • Complete 30 minutes of video training.
  • Find an OAuth2 example and port to run in a container and deploy to Cloud Run.

Last night, after completing my initial study of Go, I realized that the Go language is easy to learn. I feel that I can learn most of the Go language in one week. The real challenge is not the language, but the tools, libraries, and ecosystem that exists for Go. To become really effective with Go, I will need to spend a lot of time on everything that surrounds and supports the Go language. This will be the challenge.

I am a big fan of Qwiklabs. They have a couple of Go labs to practice with. However, by previewing these labs, I discovered a huge resource for learning Go for the Google Cloud Platform. Google has published a library of examples and Go is one of the languages:
Google Cloud Examples Package

On the Twitter hashtag #golang I found an interesting article My journey from Python to Golang. Very good article.

Go Fundaments Section 4 – Variables and Constants

Go Tips:

    • Convert a string to a byte array: []byte("Hello World)
    • Variables: Use var keyword if declaring at the package level. (What does this really mean?)
    • Variables: Names must start with “_” or a letter.
    • Go will initialize variables with a zero value.
    • To get the type of a variable use reflect.TypeOf(variable)
    • Go supports determining the type: var name = "Nigel" Go set the type of name to string.
    • Package level variables are global.
    • Shorthand to declare and initialize “:=” only works inside of functions. name := "John" This is called Short Assignment
    • Variables that are declared and not used at the function level will generate a compiler error.
    • Pointers: Taking the address of a variable is just like C: &variable.
    • fmt.Println() prints points in hex 0xc080281234
    • ptr := &variable
    • Value (contents) of a pointer is just like C: *ptr. This is called De-referencing a pointer.
    • Constants: You cannot use Short Assignment with constants. const x := 0 will generate a compiler error.
    • Environment: os.Environ() will return a list of environment variables.
    • Example: fmt.Println("TMP directory:", os.Getenv("TMP")).
    • File open example: in, err := os.Open(filename).
    • Lookup the keyword defer as in defer in.Close()
      • Defer is used to ensure that a function call is performed later in a program’s execution, usually for purposes of cleanup. defer is often used where e.g. ensure and finally would be used in other languages.

Summary of Nigel Poulton’s Go Fundaments Section 4:

This was a good section on variables and constants in Go. Very similar concepts to the C language. The video material was 25 minutes and I spent 60 minutes practicing in a Command Prompt.

Interesting Code Examples to Remember:

Print the environment variables. Note the range keyword. I am using two different ways.

for _, env := range os.Environ() {
        fmt.Println("ENV:", env)
}

l := os.Environ()

for _, env2 := range l {
        fmt.Println("ENV:", env2)
}

OAuth 2 Example in Go

Now to find an OAuth 2 example written in Go. I plan to improve whatever I find to provide OIDC Identity Tokens which can later be used for Cloud Run authentication.

I found this article with example code: Getting Started with OAuth2 in Go by Alex Pliutau. A copy and paste from his article did not work. He forgot to include some packages and other minor stuff that happens when you write an article.

Tomorrow I will include my code based upon Alex’s article.

Day #3 – June 13, 2019

My goals for today are:

  • Complete 30 minutes of video training.
  • Learn how to process argv and environment variables in a program.
  • Load and process JSON from a file.
  • Understand how to use service accounts in Go.
  • Write a simple program to read a Cloud Storage object.

My initial thoughts today. If you are a C language programmer, the Go language is easy to learn. Most of the language is the same. The libraries are very similar. The Go Standard Library reminds of me of the C Standard Library. Go has less “ad-hoc” stuff, where C and the libraries evolved over several decades. Go is cleaner. However, I am only in my third-day learning Go. Let’s see what I think after 30 days.

Go Getting Started – Section 2 – Data Types and Operators

Primitive Data Types:

  • bool
  • string
  • int int8 int16 int32 int64
  • uint uint8 uint16 uint64
  • byte // alias for uint8
  • rune // alias for int32 // represents a Unicode code point
  • There are two float types float32 and float64. There is no `float` keyword.
  • To explicitly specify a floating point number: 64.0 or 64. Notice the period (dot) at the end of 64.
  • Complex data type. See the example below. I am confused with complex() and complex32 and complex64. Research later.

Complex Data Type:

func main() {
	myComplex := complex(2,3)
	fmt.Println(myComplex)
	fmt.Println(real(myComplex))
	fmt.Println(imag(myComplex))
}

Example code (not optimized):

func main() {
	var myInt int
	myInt = 42

	fmt.Println(myInt)
}

Example code (better):

func main() {
	myInt := 42

	fmt.Println(myInt)
}

In the second example, we cleaned up the code by using a Go language feature called “Short Variable Declaration” (link and link).

Constants

  • iota – This is similar to C’s enum. This simplifies definitions of incrementing numbers. See the example below.

 

Example iota:

func main() {
	const (
		zero = iota
		one
		two
	)
	
	fmt.Println(zero)
	fmt.Println(one)
	fmt.Println(two)
}

which outputs:

0
1
2

An interesting iota example:

func main() {
	type ByteSize float64

	const (
		_           = iota // ignore first value by assigning to blank identifier
		KB ByteSize = 1 << (10 * iota)
		MB
		GB
		TB
		PB
		EB
		ZB
		YB
	)
	
	fmt.Println(KB)	
	fmt.Println(int(MB))
	fmt.Println(int(GB))
	fmt.Println(int64(TB))
	fmt.Println(int64(PB))
	fmt.Println(int64(EB))
	fmt.Println(ZB)	// Too big for int64
	fmt.Println(YB)	// Too big for int64
}

which outputs:

1024
1048576
1073741824
1099511627776
1125899906842624
1152921504606846976
1.1805916207174113e+21
1.2089258196146292e+24

Collections:

  • Array
    • Arrays have a fixed size.
    • Example: myArray := [3]int{}
    • myArray[0] = 42
    • You can print the contents of an array: fmt.Println(myArray)
    • You can get the length of an array: len(myArray)
    • Another method to initialize an array: myArray := [3]int {42, 27, 99}
    • Automatically size the array with initializers: myArray := [...]int {42, 27, 99}
  • Slice
    • A Slice represents a subset of an array.
    • Example: mySlice := myArray[:]
    • Example: mySlice := myArray[1:]
    • Example: mySlice := myArray[:3]
    • Changing the array changes the slice and any other slices.
    • Changing the slice changes the array and any other slices.
    • Initialize an array or slice with a fixed size: myArray := make([]int, 100)
  • Map
    • Holds multiple values by customizable keys.
    • Both the key and the value can be arbitrary data types.

Map Example:

func main() {
	myMap := make(map[string]string)
	fmt.Println(myMap)
	myMap["Firstname"] = "John"
	fmt.Println(myMap)
	fmt.Println(myMap["Firstname"])
}

which outputs:

map[]
map[Firstname:John]
John

Operators:

Go supports the usual C operators (+-*/%). Go also supports the postfix operators (x++) but not the prefix operators (++x). Also, these types of operators must be on their own line. Example myFunc(x++) is not legal.

Summary of Go Getting Started – Section 2 – Data Types and Operators

This was a good section. Mike goes faster than Nigel does, which I prefer as this is still basic programming information. The key areas to note for the Go language are arrays, slices, and maps. The syntax is different compared to other languages, so this is just memorization work. 24 minutes of video took me more than an hour. I spent a lot of time in the Go Playground.

I will now pause the study part for a few hours and write my first article on Google Cloud and Go. This will be an article about Service Accounts and how to load the JSON file from Google Cloud Storage. I will use more advanced security techniques where the service account has no permissions. The security is managed by Google’s new Identity feature. I wrote about these features for my article on Cloud Run Identity. I will continue this article once the new article is published later today.

Google Cloud – Go – Identity Based Access Control

Article published including source code on GitHub. The Go language is easy to write programs with. I wrote a real program that uses security accounts to access data. Link to article.

Today’s Summary

I did not keep track of my time today. I spent about an hour on video training and practice. Then I started writing my article, researching, etc. I think the total time to research, write the code, test and write the article was two to three hours. I was mentally tired last night when I stopped.

Day #4 – June 14, 2019

I am not sure where I had the impression that learning Go would take a lot of effort. After just three days and maybe six hours of study, I could write a full program in Go that did something useful with service accounts and Cloud Storage. However, when judging skills, it is not what you know that matters; it is what you don’t know that comes back to bite you in programming.

I will continue with the video courses and learn the syntax and grammar working on difficult areas such as Interfaces. In reviewing Pluralsight’s courses on Go, I discovered another course on gRPC which has a section on Go. I have not worked with gRPC, so I am adding this course to my Go training starting today. This course is Enhancing Application Communication with gRPC by Michael Van Sickle.

Enhancing Application Communication with gRPC – Section 1-2

This course is by Michael Van Sickle. Although gRPC is not really related to Go, it fits into my objective of learning Go with a focus on Google Cloud Platform. gRPC is a common technology at Google and one I have been curious about as I write a lot of software that directly calls the REST APIs. I will learn how to use gRPC in Go which will help me improve my understanding of the Go ecosystem.

Background of gRPC

  • Stubby – Developed at Google. Microservice Based; Cross-Platform; Scalable; Precursor to gRPC.
  • gRPC – Developed at Google. Cross-Platform; Scalable, Streaming; Free and Open; Pluggable; Layered.
  • gRPC – Fast and Efficient Protocol; Strongly Typed Messaging.

Tour of gRPC

Go Getting Started – Section 3 – Branching and Looping

Branches:

  • If statements. Parenthesis are not required but do work. Examples:
    • if x == 12 {
    • if (x == 12) {
  • Single line if statements are supported:
    • if x == 12 { fmt.Println("Match") }
  • The left brace must be on the same line as the if statement. If moved to the next line, the compiler will report an error.

Switch:

Notice the three styles (types) of switch statements. The first one compares strings, the second compares ints, the third compares boolean conditions. The third one does not have a variable in the switch statement.

func main() {
	os := runtime.GOOS

	fmt.Print("Go runs on ")
	
	switch os {
	case "darwin":
		fmt.Println("OS X.")
	case "linux":
		fmt.Println("Linux.")
	default:
		// freebsd, openbsd,
		// plan9, windows...
		fmt.Printf("%s.\n", os)
	}

	x := 12
	
	switch x {
	case 1:
		fmt.Println("One")

	case 12:
		fmt.Println("Twelve")
	}
	
	x = 5
	
	switch {
	case x < 12:
		fmt.Println("Less than 12")
	case x > 11:
		fmt.Println("Greater than 11")
	}
}

Loops:

  • For loops are just like C: for(i:=0; i < 5; i++) {
  • For look like the C while: for {

Console Input

  • var option string
  • fmt.Scanln(&option)

Summary of Go Getting Started – Section 3 – Branching and Looping

This was a good section. Mike did not introduce many new features. Almost everything matches the C language. Except for the := and variable declarations you might think the code is C.

The next section in Go Fundamentals is on Conditions which matches today’s lesson. I will take that tomorrow to reinforce everything.

Google Cloud SQL + Google Cloud Run

I have been planning an article on Cloud Run + Cloud SQL for a month. I will spend the rest of this evening learning how to program databases in Go. I will start with this video, which is very good:

My first MySQL database program in Go. This code connects to the SQL Proxy running on my desktop to Cloud SQL. The database has a copy of an old WordPress website, so I have some data to query.

package main

import "fmt"
import "log"
import "database/sql"
import _ "github.com/go-sql-driver/mysql"

func main() {
	fmt.Println("Hello MySQL World")

	db, err := sql.Open("mysql", "root:password@/wordpress")

	defer db.Close()

	if err != nil {
		fmt.Println(err.Error())
		return
	}

	err = db.Ping()

	if err != nil {
		fmt.Println(err.Error())
		return
	}

	type Tag struct {
		username string `json:username`
		email string `json:email`
	}

	var tag Tag

	err = db.QueryRow("SELECT user_login, user_email FROM wp_users where user_login = ?", "username").Scan(&tag.username, &tag.email)

	if err != nil {
		fmt.Println(err.Error())
		return
	}

	log.Println("Username:", tag.username)
	log.Println("Email:", tag.email)
}

I also started to practice with JSON. This example will take a map and write it out as JSON to os.Stdout:

package main

import (
	"encoding/json"
	"fmt"
	"os"
)

func main() {
	fmt.Println("Hello World")

	m := map[string]string{"name": "John", "last": "Smith"}
	enc := json.NewEncoder(os.Stdout)
	enc.Encode(m)
}

Good day studying overall. The Go language and libraries are very easy to work with provided you have Google to search for stuff.

Day #5 – June 15, 2019

Today I woke up early and started training at 6 AM. My plan is to finish three hours of studying before anyone else wakes up and then enjoy the great weather we are having in Seattle.

I started by finishing the course Go: The Big Picture by Mike Van Sickle. This is a great course to give you an overview of the Go language and the benefits of using Go. He is non-biased which is refreshing. As a beginning Go developer, watch Section 4 “What is it Like to use Go?” – great code demonstrations.

Mike recommends the following courses. I am already watching the first one:

Let’s review where I am at with the training courses:

  • Go: The Big Picture – Completed 6/15/19
  • Go: Getting Started – In Progress – 59 minutes of 111 minutes – 53%.
  • Go Fundamentals – In Progress 78 minutes of 216 minutes – 36%

Go progress. I am taking my time and slowly going thru each course. I am practicing over and over the simple items such as grammar. I want a good foundation with no bad habits.

Writing in Go is easy for me now. My big challenge is that I am not familiar with the packages/libraries. That is a big item that I must complete. I plan to start with the Go Package page at the top and write some code using each library (one at a time). Within a few weeks, I will know the packages/libraries much better. To be efficient and productive in a language means “don’t reinvent the wheel”. Use existing code and libraries where applicable.

Go Fundaments – Section 4 – Conditionals

Nigel makes a mistake in the lesson “if in Practice”. He is comparing strings instead of numbers. His code works by accident instead of by design. Solution: remove the quotes around the numbers.

One of the goals of the Go language is simplicity. Based upon this, I don’t see why the Go language creators added this syntax:

if <simple statement> ; <Boolean expression> {

The “simple statement” is really unnecessary, and I think creates a more complex if statement. Add to this that any variables defined in the if statement are local and go out of scope after the code block executes. My opinion, move the simple statement to its own line before the if statement. This allows for comments, etc that might be needed to clarify what you are actually coding.

Here is an example (I made this up):

package main

import (
	"fmt"
)

func get_number() int {
	return 0
}

func main() {
	if x := get_number(); x == 0 {
		fmt.Println("X is 0")
	}
        // x is undefined here
}

I think the line if x := get_number(); x == 0 { is not improved by having x := get_number(); in the if statement. Move the initialization of x to its own line.

A new feature that exists in Go but not C is the “fallthrough” statement. In C switch case statements fallthrough by default unless there is a break statement. In Go, break statements are unnecessary and you must specify fallthrough to continue executing the next case statement.

Concurrent Programming with Go – Section 1 – Concurrency Patterns

This section is a simple review of the various concurrency models:

  • Concurrency vs. Parallelism
  • Processor Threads
  • Events
  • Callbacks and Promises
  • Communicating Sequential Processes

Concurrency in Go:

  • No Thread Primitives
  • Goroutines
  • Channels

Concurrent Programming with Go – Section 2 – Goroutines

Look into GOMAXPROCS as I think this has changed since Mike wrote the course in 2015.

I completed the first two sections of this course. Easy to understand how to implement goroutines. Section 2 had lots of demos and I will now spend the next hour reproducing sections of each demo for practice.

I want to study the documentation for the following Go packages:

  • os
  • time
  • strings
  • strconv
  • encoding/csv

Good morning studying. I put more time in this morning that I had planned. I started at 6 AM and finished at 10 AM. I am now very comfortable writing Go programs. I have no problems reading other’s work.

Day #6 – June 16, 2019

Today my objective is to watch some YouTube videos on Go and complete the Go: Getting Started course. Then I will work on writing code for my article on Google Cloud Run + Cloud SQL.

I started with this video by Robert Pike: “why Golang is Successful by Creator of Golang Rob-pike”. Great video and I recommend watching Robert’s presentation after you have learned the basics of Go. I then watched “Brad Fitzpatrick Go 1 11 and beyond“. Brad can take a serious topic and make people laugh. Great presentation.

Go: Getting Started Section 4 – Functions

Variadic Functions accept any number of like arguments.

package main

import "fmt"

func main() {
	sayHello("Hello", "Go", "from", "Plurasight")
}

func sayHello(messages ...string) {
	for _, message := range messages {
		fmt.Println(message)
	}
}

Named Return Values. I like this feature:

package main

import "fmt"

func main() {
	len := sayHello("Hello", "Go", "from", "Plurasight")
	fmt.Println(len)
}

func sayHello(messages ...string) (items int) {
	for _, message := range messages {
		fmt.Println(message)
	}
	
	items = len(messages)
	return
}

Go: Getting Started Section 5 – Object-oriented Programming

package main

import "fmt"

func main() {
	foo := myStruct{}
	foo.myField = "bar"
	fmt.Println(foo)
	fmt.Println(foo.myField)
}

type myStruct struct {
	myField string
}
package main

import "fmt"

func main() {
	foo := new(myStruct)
	foo.myField = "bar"

	fmt.Println(foo)
	fmt.Println(*foo)
	fmt.Println(foo.myField)
}

type myStruct struct {
	myField string
}

Outputs:

&{bar}
{bar}
bar
package main

import "fmt"

func main() {
	foo := &myStruct{"bar"}

	fmt.Println(foo)
	fmt.Println(*foo)
	fmt.Println(foo.myField)
}

type myStruct struct {
	myField string
}

Outputs:

&{bar}
{bar}
bar

In C++ taking the address of a local variable (&myStruct above) is a sure way to have a bug and probably a program crash. This is OK in Go.

Constructor Functions

I found constructor functions to be more of a hack (afterthought) than part of the design. Notice in the following code how you must call a function to initialize the struct instead of calling the struct itself (which you would do in other languages)

package main

import "fmt"

func main() {
	foo := newMyStruct()
	
	foo.myMap["bar"] = "baz"

	fmt.Println(foo)
	fmt.Println(*foo)
	fmt.Println(foo.myMap)
}

type myStruct struct {
	myMap map[string]string
	
}

func newMyStruct() (*myStruct) {
	result := myStruct{}
	result.myMap = map[string]string{}
	
	return &result
}

Methods

I have seen this new function specification in other source code, but I did not understand what I was looking at. In the code below look at the line func (mp *messagePrinter) printMessage() {. The text after the func did not make sense to me. Now add a return type to the declaration and I was confused even more. Now I understand.

package main

import (
	"fmt"
)

func main() {
	mp := messagePrinter{"foo"}
	mp.printMessage()
}

type messagePrinter struct {
	message string
}

func (mp *messagePrinter) printMessage() {
	fmt.Println(mp.message)
}

Go: Getting Started Section 6 – Asynchronous Programming

Yesterday, I started the new course “Concurrent Programming with Go” which covered this section but much deeper. See my notes from yesterday.

Summary Go: Getting Started

This is a great course that provides beginner level training for the Go language. Michael Van Sickle is a good author, and this course is well worth two hours spread out with practice over several days – I spent six days on this course.

I have now completed two courses on Go. These courses are beginner level, but I now feel very comfortable reading other people’s Go code and writing my own code. I will continue and dig much deeper into the Go language and ecosystem.

Let’s review where I am at with the training courses:

  • Go: The Big Picture – 107 minutes – Completed 6/15/19
  • Go: Getting Started – 111 minutes – Completed 6/16/19
  • Go Fundamentals – In Progress 107 minutes of 216 minutes – 49%
  • Concurrent Programming with Go – In Progress 68 minutes of 156 minutes – 43%

Day #7 – June 17, 2019

No study today.

Day #8 – June 18, 2019

Today I gave myself a tough challenge. Write an OAuth program in Go that does not use any OAuth libraries. Success is determined by calling a Cloud Run service that requires authentication. This program is not yet finished but when it is ready, I will publish as a separate article.

Objectives:

  • Write in Go.
  • Do not use any OAuth libraries.
  • Save the OAuth credentials in a file for later use. This provides the ability to authenticate once and save the Refresh Token.
  • Develop the code for an “installed app”. This means that the OAuth completes via a built-in web server.
  • Port the final code to be a package that can be added to my own tools to provide Google authentication.
  • Note: I am using a web server that I wrote in Python previously for this project. The code is in my GitHub repository. I want to see what issues exist when calling a Python program from Go. There are some tasks that Python is really good at and I want to use both languages in some projects.
  • Call a Cloud Run endpoint, passing the OAuth Identity Token in the Authorization header.

The code so far, which works by the way. I just need to document and clean up the code.

package main

// https://github.com/kirinlabs/HttpRequest

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"time"
	"github.com/kirinlabs/HttpRequest"
)

var SavedUserCredentials = "user_credentials.json"

var SCOPE = "https://www.googleapis.com/auth/userinfo.email"

var ENDPOINT = "https://accounts.google.com/o/oauth2/v2/auth"

var CHROME = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"

type ClientSecrets struct {
	Installed struct {
		ClientID                string   `json:"client_id"`
		ProjectID               string   `json:"project_id"`
		AuthURI                 string   `json:"auth_uri"`
		TokenURI                string   `json:"token_uri"`
		AuthProviderX509CertURL string   `json:"auth_provider_x509_cert_url"`
		ClientSecret            string   `json:"client_secret"`
		RedirectUris            []string `json:"redirect_uris"`
	} `json:"installed"`
}

type UserCredentials struct {
	ClientID                string   `json:"client_id"`
	ClientSecret            string   `json:"client_secret"`
	RefreshToken            string   `json:"refresh_token"`
	Scope            	string   `json:"scope"`
	Type             	string   `json:"type"`
	// The following two fields are option and exist after authentication
	AccessToken		string   `json:"access_token"`
	IDToken			string   `json:"id_token"`
	Email			string	 `json:"email"`
	ExpiresAt		int64	 `json:"expires_at"`
}

type OAuthTokens struct {
	AccessToken		string   `json:"access_token"`
	ExpiresIn               int      `json:"expires_in"`
	RefreshToken            string   `json:"refresh_token"`
	Scope            	string   `json:"scope"`
	TokenType            	string   `json:"token_type"`
	IDToken			string   `json:"id_token"`
}

func readCredentials(filename string) ([]byte, error) {
	in, err := os.Open(filename)

	if err != nil {
		return []byte(""), err
	}

	defer in.Close()

	b, err := ioutil.ReadAll(in)

	return b, err
}

func loadClientSecrets(filename string) (ClientSecrets, error) {
	var secrets ClientSecrets

	data, err := readCredentials(filename)

	if err != nil {
		return secrets, err
	}

	// fmt.Println(string(data))

	err = json.Unmarshal(data, &secrets)

	if err != nil {
		fmt.Println("Error: Cannot unmarshal JSON: ", err)
		return secrets, err
	}

	// fmt.Println("ClientID:", secrets.Installed.ClientID)

	return secrets, err
}

func loadUserCredentials(filename string) (UserCredentials, error) {
	var secrets UserCredentials

	data, err := readCredentials(filename)

	if err != nil {
		return secrets, err
	}

	// fmt.Println(string(data))

	err = json.Unmarshal(data, &secrets)

	if err != nil {
		fmt.Println("Error: Cannot unmarshal JSON: ", err)
		return secrets, err
	}

	// fmt.Println("ClientID:", secrets.ClientID)

	return secrets, err
}

func saveUserCredentials(filename string, creds UserCredentials) error {
	fmt.Println("Save Credentials to:", filename)
	// fmt.Println("Creds:", creds)

	j, err := json.MarshalIndent(creds, "", " ")

	if err != nil {
		fmt.Println("Error: Cannot marshall JSON:", err)
		return err
	}

	// err = ioutil.WriteFile(filename + ".test", j, 0644)
	err = ioutil.WriteFile(filename, j, 0644)

	if err != nil {
		fmt.Println(err)
		return err
	}

	return nil
}

func fileExists(filename string) bool {
	info, err := os.Stat(filename)

	if os.IsNotExist(err) {
		return false
	}

	return !info.IsDir()
}

func debug_PrintUserCredentials(creds UserCredentials) {
	fmt.Println("************************************************************")
	fmt.Println("ClientID:", creds.ClientID)
	fmt.Println("ClientSecret:", creds.ClientSecret)
	fmt.Println("RefreshToken:", creds.RefreshToken)
	fmt.Println("Scope:", creds.Scope)
	fmt.Println("Type:", creds.Type)
	fmt.Println("AccessToken:", creds.AccessToken)
	fmt.Println("IDToken:", creds.IDToken)
	fmt.Println("ExpiresAt:", creds.ExpiresAt)

	fmt.Println("Expires At:", time.Unix(creds.ExpiresAt, 0))

	var t time.Time = time.Unix(creds.ExpiresAt, 0)
	var expires_in int64 = 0

	if time.Now().Before(t) {
		expires_in = int64(creds.ExpiresAt) - int64(time.Now().UTC().Unix())
		fmt.Println("Expires In:", expires_in)
	} else {
		fmt.Println("Expires In: Expired")
	}
	fmt.Println("************************************************************")
}

func doRefresh(filename string) (string, string, bool) {
	endpoint := "https://www.googleapis.com/oauth2/v4/token"

	creds, err := loadUserCredentials(filename)

	if err != nil {
		fmt.Println(err)
		return "", "", false
	}

	// debug_PrintUserCredentials(creds)

	// We want an access token that is good for a while.
	// Brand new tokens are valid for 3600 seconds
	// For testing require 15 minutes or 900 seconds

	var t time.Time = time.Unix(creds.ExpiresAt - (15 * 60), 0)
	// fmt.Println(t)

	// fmt.Println(time.Now())

	if time.Now().Before(t) {
		fmt.Println("Saved Token OK")

		return creds.AccessToken, creds.IDToken, true
	}

	fmt.Println("Must Refresh Token")

	// return

	content := "client_id=" + creds.ClientID + "&"
	content += "client_secret=" + creds.ClientSecret + "&"
	content += "grant_type=refresh_token&"
	content += "refresh_token=" + creds.RefreshToken

	// fmt.Println("Content:", content)

	req := HttpRequest.NewRequest()

	req.SetHeaders(map[string]string{"Content-Type": "application/x-www-form-urlencoded"})

	res, err := req.Post(endpoint, content)

	if err != nil {
		fmt.Println("Error: ", err)
		return "", "", false
	}

	body, err := res.Body()

	if err != nil {
		fmt.Println("Error: ", err)
		return "", "", false
	}

	// fmt.Println("Body Length: ", len(string(body)))
	// fmt.Println("Body: ", string(body))

	var tokens OAuthTokens

	err = json.Unmarshal(body, &tokens)

	if err != nil {
		fmt.Println("Error: Cannot unmarshal JSON: ", err)
		return "", "", false
	}

	// fmt.Println("time.Now(): ", time.Now().UTC().Unix())
	// fmt.Println(time.Now().String())

	var expires_at int64 = int64(time.Now().UTC().Unix()) + int64(tokens.ExpiresIn)

	// fmt.Println("**********")
	// fmt.Println("Expires At:", time.Unix(expires_at, 0))

/*
	fmt.Println("AccessToken:", tokens.AccessToken)
	fmt.Println("ExpiresIn:", tokens.ExpiresIn)
	fmt.Println("ExpiresAt:", expires_at)
	fmt.Println("Scope:", tokens.Scope)
	fmt.Println("TokenType:", tokens.TokenType)
	fmt.Println("IDToken:", tokens.IDToken)
*/

	creds.AccessToken = tokens.AccessToken
	creds.IDToken = tokens.IDToken
	creds.ExpiresAt = expires_at

	email, err := get_email_address(tokens.AccessToken)

	if err == nil {
		fmt.Println("Email:", email)

		creds.Email = email
	}

	err = saveUserCredentials(filename, creds)

	if err != nil {
		fmt.Println("Error: Cannot save user credentials: ", err)
		return "", "", false
	}

	return creds.AccessToken, creds.IDToken, true
}

func debug_displayAccessToken(accessToken string) {
	endpoint := "https://www.googleapis.com/oauth2/v3/tokeninfo"

	req := HttpRequest.NewRequest()

	req.SetHeaders(map[string]string{"Authorization": "Bearer " + accessToken})

	res, err := req.Get(endpoint)

	if err != nil {
		fmt.Println("Error: ", err)
		return
	}

	body, err := res.Body()

	if err != nil {
		fmt.Println("Error: ", err)
		return
	}

	fmt.Println(string(body))
}

func debug_displayUserInfo(accessToken string) {
	endpoint := "https://www.googleapis.com/oauth2/v3/userinfo"

	req := HttpRequest.NewRequest()

	req.SetHeaders(map[string]string{"Authorization": "Bearer " + accessToken})

	res, err := req.Get(endpoint)

	if err != nil {
		fmt.Println("Error: ", err)
		return
	}

	body, err := res.Body()

	if err != nil {
		fmt.Println("Error: ", err)
		return
	}

	fmt.Println(string(body))
}

func debug_displayIDToken(accessToken, idToken string) {
	endpoint := "https://www.googleapis.com/oauth2/v3/tokeninfo"

	endpoint += "?id_token=" + idToken

	req := HttpRequest.NewRequest()

	req.SetHeaders(map[string]string{"Authorization": "Bearer " + accessToken})

	res, err := req.Get(endpoint)

	if err != nil {
		fmt.Println("Error: ", err)
		return
	}

	body, err := res.Body()

	if err != nil {
		fmt.Println("Error: ", err)
		return
	}

	fmt.Println(string(body))
}

func call_cloud_run_endpoint(url, id_token string) {
	endpoint := url

	fmt.Println("URL:", endpoint)
	fmt.Println("ID:", id_token)

	req := HttpRequest.NewRequest()

	req.SetHeaders(map[string]string{"Authorization": "Bearer " + id_token})

	res, err := req.Get(endpoint)

	if err != nil {
		fmt.Println("Error: ", err)
		return
	}

	body, err := res.Body()

	if err != nil {
		fmt.Println("Error: ", err)
		return
	}

	fmt.Println(len(body))
	fmt.Println(string(body))
}

func get_email_address(accessToken string) (string, error) {
	type Access_Token struct {
		Azp		string   `json:"azp"`
		Aud		string   `json:"aud"`
		Sub		string   `json:"sub"`
		Scope		string   `json:"scope"`
		Exp		string   `json:"exp"`
		Expires_in	string   `json:"expires_in"`
		Email		string   `json:"email"`
		Email_verified	string   `json:"email_verified"`
		Access_type	string   `json:"access_type"`
	}

	//************************************************************
	//
	//************************************************************

	endpoint := "https://www.googleapis.com/oauth2/v3/tokeninfo"

	req := HttpRequest.NewRequest()

	req.SetHeaders(map[string]string{"Authorization": "Bearer " + accessToken})

	//************************************************************
	//
	//************************************************************

	res, err := req.Get(endpoint)

	if err != nil {
		fmt.Println("Error: ", err)
		return "", err
	}

	body, err := res.Body()

	if err != nil {
		fmt.Println("Error: ", err)
		return "", err
	}

	//************************************************************
	//
	//************************************************************

	var tokens Access_Token

	fmt.Println("Valid:", json.Valid(body))

	err = json.Unmarshal(body, &tokens)

	if err != nil {
		fmt.Println("Error: Cannot unmarshal JSON: ", err)
		return "", err
	}

	return tokens.Email, nil
}

func main() {
	// fmt.Println("Hello world")

	//************************************************************
	//
	//************************************************************

	flag_auth := flag.Bool("auth", false, "Authenticate ignoring user_credentials.json")
	flag_login := flag.String("login", "", "Specify an email address as a login hint")

	flag.Parse()

	//************************************************************
	//
	//************************************************************

	fmt.Println("Auth:", *flag_auth)
	fmt.Println("Login:", *flag_login)

	if *flag_auth == false {
		if fileExists(SavedUserCredentials) {
			accessToken, idToken, valid := doRefresh(SavedUserCredentials)

			if valid == true {
				fmt.Println("Access Token: ", accessToken)
				fmt.Println("ID Token:     ", idToken)

				// debug_displayAccessToken(accessToken)
				// debug_displayUserInfo(accessToken)
				debug_displayIDToken(accessToken, idToken)

				url := "https://cloudrun-go-test.a.run.app/"

				call_cloud_run_endpoint(url, idToken)

				return
			}
		}
	}

	// secrets, err := loadClientSecrets("c:/config/client_secrets.json")
	secrets, err := loadClientSecrets("c:/config/client_secrets_mystic_advice.json")

	if err != nil {
		fmt.Println(err)
		return
	}

	cmd := exec.Command("python", "webserver.py")

	err = cmd.Start()

	if err != nil {
		fmt.Println(err)
		return
	}

	//************************************************************
	url := ENDPOINT
	url += "?client_id=" + secrets.Installed.ClientID
	url += "&response_type=code"
	url += "&scope=" + SCOPE
	url += "&access_type=offline"
	if len(*flag_login) != 0 {
		url += "&login_hint=" + *flag_login
	}
	url += "&redirect_uri=http://localhost:9000"
	//************************************************************

	cmd = exec.Command(CHROME, url)

	err = cmd.Start()

	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("Chrome running")

	//************************************************************
	// Start the web server
	//
	// FIX: This is coded in Python.
	//************************************************************

	fmt.Println("Web server starting")

	out, err := exec.Command("python", "webserver.py").Output()

	if err != nil {
		fmt.Println(err)
		return
	}

	if len(out) == 0 {
		fmt.Println("Error: Missing OAuth2 Code")
		return
	}

	fmt.Println("OAuth2 Code:", string(out))

	AUTH_CODE := string(out)

	//************************************************************
	content := "client_id=" + secrets.Installed.ClientID
	content += "&client_secret=" + secrets.Installed.ClientSecret
	content += "&code=" + AUTH_CODE
	content += "&redirect_uri=http://localhost:9000"
	content += "&grant_type=authorization_code"
	//************************************************************

	endpoint := "https://www.googleapis.com/oauth2/v4/token"

	req := HttpRequest.NewRequest()

	req.SetHeaders(map[string]string{"Content-Type": "application/x-www-form-urlencoded"})

	res, err := req.Post(endpoint, content)

	if err != nil {
		fmt.Println("Error: ", err)
		return
	}

	body, err := res.Body()

	if err != nil {
		fmt.Println("Error: ", err)
		return
	}

	//************************************************************
	//
	//************************************************************

	var tokens OAuthTokens

	err = json.Unmarshal(body, &tokens)

	if err != nil {
		fmt.Println("Error: Cannot unmarshal JSON: ", err)
		return
	}

	//************************************************************
	//
	//************************************************************

	var expires_at int64 = int64(time.Now().UTC().Unix()) + int64(tokens.ExpiresIn)

	var creds UserCredentials

	creds.ClientID = secrets.Installed.ClientID
	creds.ClientSecret = secrets.Installed.ClientSecret

	creds.RefreshToken = tokens.RefreshToken
	creds.Scope = tokens.Scope
	creds.Type = tokens.TokenType

	creds.AccessToken = tokens.AccessToken
	creds.IDToken = tokens.IDToken
	creds.ExpiresAt = expires_at

	//************************************************************
	//
	//************************************************************

	email, err := get_email_address(creds.AccessToken)

	if err == nil {
		fmt.Println("Email:", email)

		creds.Email = email
	}

	//************************************************************
	//
	//************************************************************

	err = saveUserCredentials(SavedUserCredentials, creds)

	if err != nil {
		fmt.Println("Error: Cannot save user credentials: ", err)
		return
	}

	//************************************************************
	//
	//************************************************************

	// debug_displayAccessToken(creds.AccessToken)
	// debug_displayUserInfo(creds.AccessToken)
	debug_displayIDToken(creds.AccessToken, creds.IDToken)

	url = "https://cloudrun-go-test.a.run.app/"

	call_cloud_run_endpoint(url, creds.IDToken)
}

Day #9 thru #19 – June 19 – June 29, 2019

I decided to write a major program in Go. Source code released today (June 29) on GitHub. This program provides a CLI interface to the Google Cloud Shell. This program supports authentication, SSH, SFTP, SSH Key Pairs, launching Putty, uploading files, downloading files, and remote command execution. Almost everything you need to make Cloud Shell part of your development environment.

This program was a lot of work. Not only am I learning the Go language, but I had to work with some new “alpha” level Google interfaces to Google Cloud Shell. Documentation is short on details in some areas. I worked on this program almost every evening for a couple of hours except for June 25, when I did a presentation on Google Cloud Run at the Google GDG in Portland Oregon.

Google Cloud Shell CLI Written in Go

Day #20 – June 30, 2019

No study today. I made several improvements for my Cloud Shell CLI to support Linux.

Day #21 – July 1, 2019

Michael Van Sickle released a rewritten course about Go on June 28, 2019: Go: Getting Started. I really liked the first version and his new course is twice as long. Now that I have written a few thousand lines of Go code and published two programs to GitHub, I want to go back to the beginning and study the basics again. I now have a new perspective on the Go language (which I really like) and I want to polish my technical knowledge. I also plan to Google search for a Go language interview questions list to see what is expected of Go programmers. This should provide me with a list of specific points to study further. In 10 days I plan to take the Pluralsight Go Assessment test and it is time to get ready.

Go: Getting Started Section 1 – 3 (New Course)

Important features of Go:

  • Fast Compilation
  • Fully Compiled
  • Strongly Typed
  • Concurrent by Default
  • Garbage Collected
  • Simplicity as a Core Value

Goal: Do more research on each item to understand the value proposition of Go and contrast with other languages that I know well such as C, C++, C#, JavaScript, and Python.

A feature of Go that created a bug in my program.

package main

import (
	"fmt"
)

func main() {
	x := 1
	fmt.Printf("x = %d\n", x)
	
	{
		x := 2
		fmt.Printf("x = %d\n", x)
	}

	fmt.Printf("x = %d\n", x)
}

Output:

x = 1
x = 2
x = 1

In this simplified example, I used := instead of = because of a bad habit. The end result is that x did not retrain the value that I expected. Note that in the real code this was part of an if statement. Keep this in mind when using the feature := over declaring variables using var statements. Here is a link to this code on play.golang.org

Today I completed the first three sections of Michael’s new course. I am very glad that I did. Excellent review. Also today, Jeremy Morgan (@JeremyCMorgan) send out a tweet about WSL and Visual Studio Code Remote (link to article). In Michael’s course, he uses the same editor. This started me on two paths. 1) to install WSL to use for Go development on Linux and 2) to learn VSCode for Go programming. I setup WSL on my laptop, which was very easy, then installed the Google Cloud SDK into Linux, setup VSCode, etc. Tomorrow I am hoping to learn the “remote” features of VSCode. Very interesting day.

Day #22 – July 2, 2019

Go: Getting Started Section 4 – Working with Primitive Data Types

Good section with an overview of the basic data types. I practiced extensively with pointers today. Go pointers are very similar to C/C++ with some limitations. Go does not support pointer indexing, incrementing, decrementing, etc. Since Go memory is managed and garbage collected, you are limited to what you can do. However, the designers left enough features in Go to make pointers useful.

Go Debugging

I then decided I need to start using a debugger that supports Go. I discovered another course by Michael Van Sickle, Debugging Go Applications with Delve (link). Extremely good “must watch” course. I finished sections 1, 2 & 6. Practiced debugging in both the command line and with Visual Studio Code. I have extensive experience with Visual Studio Professional in C/C++ and using Go with Visual Studio Code feels very natural.

Now I will try to figure out remote debugging with Visual Studio Code. My goal is developing on Windows and debugging both Linux and Windows Go programs on a remote system which is my laptop running Windows 10 Home and WSL Debian.

Delve Debugging Commands to study:

    args ------------------------ Print function arguments.
    break (alias: b) ------------ Sets a breakpoint.
    breakpoints (alias: bp) ----- Print out info for active breakpoints.
    call ------------------------ Resumes process, injecting a function call (EXPERIMENTAL!!!)
    clear ----------------------- Deletes breakpoint.
    clearall -------------------- Deletes multiple breakpoints.
    condition (alias: cond) ----- Set breakpoint condition.
    config ---------------------- Changes configuration parameters.
    continue (alias: c) --------- Run until breakpoint or program termination.
    deferred -------------------- Executes command in the context of a deferred call.
    disassemble (alias: disass) - Disassembler.
    down ------------------------ Move the current frame down.
    edit (alias: ed) ------------ Open where you are in $DELVE_EDITOR or $EDITOR
    exit (alias: quit | q) ------ Exit the debugger.
    frame ----------------------- Set the current frame, or execute command on a different frame.
    funcs ----------------------- Print list of functions.
    goroutine (alias: gr) ------- Shows or changes current goroutine
    goroutines (alias: grs) ----- List program goroutines.
    help (alias: h) ------------- Prints the help message.
    libraries ------------------- List loaded dynamic libraries
    list (alias: ls | l) -------- Show source code.
    locals ---------------------- Print local variables.
    next (alias: n) ------------- Step over to next source line.
    on -------------------------- Executes a command when a breakpoint is hit.
    print (alias: p) ------------ Evaluate an expression.
    regs ------------------------ Print contents of CPU registers.
    restart (alias: r) ---------- Restart process.
    set ------------------------- Changes the value of a variable.
    source ---------------------- Executes a file containing a list of delve commands
    sources --------------------- Print list of source files.
    stack (alias: bt) ----------- Print stack trace.
    step (alias: s) ------------- Single step through program.
    step-instruction (alias: si)  Single step a single cpu instruction.
    stepout --------------------- Step out of the current function.
    thread (alias: tr) ---------- Switch to the specified thread.
    threads --------------------- Print out info for every traced thread.
    trace (alias: t) ------------ Set tracepoint.
    types ----------------------- Print list of types
    up -------------------------- Move the current frame up.
    vars ------------------------ Print package variables.
    whatis ---------------------- Prints type of an expression.

Day #23 – July 3, 2019

In practicing the Iota and Constant expression section of “Go: Getting Started Section 4 – Working with Primitive Data Types”, I ran into a surprise. Take a look at the following code and try to guess what will be printed.

package main

import (
	"fmt"
)

const (
	first = iota
	second = iota
	third = 0
	fourth = iota
	fifth
)

func main() {
	fmt.Println(first, second, third, fourth, fifth)
}

Output:

0 1 0 3 4

I set third to zero and started another iota. I expected fourth to be zero, thinking that constant iota expression started over. Instead, it is three. If I move fourth and fifth to another constant block, it works as I expected.

Day #24 – July 4, 2019

Today, I ran across a #golang tweet with an interesting quiz. One that I did not know the answer to. So I sent out a tweet asking for the answer. This tweet surprised me and generated a large amount of activity (4,000+).

The original tweet by @dastanng:

#golang what does this program print?

package main

import (
    "fmt"
)

type foo struct {}

func (f *foo) hi() {
    fmt.Println("Hi.")
}

func main() {
    var f *foo
    f.hi()
}

I received an answer from Bill Kennedy @goinggodotnet : “Methods are just functions and think of nil as a value like any other that the variable could contain. So nil is passed into the method call as the receiver value. Since the method does nothing with the receiver variable, there are no exceptions.”

I then spent an hour or so studying methods with information from this article: “Golang Methods Tutorial with Examples

Day #25 – July 5, 2019

This morning I started another course by Michael Van Sickle: “Building Better Go Web Apps with the Gorilla Toolkit“. This time I had an objective. I wanted to study HTTP/web sessions and cookies in Go. I started with Part 6: “Gorilla/Securecookie: Securing Sensitive Information” and then part 8 “Gorilla/Sessions: Persisting Information between Calls”. Excellent material.

Day #26 – July 6, 2019

Today, no Go studies. I published two articles today: Google Cloud – HTTP Load Balancer File Upload Error and Google Cloud Run – Minimizing Cold Starts.

Day #27 – 30 July 7 – 10, 2019

I was not able to study at all. Too many commitments. One of them was a presentation on Google Cloud Run.

Day #31 – July 11, 2019

This is the planned day for taking the Pluralsight “Go Skill Assessment” to measure what I accomplished.

July 14, 2019

Go to Part 2 to see my results.

Credits

I write free articles about technology. Recently, I learned about Pexels.com which provides free images. The image in this article is courtesy of Vural Yavas at Pexels.