Go “On The Fly”

David Pitt Keyhole Creations, Programming, Technology Snapshot, Tutorial Leave a Comment

People that know me, know that I love to fly fish and tie flies. I made up the saying “Time flies when you’re tying flies.” It is true, just like when you are trying to solve a programming problem, time flies.

Over the past few years, we at Keyhole have utilized Docker (with assorted technologies) and have gotten up to speed on the Hyperledger blockchain framework. Something that all of these technologies have in common is the Go language. Go is the language used to implement Docker, Hyperledger, OpenShift, and many other system-level applications.

Personally, I like to peek under the hood to better understand the tools I’m using. That led me to learning about the Go language. And in my opinion, the best way to learn a language is to build something.

So, I built an application for fly tying videos. There are numerous fly tying tutorials on YouTube, so I built an application that allows them to be organized into virtual fly boxes and types.

In this blog, I will introduce you to the Go language. We’ll go over some of the key language concepts by walking through how the https://flytyerworld.com server-side API is implemented using Go.

Note: The user interface was written in React, but this blog is not about React. So, if you’re interested in React, instead check out the blog “Getting Started with React.

A screenshot is shown below, and here’s a link to the deployed application: https://flytyerworld.com

About Go

Go was released in 2003 by Google. Here is the Wikipedia description of it…

“Go, also known as Golang, is a statically typed, compiled programming language designed at Google by Robert Griesemer, Rob Pike, and Ken Thompson. Go is syntactically similar to C, but with memory safety, garbage collection, structural typing, and CSP-style concurrency.”

While there are many languages that are typed and have garbage collection, what differentiates Go from the pack is Communicating Sequential Processes style concurrency. CSP style processing means that currency in Go is handled by processes and the channel communication between these processes. This is opposed to concurrency (in languages such as Java), that use preemptable operating system threads that are managed by the developer.

Go implements concurrency using Goroutines. They are not individual threads or processes. Instead, they manage and hide the complexity of multiplexing OS threads in order to eliminate blocking and improve performance.

The blueprint for Goroutines originates in the theory of CSP concurrency that was introduced in a 1979 paper by Tony Hoare. It has since been known as Hoare’s Communicating Sequential Processing (CSP). There is a great deal of information on this subject, but in a nutshell, concurrent GoRoutines communicate through channels, not shared memory. Developers don’t have to apply synchronization logic. An analogy compares GoRoutines CSP style of concurrency to Unix pipelines.

The bottom line is that Go makes concurrent programs safer and easier to implement.

Go Syntax

I like Go’s simple syntax style and its different take on type and function definitions. Go is a free form language; white space and position are insignificant. Like most modern languages, however, there is no end-of-line punctuation required, like a semicolon.

Go is statically typed, with type inference. Here is how a variable is defined:

Type Inferred

var count = 0

Here is a variable definition with type and default value:

var count int

Notice the type definition is at the end of the expression. Multiple definitions can be defined and initialized in one expression.

var a,b int = 10, 20

Here is an interesting shorthand syntax for declaring and assigning a value to a variable.

a := someFunc()

The := command combines the variable assignment and declaration into one expression. Using just the = is just an assignment operation. The previous function without using just = is done this way.

var a int = someFunc()

Object-Oriented?

Technically, Go is not object-oriented, there is not a class constructor inheritance in the language. However, just as you would with traditional object-oriented languages, you can still apply encapsulation, define stateful objects, and use delegation and composition to implement generalized configurable algorithms.

Go allows data structures to be defined so that you can define and operate against custom types. Here is an example:

 type Employee  struct { 
  First         string
  Last         string
  Salary      float 
  Email       string		
 }

Here is how a structure is created:

  emp := Employe{ First: “Clifford”, Last: “Squidlow”, Salary: 95000.00, Email: “[email protected]” }

Assign or access properties like this:

  emp.LastName  
  emp.LastName = “Jones”
 

Structures can also have structures nested within themselves to provide a more complex type. However, in my opinion, it would be best to steer clear of this type of structure.

Functions

Algorithms and logic are defined in function definitions. Functions signatures are the same as other languages, just in a slightly different order. Here’s a function definition example:

func Myfunc ( id int, description string) string { 

     …..

   return “hello world”
}	

Notice, input parameter types are defined on the right side of input parameters, and the return type of the function appears after input parameters. This allows them to be optional, if the type can be derived.

Another unique feature of Go is that it has the ability to have multiple return types. Here is a very simple function that returns a string saying hello and the current date time.

func SayHello( ) (string, time.Time) {

   return “hello’, time.Now()

}	

Here is how the function is called and how the return types are handled:

f, dateTime := SayHello()

log.Println(f,dateTime)

