I tried out Go as part of my “2 weeks with Go” challenge and wanted to share my experiences as I … go.

package management

Go’s package managemenet is completely bizarre. At first, I thought it was awesome. You don’t have a package.json, you don’t have any crazy dependency trees, you simply list a package, and run go get. The way you list your package is directly in your import statement and you list it by basically telling Go where its repo is. So there is no centralized repository database. Any Github/Bitbucket/Whatever repo can be imported and installed.

The weird thing is that there is no version management. There is no semver, and there is no built-in way to even pull a dependency in by a tag. You simply install it at the latest version or keep your current version (whenever you installed that). This can lead to huge issues.

The canonical way to deal with it? Either you fork the repo and manually pull in changes from the master repo or you keep a copy in the source tree. This is just bizarre to me but there seems to be a lot of thinking behind it. Namely, Google uses the source tree method internally where it keeps a copy of the entire dependency tree at all times and updates manually per package.

However, if you’re used to NPM or Bundler, you might prefer looking at the third-party package managers.

Type system

I’m not entirely too familiar with type systems. I learned some C++, C, C#, and Java over the years but not enough to be an expert. One thing I found strangely confusing was the various instances in which declaring a variable changes. For instance, here are a few ways you can declare a variable within a function:

var i int = 0
var i = 0
i := 0

All three are valid with the latter two having inferred types. The weird thing is that there are restrictions on when and how you can use these three methods click to read more. For instance, if you’re declaring a variable outside of a function (meaning at the same level as, say, import), you can only use var to declare it. You can’t use the short way of variable := value.

On the flip side, I’ve noticed that in a for loop, you can’t use any other variable declarations than variable := value. Meaning that what you can’t do is the following:

for var i int = 0; i < 10; i++

Or declare the variable type. I suppose that this is because that variable’s lifecycle ends when the loop ends and is not as important.

I guess overall, the weird thing is that unless you’re declaring an empty variable, you don’t have to know the type.

I find your lack of parentheses disturbing

Go decided to do away with the frivolous, from the lack of semicolons to the lack of parentheses. The fact is, this bothers me. The semi-colons not so much (despite the fact that I do, in fact, like them), but the lack of parentheses, yes. Let’s look at an example of an if statement:

var l int

if v := someData; v < 7 {
    l = v
} else {
    l = v + 5
}

In this statement, we are creating a temporary variable for the if block (and the else block). What I see is basically a huge mess. That if statement will look crazy the longer it gets. Without parentheses to separate the if and the brace, everything goes together. Just look at this (rewritten, imaginary) rewrite:

