One moment of silence for Joe Armstrong who taught me how to write software.

Go is my favorite programming language when I am serious about what I am doing. This is a potential sequence of posts about thinking in Go it starts with a chaotic introduction for now. In the future you can expect a more structured type of posts.

Why you don’t like Go

Go is boring.

Boring isn’t interesting. Go has no fancy features or cool operators like |> . Besides interfaces, concurrency and the type sytem it’s a similar language to C , but those features are what makes Go GO . Go is a different specimen than C, in Go it’s better to deal with things as they are. A Mistake many new Gophers make is pointers everywhere under the false assumption that pointers = optimization and what do we say to them ? Not here nor today .

The language is simple, the spec is readable but sometimes you’ll find yourself wishing for more. Take built-in data structures Go offers arrays ,slices and a map type . This is mostly what you’ll need given that any type can be built using a combination of these. A tree or set can be built using slices and maps or simply plain C like trees with pointers which is the best way.

Go package management isn’t ideal,on the other hand being able to build and deploy a binary to most supported operating systems makes it acceptable.

I accept all Go shortcomings because it makes it easy to write software and build systems.

After all Go inventors encourage writing more or generating more.

P.S : The go.mod that was introduced earlier this year makes package management sane and simple.

Why Go gets shit done

Any programming language comes with an overhead for usage:

Learn the syntax -> Learn the tooling -> Learn the libraries -> Repeat

I bet you always check syntax quirks while writing code, because keeping with all the different constructs is hard. In Go’s case the syntax is easy to grasp if you dabbled with Python or C. It’s simpler than both in terms of overall design. You get a standard formatting tool (gofmt) and you don’t need to remember semi-colons; On top of that you have all the tooling you’ll need (profiling, benchmarking, tests …)

There is really nothing surprising about Go, that’s what I like the most , you get what you write .

Go doesn’t have inheritance, polymorphism nor even function overloading. A lot of what could make code more complex is removed this results in a predictable and simple design of software.

I think the Go approach to programming is close to structured the style you find in Niklaus Wirth book . And I think that the most suitable way to write programs is this, you shouldn’t burden yourself with thinking about the language but more about the program .

Algorithms + Data Structures = Programs

OOP in Go

I won’t rehearse OOP histroy… but let’s focus on the few concepts that are OOP-esque in Go .

Methods

Methods in Go can be thought of as functions and choosing between whether to use many methods or one function depends on how many degrees of freedom you have to link them trough interfaces . Or whether you need to modifiy your object internal state.

A Rule of thumb I use

Methods for mutating state / Functions for not mutating state .

If I need to add more items to an underlying shopping list then a method Add gives more context about the code. While checking whether items in a shopping cart are available in stock a function RemoveNotInStock could be better .

This is a functional-ish way to do things especially since your code no matter how abstract it is, remains about manipulating sequences of data and operating on them. But Go isn’t functional the way Ocaml is , and trying to make Go functional is really a bad idea. First you hack your way by using interface{} to simulate a generic style and second Go isn’t functional so don’t make it so.

Interfaces

Go encourages a design where behavior is a signature. Behavior for a type stands for the operations or operators you can use with or on the type a signature is a way to unify this behavior accross many types.

For example :

type Tree interface { Find ( value int ) ( int , error ) Insert ( value int ) ( error ) New ( values [] int ) ( error ) } type AVLTree struct { // pointers and what not } func ( avl * AVLTree ) Insert ( value int ) error { // Rotational Ninja ... } func SearchItems ( items [] int , tree * Tree ) { // search items using a tree for some reason tree . Find ( items ) } var avl AVLTree var bin BinaryTree SearchItems ( items , avl ) SearchItems ( items , bin )

What you need is an abstract type , what you use under the hood are different implementations for that type. Hence the famous accept an interface and operate/return an actual structure type when needed.

type DB interface { Get ( key [] byte ) ([] byte , error ) Put ( key , value [] byte ) ( error ) Delete ( key [] byte ) ([] byte , error ) } type DiskDatabase struct { underlyingFile * os . File transactions list . List ... } type MemoryDatabase struct { memdb map [[] byte ][] byte ... } func Store ( key [] byte , value [] byte , db DB ){ db . Put ( key , value ) // error processing ... } var fd = NewDiskDatabase ( filepath ) Store ([]byte( "gopher" ),[]byte( "is cool" ), fd )

Interfaces communicate an intent between your parts they give you the freedom to switch between underlyings when you need them . Your interfaces should be simple, aimed to communicate an intent and that’s it. Interfaces are helpful to build behavior that is independant of the behavee.

Conclusion

How I use Go is by building my program from a set of parts. Each part does a task (encoding types to binary, storage, network protocols, numerical algorithms…) and in my program I write my principle functions in a way that operates on an interface that is fullfilled by the parts. Every part can be different for example CBOR or MessagePack or BSON are all viable solution to encoding types to a binary format that can be written to disk or sent across a network. But the functions only know BinaryMarshaller hence I can implement a method using MessagePack but later replace it with CBOR.

Celebrate Simple .

Notes

Go has some usage pitfalls they’re mostly biases from previously used language or maybe misunderstanding the language itself. I compiled a list of posts and articles that will help cover these Gotchas, the ressources are ordered in no particular order explicitly but they’re ordered implicitly to ease understanding.