If you call a function with multiple return types, but you do not want to care about all the return types, then you can use an underscore to tell the compiler to ignore a specific return type. An example of this is shown below:

        f,_  := SayHello()

The _ operator is important because if you have a variable definition in a method, then it must be used somewhere. If not, you will get a compile error. Therefore, this command allows you to tell the compiler to ignore return values.

Anonymous Functions & Closures

You can treat functions as data in Go. In other words, a function can be assigned to a variable and passed around like a piece of data. This is commonly referred to as “anonymous functions”.

See Also:  Integrating Azure Functions with Cosmos DB SQL API in .NET Core 2.2

Here’s a simple anonymous function defined and used:

   ...
    SayHello := func(s string) string {
        return "Hello World ->" + s
    }
  
   log.Println( SayHello(“David” ) )           // Outputs “Hello World -> David 	

  …
 

Anonymous functions are often used to define closures, but named functions can as well. Defining closures allows data to be preserved within enclosed anonymous functions, and data within this scope lives beyond the function call life. This scope is referred to as the closure. The example below returns an anonymous function from a function:

func counter() func() int {
    i := 0
    return func() int {
        i++
        return i
    }
}

Since the function returned from a function operates upon a variable in the outer enclosing scope, this variable state is preserved between function calls. The usage example shows this below:

c := counter()

c()
c()
c()

log.Println("Current Count -> ", c()) // Results will be “Current Count -> 4”

The returned anonymous function is the closure since it preserves the int i variable value, defined in the outer function.

Methods

Yes, I said Go is not really an object-oriented language, and yes, I said Go has methods, but let me try to explain. Structures were introduced previously where you could create a customer data type of arbitrary typed elements. Method functions can be bound structures giving operations behavioral methods. To see this, consider the following Boat Steering structure definition.

	type Steering struct {
	      Rudder       int   // 0 - 35
	      Direction     int   // 1 right   -1 left
	      Speed	 int    // knots 0 - 20
} 

The Steering structure has a direction and Speed and Rudder values. Method functions can be defined and bound to a structure to give the structure behavior, like an object. Below are the method implementations:

         func (boat Steering ) rightFullRudder() {
		boat.Rudder = 35
	            boat.Direction = 1
                        boat.Speed = 20
         }   


           func ( boat Steering ) leftFullRudder() {
		boat.Rudder = 35
	            boat.Direction = -1
                        boat.Speed = 20
          }   
        
      func ( boat Steering ) rudder(direction int, degrees int) {
		boat.Rudder = degrees
	            boat.Direction = direction
                        boat.Speed = 20
          }   
	

        func (boat  Steering)  increaseSpeed( knots int) int {
	  return boat.Speed += knots
	}

A method differs from a function in that the structure type name is defined before the method name. This binds the function to the structure state. Here is an example of method use:

      
	s := Steeringt{Rudder: 0 ,Direction: 1, Speed: 20}
            s.rightFullRudder()
            s.rudder(-1,5)
            currentSpeed := s.increaseSpeed(10)

Go has some object-oriented type behaviors. But, it does not have inheritance features — rather, it promises composition over inheritance in design. Which is preferable? That is a subject for another blog.

Interfaces

Define abstract types and interfaces in Go to help enforce contract types and apply polymorphic designs. Here is an interface type definition:

      type Navigate interface {
	  rightFullRudder() 
  leftFullRudder()	
	  rudder(direction int, degrees int) 
              increaseSpeed(knots int)
      }      

Developers do not implicitly implement interfaces. Instead, the Go compiler matches the interface methods with function signatures, allowing one or more functions to be treated as the interface type.

Here is the interface applied to a complete implementation:

type Contact interface {
    name() string
    location() string
}

type Person struct {
    First   string
    Last    string
    Address string
}

func (p Person) name() string {
    return p.First + p.Last
}

func (p Person) location() string {
    return p.Address
}

type Business struct {
    Name    string
    Address string
}

func (b Business) name() string {
    return b.Name
}

func (b Business) location() string {
    return b.Address
}

type Web struct {
    URL string
}

func (w Web) name() string {
    return w.URL
}

func (w Web) location() string {
    return w.URL
}

func main() {

    p := Person{First: "Clifford", Last: "Squidlow", Address: "123 somewhere Suite, Leawood, KS"}
    b := Business{Name: "Keyhole Software", Address: "8900 Stateline Road Suite 455, Leawood, KS"}
    w := Web{URL: "wwww.keyholesoftware.com"}

    printLabel(p)
    printLabel(b)
    printLabel(w)

}

func printLabel(contact Contact) {

    log.Println("Name:", contact.name())
    log.Println("Location:", contact.location())

}  

