Are you a software craftsman? here is why you should become a Gopher

After a whole year of radio silence, what better topic to blog about than software development?

I've lately been back to my roots and coding my head off, and let me tell you it has been an exhilarating nirvana to able to sit down and code out of passion for a change, and this brings me to my topic of choice, software craftmanship and of course Gophing -a little about that later-.

Software craftsmanship

There are software developers, engineers and then there are craftsmen; those rare bread who take pride of their code, fantasize about DSLs, make a big deal of non-standard code styles and worship programming languages for their design.

A software craftsman has no language of choice, his skill is learning, he will glance at an alien programming language syntax, one that he hasn't picked up yet, and start imagining how he can express himself in that new language.

Programming is simply a sixth sense for software craftsmen; they do it unconsciously not out of talent, but out of passion.

I like to think of myself as a Software craftsman rather than a developer or engineer, I indulge in my creations, I take pride of my development environment and I'd pick up a new language not because its hip but because I fell in love with the beauty of it's syntax and the eureka moment reading its design and features.

This is exactly why I've been a Ruby developer for the past 7 years, C# for 5 years and C since forever, even Assembly to me is art, its this feeling I get when I write in those languages, the feeling of `flow`, how the language can shape at your fingertips to express your exact intention for your project without hassle or monkey business (not monkey patching, I actually believe I'm a code baboon :P).

Although I'm a monkey, recently I decided to be a Gopher and `gooph` around a little bit; being a Gopher is writing in Google's GoLang, and here is why you, as a software craftsman/woman, should become a gopher too.

Beauty is in the eye of the beholder

I wont yap about how beautiful Go is, list its features, how satisfying is it's pointer arithmetic, its amazing typing, or how ingenious its approach to parallelism and concurrency.

You probably can pick up on all of those googling the web and watching the many youtube videos about it.

Instead, I'll show you a simple function from the prototype for CodeTime, my next venture.

func ReadBuffer(reader io.ReadWriteCloser, nbytes int, result interface{}) (bytesRead int, err error) {
    byteBuffer := make([]byte, nbytes)
    bytesRead, err = io.ReadAtLeast(reader, byteBuffer, nbytes)

    if err != nil {
        return
    }

    Logger.Tracef("Read %d byte(s)", bytesRead)

    switch result := result.(type) {
    default:
        Logger.Tracef("Reading into type: %T", result)
    case *byte:
        *result = byteBuffer[0]
    case *[]byte:
        *result = byteBuffer
    case *int:
        var ret int
        for i := 0; i < nbytes; i++ {
            ret <<= 8
            ret += int(byteBuffer[i])
        }

        *result = ret
    case *uint:
        var ret uint
        for i := 0; i < nbytes; i++ {
            ret <<= 8
            ret += uint(byteBuffer[i])
        }

        *result = ret
    case *string:
        *result = string(byteBuffer)
    }

    return
}

This piece of beauty has so many things to talk about than I can, but I'll try to make you see why this is an amazing piece of code.

This function simply reads nbytes bytes from a buffer reader into result and returns the bytesRead bytes read and err error (if any), seems pretty straight forward right?

Well in its own way its simple, first lets look at the function definition

func ReadBuffer(reader io.ReadWriteCloser, nbytes int, result interface{}) (bytesRead int, err error)

Like other languages this defines a function called ReadBuffer that takes reader, nbytes and result as arguments, and like some languages it defines multiple named return arguments bytesRead and err.

Lets start with the return values; you might think why would I name my returns, won't this limit me and others when I use this function? well no, you see naming your returns dont force the names on other functions that consume your function, on the contrary, this actually does 2 things:

  1. It declares your return variables within your function scope, which saves you a couple lines of code.

  2. It allows you to just type return and it will smartly return your variables without having to specify them.

For me this is just beautiful, its descriptive and allows you to understand what this function returns by just glancing at it's definition.

Next, lets look at input parameters; you might have already noticed that unlike the norm in other statically typed programming languages, Go actually defines the variable type on the right handside of the expression rather than the left, this is not done for the fun of it, but I won't go into that right now, instead you can read about it here.

Other than the variable declaration, there is one really wierd keyword out there, interface{}, this little genius keyword is the base of Go, its why Go's standard library is the best in my opinion.

Interfaces in Go serve a great deal of importance, however they are not implemented the way you'd expect, instead of forcing explicit interface implementation on objects, Go just doesn't, instead you implement an interface by just implementing its functions, without explicity saying your object implements the interface.

What this does is allow an object to implement multiple interfaces, in other words, cat words to be exact, "If I fits, I sits", if that object can perform these function then it can pass as this interface.

Now back to our function definition, the interface{} declaration here serves as a general type, which is very useful when you want your function to take in variables that you are not sure what their type is or you want it have it take multiple types without the need to rewrite the method again for each type.

In our case, I want the ReadBuffer to read the number of bytes from the buffer and save the result in the result variable which can have different types that is only known at runtime.

To understand how this is done, lets look at the switch statement:

switch result := result.(type) {
default:
    Logger.Tracef("Reading into type: %T", result)
case *byte:
    *result = byteBuffer[0]
case *[]byte:
    *result = byteBuffer
case *int:
    var ret int
    for i := 0; i < nbytes; i++ {
        ret <<= 8
        ret += int(byteBuffer[i])
    }

    *result = ret
case *uint:
    var ret uint
    for i := 0; i < nbytes; i++ {
        ret <<= 8
        ret += uint(byteBuffer[i])
    }

    *result = ret
case *string:
    *result = string(byteBuffer)
}

This is a type switch statement, meaning that its cases are variable types instead of values; here we check if result is either a byte, byte slice, int, uint or string, and accordingly do the required conversion and save it in result.

But notice the * before the variable types and result, this is the pointer operator that you can see in C and C++, it allows you to have variables that point to memory locations instead of values, which means that you can directly edit that memory location even though its assigned outside of the current function scope, and in this case, it allows us to pass the memory address for the variable we want the bytes stored in, and have it updated with the result instead of returning it in a return variable.

Its just amazing that we can do this without reflection and out of the box without having to import extra libraries in a statically typed language.

Also being statically typed, Go is light years faster than its dynamically typed counters, not to mention being much less prone to errors that usually comes with type uncertainity in dynamically typed languages.

Conclusion

I hope this ~1400 words blog gave you some insight of Go and optimistically convinced you (the amazing next Linus Tovalds) to pick up Go and start crafting some cool stuff for the world and more specifically for the Go community.