if (v := someData; v < 7) {

Isn’t that better? For loops are even worse, take this example of looping through an array:

for ind, val := range myArr {

}

or a traditional for loop:

for i := 0; i < 10; i++ {

}

That looks like gibberish to me. I come from a JS background, which means that you have to be as precise with your statements as possible. That means that you litter your code with ; everywhere they need to be, you put parentheses around everything and you even use a linter to make sure you didn’t forget one place.

But…I’m getting used to it.

At least they still use braces. At least…at least there’s that.

Note: Did you know that Go’s codestyle is built-in? Yep, no more arguing over spaces vs tabs, or where to put what brace. Go has a tool called gofmt and you can run it via go fmt /path/to/package and it’ll format ALL of your code.

Intuitive helpers

You know how sometimes there are some basic things you do, and you wonder why a language makes it such a run-around? Go has impressed me so far with its ability to predict how you’ll use a language and provide you with a ton of cool shortcuts. For instance, we’ve talked about the for loop, right? I absolutely love the way it works. The for loop is super versitale meaning that it takes on a few different shapes.

Let’s say we want to run an infinite loop, most languages let you do that with while(true) and then break out of it. Using while(true) seems like a hack, a workaround. If you had a for loop, the traditional way to do this is with for(;;), basically skipping all arguments. Well, Go lets you bypass all of that with just for { }, that’s it. Just for, and it loops until you break it.

What about a while loop? A while loop is basically for (; condition ;) { }. The middle condition is the one condition that gets tested in the end, nothing else. So, a while loop in Go is just for condition.

I find this very cool since it basically recognizes where all these very intuitive. The next cool one is the switch. A basic switch look somewhat like this:

switch value {
    case valueA:
        someFunc()
    case valueB:
        someFunc2()
    default:
        otherFunc()
}

Notice the lack of break between cases. Most languages require a break so that the next case doesn’t get evaluated in the switch. What’s interesting is that the default behavior of a switch in other languages (without using break) is pretty much evaluating every case and running all of the logic for each case. And that behavior is rarely ever used. The common way to use a switch is to definitely use a break. Golang decided to do the opposite. The default behavior is that once a case matches, the switch breaks. If you want the opposite, you use the keyword fallthrough which is the opposite of break and allows multiple cases to be evaluated.

Lastly, let’s talk about the if statement. The part that got me is the ability to run logic before the if condition is evaluated like so:

if v := myData; v < 7 {

}

This creates a temporary v variable in the if block (and any attached else block). I used to do something like that in PHP if ($v = $Mydata < 7) {} except that $v wouldn’t be available to the else loop and it would be available outside of the if loop if it evaluates true, but not if it evaluates false.

One does not return just one thing

We’re used to using return to return a value or a function or whatever else. What if you could return multiple items? In most languages, you’d do this either with an array or a map. In JS, you’d probably use an object like so:

function findById(value, arr) {
  var ind;

  for(key in arr) {
    if(arr[key].id === value) {
      ind = key;
    }
  }

  return {
    result: arr[ind],
    ind
  };
}

This is rather convuluted. Usually, your findById function would simply return the result but then, you don’t can’t get any other information. And even if you used the object notation, it sucks to always have to extract the result with .result. With Go, you can return as many variables as you want. In fact, here’s findById rewritten with Go:

func findUserById(int id, users []user) (user, int) {
    var key int
    var u   user

    for ind, user := range users {
        if user.id == id {
            u = users[ind]
            key = ind
        }
    }

    return u, key
}

And then just access it like so:

user, key := findUserById(id, users)

This is pretty simple and what’s cool is that you don’t have to use any additional values, you can simply call user := findUserById(id, users) and that’d work. The key is there only if you want it or need it.

One place that I’ve found this used in the Go tour is when using maps. Let’s create a map real quick and check if a key exists in the map:

var m = map[string]int

val, exists := m['test']

If a value doesn’t exist, you get a 0 which seems counter-intuitive. I’m used to nulls everywhere but in this case, the second value that gets returned is a boolean that tells you if a value for that key exists. We’ve just initialized an empty map so it obviously won’t exist so exists will be set to false.

Lastly, you can name your return values and not have to bother with declaring them, like so:

func findUserById(int id, users []user) (u user, key int) {
    //magic happens without having to initialize u or key

    return //return without specifying values
}

All this is cool but…

I’ve yet to find some consensus on web development. It feels like the good ol’ wild days of NodeJS again. There’s martini which looks awfully a lot like Express. Unfortunately, that’s apparently not a “good thing”. Go has its own idiomatic way of doing things and so far, all the webdev frameworks have their non-idiomatic way of solving things. There’s an awesome article series on this topic which was really enlightening. It seems like things are still up in the air but some main contenders are emerging.

The problem is that it’s difficult to “pick” what to go with. I want to go with Martini because it feels familiar but if it teaches me bad Go habits, why bother? And the only other alternatives either wrap the built-in HTTP library in some strange way or they’re “not performant”. Performance is a relative term I suppose though.

My closing notes are that there’s a lot to Go that there is to be learned. It’s not something you can just pick up over the weekend or in a couple of weeks. There’s much more to it than that. But it’s definitely a fun language to learn. My only problem with it is the lack of online tutorials. While there are hundreds of Node.JS tutorials on creating a basic server or building your first web app, there is only a handful of Go tutorials. Luckily, the Wiki is well-written so you can get a good deal of information from there.

Resources