The example above defines a Contact interface. It defines three unique structures for Person, Contact, and Web. Notice the definitions for each of these structures with signatures that match the Contact interface. The main method sets values to these structures, and then they are passed into a printLabel(Contact) method. The interface allows for a polymorphic print label to be applied.

Public/Private

Go does not have a public/private keyword to control the visibility between packages/modules. Although we have not covered this topic yet, functions and variables defined in packages form a module. Packages are text files containing source code having the extension of *.go. Here is a simple package definition example:

// This would be in a file named foo.go
package bar

func BeyondAllRecognition() string { 
     return “Yep, it is..”
}

Import the bar package into another package with the following command:

 package foo 

 import (
 
     “./path/to/package/bar”   
	
)

func main() {

       bar := bar.BeyondAllRecognition()
}

How is public-private visibility applied through convention? A public function structure or variable begins with an uppercase letter is public. Otherwise, it is private.

So, if the BeyondAllRecongition () function is changed to beyondAllRecognition(), the example would not compile. In my opinion, this is cleaner and less wordy than having to apply public/private to elements.

Dependencies

Note that a set of supporting packages are installed and available with the Go SDK. Below you can see how dependent package modules are brought into a package for use:

 import(
	"log"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"github.com/gorilla/mux"
)

Notice that the package, such as log and os, does not have a qualifying path. This is because they are available with the based Go implementation. The mux package is qualified with its Github repository path. Github acts as the Go source code and dependency management repository.

Pointers

Pointers, as in C, point to a memory location where a value is stored. Defining a pointer allows accessing values by “reference” (as opposed to by “value”), as is the case of passing non-pointer variables into functions. As in the C language, create a pointer to a value by applying a & prefix to a variable name. Get a pointer’s value by prefixing a * to its name.

Here is a usage example illustrating how pointers work. Consider the Add function shown below:

func Add(a int, b int, c *int) {

    *c = a + b

}

The C parameter is an integer pointer, meaning that a pointer to the memory location is passed in, rather than the actual value. Using the function example is shown below:

    sum := 0
    Add(10, 20, &sum)

    log.Println("10 + 20 =", sum) 

The sum variable is dereferenced to a Pointer(memory address) using the & operator. This allows the Add function to set the sum variable located outside of the function. As you can see by the results, execution would output that value:

       “10 + 20 = 30”

Looping Structures

The for loop is the only looping structure in Go. There is not a while or do while loop mechanism. I’m not sure why, other than compiler simplicity and optimization. Here is an example:

for   i := 0 ; i < 10 ; i++ {
    ….
   …..
} 

This is straightforward; there are no parentheses required around the looping control expressions, saving keystrokes. However, parentheses are always required around the loop code block expressions. I think that this is a good thing. Personally, I always apply code block {..} operators, even with one line expressions.

See Also:  Gaining Docker Image Size Efficiencies By Separating Application Layers

Go’s if...else... statements work the same way. There is no need for parentheses to enclose the boolean expression.

Real-World Implementation

Now, let’s jump into a real-world implementation. A lot of Go’s momentum has been from developing system-level applications such as Docker, OpenShift, Hyperledger Fabric, to name just a few. I’ve also read that Google is replacing its server-level software implementations (that traditionally use C++ or Java) with Go.

We created the https://flytyerworld.com web application server-side RESTful API that persists data to a MongoDB instance. The site has basic CRUD-type behavior. It seems as if I have been writing the same CRUD application for 30 years :).

I will start with the API implementation. Go has an HTTP package that can be used to start an HTTP server to listen for TCP requests. Here is how a server is started:

           router := mux.NewRouter()
           router.HandleFunc("/api/videos/{category}", getVideosByCategory).Methods("GET")
http.ListenAndServe(":8080”, router)

A router matches the RESTful API routes to the appropriate handling function. The example below routes api/videos/somecatetory coming across port 8080 that will be handled by the getVideosByCategory function. The mux package and open-source package both enhance routing capabilities. Here is a link to the Github website: https://github.com/gorilla/mux.

Here is an example of the GET-handling function implementation:

// getVideosByCategory - get all videos
func getVideosByCategory(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	v := videos.GetByCategory(vars["category"])

	_ = json.NewEncoder(w).Encode(v)

}

All HTTP verbs are supported. Here is how a POST route is registered with the router:

    router.HandleFunc("/api/addflyboxitem", addFlyboxItem).Methods("POST")

Additionally, here is the implementation of the POST addFlyboxItem handling function:

// addFlyboxItem - Add  flybox
func addFlyboxItem(w http.ResponseWriter, r *http.Request) {

    if enforceAdminRole(r) {

        decoder := json.NewDecoder(r.Body)
        var t FlyboxItem
        err := decoder.Decode(&t)
        if err != nil {
            panic(err)
        }
   
        boxID := t.BoxID
        youtoob := t.YoutubeID
        userid := t.UserID

        b := flyboxitem.Create(boxID, youtoob, userid)

        // Nofity users watching fly boxes

        go notify.WatchNotify(boxID)

        _ = json.NewEncoder(w).Encode(b)
    } else {
        http.Error(w, "Add Flybox item user has no admin session", http.StatusInternalServerError)
    }
}

As you can see, handling API routes is fairly straightforward.

Now, let’s talk about database access. We decided to use the mgo https://labix.org/mgo library that implements a Go client for MongoDB. A Go package is basically defined for each collection (or table in SQL speak). Each package has logic to obtain a database connection. There is a connection pooling utility implemented to help manage collections. We define a data structure, as well as the functions that operate against that structure by writing and reading it from the MongoDB database.

Here is a partial listing for the flybox.go package:

package flybox

import (
	"fly-world/utils"
	"log"
	"os"
	"time"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

// Flybox - structure
//noinspection GoNameStartsWithPackageName
type Flybox struct {
	ID          bson.ObjectId `bson:"_id"`
	Name        string
	Description string
	UserID      string
	Type        string
	Private     bool
	Date        time.Time
}

// FlyboxWrite - structure
//noinspection GoNameStartsWithPackageName
type FlyboxWrite struct {
	Name        string
	Description string
	UserID      string
	Type        string
	Private     bool
	Date        time.Time
}

var db string

const flyboxCollection = "flybox"

// Init - initialize
func init() {

	var isPresent bool
	db, isPresent = os.LookupEnv("MONGO_DB")
	if !isPresent {
		db = "flyworld"
	}
}

// GetForUserID - retrieve for userid
/*func GetForUserID(userid string) []Flybox {

	tsession := utils.Dbsession()

	var results []Flybox

	c := tsession.DB(db).C(flyboxCollection)

	err := c.Find(bson.M{"UserID": userid}).All(&results)
	if err != nil {
		log.Fatal(err)
	}

	return results

}*/

// GetAll - retrieve for userid
func GetAll() []Flybox {

	tsession := utils.Dbsession()

	var results []Flybox

	c := tsession.DB(db).C(flyboxCollection)

	err := c.Find(nil).All(&results)
	if err != nil {
		log.Fatal(err)
	}

	return results

}

// Create - create new flybox
func Create(userid string, name string, description string, tipe string) FlyboxWrite {

	var flybox = FlyboxWrite{Name: name, Description: description, UserID: userid, Type: tipe, Private: false, Date: time.Now()}

	tsession := utils.Dbsession().New()

	// Optional. Switch the session to a monotonic behavior.
	tsession.SetMode(mgo.Monotonic, true)

	c := tsession.DB(db).C(flyboxCollection)

	err := c.Insert(flybox)
	if err != nil {
		log.Fatal(err)
	} else {
		log.Println("Inserted flybox", name)
	}

	return flybox
}

…. Partial listing.. 

You can see that it is fairly straightforward; we define a data structure, as well as functions that retrieve and create fly boxes in MongoDB. This illustrates the ability for Go to eliminate boilerplate code.

If you implemented an API that performs CRUD operations against a data source in Java or C#, it would require more elements to be defined. (Think DTO/DOMAIN classes, controller classes, maybe repository O/R mapping classes, and probably a service class in between the controller and repository classes.) I am not saying that that is incorrect, I am just making an observation. I will let the users come to their own conclusions on which is better.

Remember it’s compiled, just saying

Go is intended to be an easy-to-learn performant language that can compete with the C language. Since it compiles to machine code, like C, it performs very well.

We wanted to compare the memory footprint of Go with .Net Core and a Java/Spring Boot-based application. We did this by creating a simple API service in all three languages and checked out the memory footprint. The results are shown below:

Each API implementation was contained into a Docker container and deployed to the same Kubernetes managed infrastructure. A user load was applied to all three services. As you can see, Go used only 17.9 MB of memory compared to Spring Boot’s 221 MB and .NET Core’s 142.5 MB of memory. That is A LOT, and could be a big factor in serverless-based implementations.

Wrap Up

My experience with Go has been positive. It’s a language that is easy to wrap my head around and I have enjoyed working with it.

Most of our enterprise customers utilize .NET or Java technologies. This makes sense as each have each been around for a long time. Both have plenty of developers, tooling, and large corporate sponsors or owners.

With that said, I will certainly consider Go as a viable alternative in the future when the essence of all requirements focus on high performance and low footprints. It’s a great choice, as well, when involving a CLI or system programming-oriented use case.

What Do You Think?