Hacker Read top | best | new | newcomments | leaders | about | bookmarklet login
Why Tech Startups Should Look at Go (startupedmonton.tumblr.com) similar stories update story
50.0 points by ardan-bkennedy | karma 47 | avg karma 5.22 2015-01-15 14:36:21+00:00 | hide | past | favorite | 110 comments



view as:

While go has some nice features-- standalone executables and fast execution are two. I don't really see a compelling reason to switch to it from Elixir/Erlang.

Biggest downside seems there's no real easy way to handle errors being returned from function calls.

Easier deployment would be good, but once you solve it for elixir it's not a big issue. On the other hand Erlang is very well tested and established and pretty complete-- though go's libraries and open source support is growing by leaps and bounds.

So really, it's that error issue. Oh, and pipe. I really love elixir's pipe ( |> ) operator.


Can you be more specific in how handling errors is difficult? I've found it to be generally forced and explicit, which, while sometimes unpleasant, is quite comforting.

The alternative seems to be exceptions flying unhinged.


> The alternative seems to be exceptions flying unhinged.

The commenter you replied to explicitly mentioned Erlang and Elixir, you may want to have an idea about where they're coming from before replying to their comment.


Yeah, that's why I said seems. I'm not going to lie, I know next to nothing about Erlang and Elixir.

Let it fail, let it fail, let it fail! (to the tune of "let it snow, let it snow, let it snow!) Supervisor Trees!

Exceptions are not much better, but checking the return every time is no fun. And if you crash the whole thing crashes.

In erlang you can have a once in 1x10^9 error and not even catch it, but only that process crashes (and your system keeps running) and that process gets relaunched. With go, it's the whole program that will crash, necessitating checking every return value.

I say this, though I might be missing some error handling system in go that I'm simply not aware of.


You can set a `defer recover()` which will stop the panic from crashing the entire program, letting you recover & take whatever action you deem appropriate.

> I don't really see a compelling reason to switch to it from Elixir/Erlang.

What about ease of growing your team and finding 3rd party libraries so you don't have to re-invent the wheel?


I think it's funny, but not surprising, that you assume it will be easier to grow the team with Go. It's not a more popular or established language, yet.

But also, I've recently built a team using Elixir before Elixir was even 1.0. About the hardest possible example of that argument and we found great people, grew a great team in Austin Texas.

Having a really good language as part of your stack works as a filter-- you get the best programmers that way. Not saying go is bad, but it's popular, and so you're going to get a lot of people who chose it because it was popular.

As for re-inventing the wheel, erlang has a lot of 3rd party libraries, and is ahead of go in that regard, for the time being.

Most interesting to me is your perception of the situation, which I'm guessing is driven by the fact that go is very popularly being evangelized right now.


> Having a really good language as part of your stack works as a filter-- you get the best programmers that way.

Agreed. At one point I felt this way about Scala, but it's starting to change as the boulder rolls downhill.

I still use Scala, because it's fantastic, but it's no longer a safe assumption that a Scala programmer can be trusted with sharp objects from the jump.


>It's not a more popular or established language, yet.

Github would disagree as one data point.

I don't have my own numbers to back this up but I firmly believe based on my communication that there are more people in the world that have written Go right now than Erlang.

>Having a really good language as part of your stack works as a filter--

I think this is good for Go and Erlang... So I don't think it helps distinguish.

Not to mention anyone that smart knows C/C++/C#/Java can very quickly become a gopher if needed; quicker I would contend than you will ramp them up on Erlang.

>Most interesting to me is your perception of the situation

I've been writing Go full-time since before Go 1.0 RC-- I think you don't have an accurate perception of where Go is at.


I've never really understood the "no easy way to handle errors" complaint. I'm not saying it is easy, nor that it isn't verbose (hell, it is super verbose!) but I'm seriously asking: what would be an easy way to handle errors? I'm not asking about how to do it in Go, just how to do it in any programming language.

To me errors are very special constructs, is not a typical return value, as for example a method returning true or false whether the arguments are valid or not, so I expect errors to be something similar (at least semantically) as exceptions in other languages, and in that case, that is, return values that should be deal with in a certain special manner, so I don't expect to deal with them in an "real easy way"™, but in a very conscious and deliberated way.


It's the verbosity that I'm talking about. In go I end up with %70 of my code being error handling or error related... with Elixir it's close to %0.01. I'm giving estimates here, of course, but they aren't off by much. With elixir, using try catch is rare, because it should never crash, and when it does, you lose a process and debug it.

With go, every line that calls a function needs to check to see if there was an error. And handling that error takes at least another line or two.

Unless there's a better way that I'm missing.


Ok, verbosity I agree. That doesn't have anything to do with being easy or not, I think. I might be wrong. Verbosity can be a pain. Even after reading Rob Pike's article on "Errors are values" [1], I agree with you that the solution is still verbose.

Those numbers you gave, even when you said they're estimates, still seems like made up numbers. I've never used Elixir, so if you could point me to an example so I can be more informed, I'll be grateful :) but also I've read some Go programs (not many, I'm not an expert) and it didn't seem to me that 70% of the code is dedicated to error handling.

Note that I'm not defending Go's position on error handling, I'm asking about error handling in general, what does people mean with "easy way to do it".

[1]: http://blog.golang.org/errors-are-values


The Erlang/Elixir way can be hard to appreciate because it's not just a very different way of handling errors, it's a completely different way to architect your application. The following tutorial only takes about 45 min to go through, but you'll get a taste for how error handling (across distributed process, at that) works in Elixir: https://howistart.org/posts/elixir/1

I wonder how long it will be until Rob Pike decides that "Handling error values should be enforced by the type system".

here is a podcast where they cite error handling stats of C++ vs Erlang.

http://mostlyerlang.com/2014/11/19/049-supervisors/

starting at 28:45 although you might want to listen to the whole podcast


There are better ways.

The Erlang way would be to code for the happy path, and not try to anticipate most errors. If your process encounters an error, it will crash, the supervisor will restart it, and it will continue processing. Of course, you can choose to handle anticipated errors if you would like to be more user friendly (e.g. provide a user-friendly message if a file is missing), or if you want to log the error or something. But generally it's considered defensive programming and an antipattern to try and handle every error condition in an Erlang program like you have to do with e.g. Java exceptions.

In languages with powerful type systems like Haskell, errors can be handled by using (for example) the Either[1] type. That way, you are forced to pattern match on the type (it will be a Right if successful or a Left if unsuccessful/errored), so it's not possible to "forget" to check for a null reference like you do in Go (i.e. checking err != nil all over the place).

[1]: http://hackage.haskell.org/package/category-extras-0.53.4/do...


Thank you for the explanation. I think it makes sense somehow, however, and high likely because I've never dealt with errors in that way, the _encounter error, crash, restart, continue_ workflow seems a bit awful to me :)

The Haskell solution seems really nice. I've only used Haskell for pet projects and it's one of my favorites languages (though I don't have any proficiency with it,) so thank you for teaching me something else about it.


> _encounter error, crash, restart, continue_ workflow seems a bit awful to me :)

Granted it is better and less awful than error, everything stops, get calls from customer at 4am, fix, continue cycle ... ;-)

It is a bit different. Learn about it some more and you'll love it. The reason you can't easily do it in other languages is that errors are not isolated. That crash that happened, it might have left some global variable some place in a strange un-expected state. That is why Erlang/Elixir processes do not share memory.

That way it lets you feel a bit safer about crash-restart parts of the system.


> high likely because I've never dealt with errors in that way, the _encounter error, crash, restart, continue_ workflow seems a bit awful to me

It is a different way to see things, but makes sense when you consider that Erlang comes from the world of distributed high-availability telecoms where "one machine" is the same as no machine (because when — not if — the machine crashes, the system is dead).

Applied to the development environment, that means of course erlang developers try to avoid errors, but its designers know it's not possible to have 0 errors so they've built support for independent error recovery into the system: when an error occurs, the whole agent may be corrupted (in an invalid state or whatever) so the erlang way is to throw it out and have an independent "auditor" (the supervisor) decide what should be done.

At scale, that's essentially what Netflix builds (and exercises with their Chaos Monkeys)


Something to think about: this is similar what people are building (outside of Erlang/Elixir) using Docker and CoreOS. Deploy a bunch of instances of your app both to scale and to handle failures. Need to update the OS on a box? Restart it, there's other app instances to cover it. A container crashed? Restart it -- it's not sharing state with other instances so things will be fine.

Another way to handle error propagation transparently is using monads. Even if you haven't used monads in Haskell, you've probably used them in Javascript: promises are monads. Consider how both errors and exceptions propagate through .then chains in promises. There might not be as much syntactic sugar in JS as there is in Haskell, but the idea is pretty much the same.


Go's panic() acts similarly to what you're expecting out of Erlang. You still have to call it for other libraries.

> so it's not possible to "forget" to check for a null reference like you do in Go

The Go compiler will complain if you don't use the `err` variable after creating it, helping to make you remember to check it, and letting you branch accordingly. This doesn't help with someone who re-uses the err variable or assigns the error return to `_`, but those are conscious choices to bypass the checks Go adds for you.


> Go's panic() acts similarly to what you're expecting out of Erlang. You still have to call it for other libraries.

Go uses a shared heap. So even though one go-routine panics, you can't safely assume the state of your system is still predictable. If it is not predictable you can't necessarily safely restart that go-routine.

Without Erlang/Elixir I would actually do it with OS processes / containers at a higher level. Erlang's processes are only a few K of memory and are very easy to restart and handle so you get all that built in.


To be fair, if you're modifying the heap from a goroutine, you're "doing it wrong". Go provides channels, which work quite well at reducing the need to mutate the global state. I use such a pattern quite frequently (the http.Server), and have never had a problem with heap corruption due to a handler goroutine panicing.

That's true. To that extent C, C++, Java work took. The Threads + thread safe queues is a common paradigm I've used. The problem comes with using other libraries, sharing code with others in a large code base. But errors and concurrency bugs still happen.

But just like type systems, they are there not just to make code faster but add some guaranteed safety. The guaranteed is important. In case of concurrency, errors and state, the isolated heap also adds that guarantee. That is important.


There is a cost, though. Low enough to bear in most cases, but transferring more state through IPC, the overhead of starting new processes, context switching between processes, duplication of in-memory structures; these can add up to make an equivalent Erlang program much more heavyweight on a system than a Go program using many goroutines.

Right tool for the job, yadda yadda. :)


Erlang processes are nothing at all like Unix processes. They are much, much smaller memory-wise as well as in terms of spawning/killing speed as they do not rely on system calls but rather the Erlang VM (which is highly tuned for these purposes).

Yes, there is a small overhead incurred when copying data between processes because the VM is truly copying the data[1], but the benefit gained is that you get per-process heap isolation (references can't cross process heap boundaries). This is important because in languages like Java or Go, one misbehaving bit of code that is causing a lot of GC to happen can "stop-the-world", and make your entire system pause (and it does happen[2]). This is not acceptable when writing soft real-time code, like say an auction system.

I'm not sure why you think an Erlang program is more heavyweight than Go. Is it due to Go programs being compiled to binary? Erlang can do that as well,[3] although it's not often done as Erlang requires a runtime, and it's often simpler to use a separate runtime. But you should know that Go also requires its own runtime to run Go programs[4], it's just that it is statically linked into your compiled code (which is what makes the resulting binaries so huge). But Erlang could do the same thing, it's just not really an industry practice.

[1]: http://jlouisramblings.blogspot.dk/2013/10/embrace-copying.h...

[2]: https://groups.google.com/d/topic/golang-nuts/S9goEGuoMRM/di...

[3]: http://erlang.org/doc/man/compile.html

[4]: http://golang.org/doc/faq#Why_is_my_trivial_program_such_a_l...


> "real easy way"™, but in a very conscious and deliberated way.

If your don't deal with errors in a "real easy way"™, your customers will deal with errors in "a harder way"™ and they'll call you at 4am about it too.

You can't avoid dealing with errors basically.

> deal with in a certain special manner,

Ok is this "manner" easy or hard to handle.

You can also look at it this ways, errors will happen. Some will be predictable (as in you expected a "connection refused" exception or error value. Some will be unpredictable ("this library I downloaded return -5 and just silently doesn't send the value" or throws some un-expected exception).

There are 2 good ways to deal with errors:

1) Use a stronger/better type system or other static checkers. Something like Haskell or Rust, hoping the type checker will prevent some class of errors. You hope to avoid errors ahead of time here. This approach is taken for some critical systems. Navigation, medical equipment, military hardware etc.

2) Isolate errors when they happen. Errors will happen at runtime, even in a typed-checked language. How do you want to deal with them? You can deal with them in an easy way -- isolate the component that fails and degrade the system slightly without completely stopping service. Or even better restart just that one sub-components. Or, have everything come crashing down with an exception or tracelog and get a call from a customer. Erlang and Elixir (and other BEAM VM) languages do this best. You can to a certain way replicate this with OS processes, but Erlang has that built-in. The reason for that is concurrency primitives (processes in Erlang, others have tasks/goroutines/threads) do not share a global heap. So that lets you both isolate the errors they happen to one component, and lets you separate main code from error handling code (you can have supervisors that watch other processes and if they crash they can deal with it better).


>To me errors are very special constructs

Special how? Surely they are not special in a way that can't be captured by a type system. You say they should be handled in a special/deliberate way, but that's what it means for something to have a distinct type: it can't be handled like everything else. You just define special error-handling functions and they will work on errors and nothing else, and nothing else will work on errors.

As far as syntax goes, the I feel the big issue is about deferring error handling. You don't always want to mix error handling code with your algorithm logic, so you need to defer. We also talk about 'errors' so generally that we never bother to qualify which kinds of errors should be deferred or not in a way that is encapsulated in the type system. Or what kind of deferring should be available -- return errors or just move them later in the same scope? (Java's checked exceptions are a good example of attempting to do this, but it doesn't work out in practice. Programmers don't think like programs do: deferred error handling isn't the same as deferred error-handler writing, and both are needed in different ways.)

From what I can tell about error handling in Go, it isn't really a step forward. (And we really want a step forward.) Go just kind of falls back on "this was the last thing that worked, and making significant progress is probably too hard, so we won't bother trying."

That's the impression I get, at least. I don't actually do any Go programming, but I'm not inspired by its approach, either.


Let be honest here, who really use Erlang? How do you find people that knows this language?

Who? Guys who know about high load and distributed systems, mostly the telecom industry.

Whatsapp

WhatsApp is one of the more well known examples: http://highscalability.com/blog/2014/2/26/the-whatsapp-archi...

I've recruited and built a team which was writing code in Elixir, even more obscure than Erlang. It wasn't really a problem finding people who knew it or were strong programmers who were interested in it.

Good languages attract good programmers.

The idea that we need to stick to popular languages is, I think, driven by business guys who want commodity programmers.

If you want 100 engineers added to your team in a year, then sure, use Java. But you will still be less effective, I bet, than 10 engineers doing erlang in that same year.


I would argue that you can pick any new'ish (last 5 years) language that is suitable for development and find the same results. Anyone who knows the language well taught themselves how to use it without the guarantee of being able to use it at a job.

This will be a fairly small subset of developers, the ones that have motivation and time to put into growing themselves. So this probably means that the devs that know new language X are just more interested in software development (compared to devs that just know the language(s) they learned in school, and whatever they were taught on their jobs). So they have a much higher chance of being good developers.


German game studios.

A few well know companies in the healthcare world.



Do you want to hire people that are incapable of learning a new language?

Basho, Klarna, Cloudant (now IBM), WhatsApp, T-Mobile for some SMS stuff, many others.

You also use Erlang without even knowing ;-) Chances are every time your access the Internet via your smart phone, there is Erlang code managing that. RabbitMQ broker is written in Erlang.


I am not going to argue about "which one does it better", because I have no experience with Elixir.

But regarding Go's verbosity when dealing with errors in particular, this article helped me a lot:

http://blog.golang.org/errors-are-values


Nope, that's what I'm talking about. That article shows how to optimize this constant checking of errors.

What I'm trying to say is that in elixir you handle this at the level of the process. In go the whole thing is one process so you can't do that. In elixir you let it crash, and if the process crashes you report the error and conditions of the crash in the log.

In a real system you would only have a couple things where you do a try/catch or "is error not null" type checks-- for the whole program.


tl;dr:

* Stratups don't have time to rewrite the prototype the right way, and then hit the performance wall.

* A few startups explain how Go is faster and more reliable than Ruby/Rails, Python, and JS/Node.


Some thoughts on those points.

>Startups don't have time to rewrite the prototype the right way, and then hit the performance wall.

I would guess that for experienced C/C++ programmers (and probably C#/Java) Go isn't going to be slower to build in than Python/Node etc. I actually build things the fastest right off the bad in Go... I've ported node.js applications to Go, and let me tell you it was not fun. Even if the first throw away prototype was in Go, it would have made the rewrite much easier.

>A few startups explain how Go is faster and more reliable than Ruby/Rails, Python, and JS/Node.

Considering Go was built to compete with Python/C/C++/Java at Google I would hope so. I think a key metric that often is left out is maintainability. I think Go's very straight forward code (which some people call boring) is an asset here.


Gophers love to quote TJ Holowaychuk to justify choosing Go over Node.js. In my eyes, TJ is a traitor - If he preferred Go, that's fine - He could just go ahead and use it as he likes, but he wrote a post completely debasing Node.js without pointing to any real, concrete issue.

I bet he is still using Node.js from time to time - The 'Goodbye' article is obviously just a stunt.

He probably cashed out! I read somewhere that he got a decent sum for his Express framework. I would be interested to know who else is behind this.


Speaking only for myself, I've found the following to be broadly true with Node.js and Go:

If I'm building a strictly server-side app using Express, it's a joy to use Node.js (especially for a prototype) - everything more or less works, and the NPM ecosystem is rich and broad. Very easy way of getting a RESTful JSON API up-and-running from FooDB.

If I'm building a client (web scraper, getting stuff out of an API to load into R, etc.) then I really quickly run into "Too Much Concurrency" TM with Node. I quickly find myself building something with Go (or Ruby) to do the following:

- Limited Number of workers

- Automatically re-try request N number of times if fails, depending on response code

- Log all successes/failures

- Throttle total # of requests/second based on site-specific rate limiting

To make the above work in Node, I have to use caolan's async + Q promises + other libraries (or write in Icedcoffeescript, which I like but is very weakly typed and has inferior tooling) and find myself refactoring most of the small script just to fit into the async libraries. With Go, I can use mutexes or simple channels to control throttling, and do whatever I want with errors. There's a lot of boilerplate to get the above up-and-running robustly for Node, or at least that's been my impression the last few times that I've used it. Node has solutions for advanced concurrency (Generators, promises, CSP libraries), but why reinvent the wheel when Go has that out of the box?


Tech startups who hit this phase (or "wall," as it's described here), should look at all options. Even if Go is the best technical option, it may not be the best business decision. That's an unfortunate reality for startups - if you can't bring in the staff you want / need, the best tool for the job might not be the right one.

This ends up being another pro for the distributed microservice model, allowing some experimentation and internal learning in new languages without impacting an entire product.


One upside is that learning Go is easy for a an experienced developer.

> Even if Go is the best technical option, it may not be the best business decision

Why might Go not be the best business option? I see technical case for or against Go as very much religious and shaped by personal preference. But what could be a business reason not to use Go for a new startup that is independent of the technical side?


I thought I hinted that it was more a matter of available resources. The Go community is growing but if you're a lean startup looking for developers to get moving quickly, the pool for Python, PHP, Node & Ruby/Rails dwarfs that of Golang.

And to the other comment, yes, it's easy (and generally surprisingly pleasant) for experienced developers to pick up, but that's an investment.


At Canonical, 2/3 of our developers on Juju hadn't written Go code before joining the team. They get up to speed in the first week, or often, even before their first day through their own efforts. The language is incredibly easy to pick up. It's basically zero cost if you have at least a few devs with Go experience to answer the occasional question.

You could assume that Go, although popular, isn't at the level of Python and Ruby in terms of available developers. The ones that would know Go are most likely very good and also expensive compared to just finding that one Ruby/Node/Python programmer of the many out there which will go low enough and suddenly Go doesn't make sense anymore for startups without the cash.

>You could assume that Go, although popular, isn't at the level of Python and Ruby in terms of available developers.

Not really, any smart C/C++/C#/Java developer can be highly productive in Go in weeks.

Side thought: If your startup isn't on the west coast, C/C++/C#/Java developers are far MORE common than Python/Ruby devs. Although C/C++/C#/Java developers are not rare anywhere.


The Iron.io blogpost was what got me looking into Go. As a Rubyist it was quite eye-opening!

You'd probably enjoy Haskell more than Go as a Rubyist imo. Most Rubyist I've known seem to really like Haskell.

Essentially all of the quoted usecases switched from a slow dynamically typed language to Go. Of course that's an improvement.

But I still don't see why you would choose Go over Java (or Scala) for serious backend development. Java has more libraries, is faster, has generics (for the love of god), has better IDE support, and has a larger hiring pool. In summary, the ecosystem is more mature.

Java's checked exceptions are less painful then Go's C-style error handling. They could have gone with something sane like Rust/Haskell style error handling (using the type system), but they instead regressed to return value checking.

The complaints about Java's overwhelming verbosity are mostly dated both on the language-level and the ecosystem-level. Java 8 has lambdas, streams, and more. Spring Boot and Dropwizard are 2 modern, lightweight frameworks that do away with the XML configuration nonsense.

I'm actually genuinely asking why anyone would choose Go over Java and not trying to start a flame war. An API I'm working on is due for a rewrite and it's currently written in PHP. I'd like to give Go a chance but it just seems like a poor choice compared to Java.


I'm much more productive (in terms of bug-free-functionality-per-hour) in Go than I am in Java (and even more so in Elixir than go).

It seems the value of those 3rd party libraries are not as much for me as for you and others. I guess cause the essential stuff is covered for Elixir and most other languages.


I like coffee and long walks.

Great point. If you switched to those language you might have more time to go for coffee and take long walks, because your system have a higher chance to manage errors and crashes and you don't have to rush to the office right away or at night to fix issue.

> Java is faster

Do you have any evidence to back that up? I am not disagreeing, just curious.



I love the fact that lua is at the top, directly after java.

Go still beats Java sometimes: https://www.techempower.com/benchmarks/#section=data-r9&hw=i...

I'm not saying Go wins more, but they are very close compared to other languages.


I want to point that in fact Go is extremely performant on EC2 for every tests and average on Peak. So with that and all its features, it seems that Go is an awesome solution for startups.

And then Java when you start to be quite big.


The couple of things I've found (which are perhaps more niche) are the GC behavior of golang seems to be "nicer" / "easier" than that of java and I've found the concurrency of the channels to be easier to use and more predictable than the N different concurrency constructs within Java proper (that isn't to say using something more akin to Quasar isn't a nice alternative).

Like with any languages, there's lots of tradeoffs between systems. I would also suggest the "Java .. is faster" isn't always true.


An experienced programmer friend of mine uses Go professionally. I was surprised to hear that he much prefers Java: he said that many concurrency libraries are available for Java and that Go's features are quite limited in comparison. He dislikes the fact that you have to break Go's poor type system to get many things (such as tests) to work. He has a pretty strong background in FP, so I think that perhaps Go's interfaces are the straw that broke the camel's back.

This made me realize that I'm still holding onto some biases about Java, and that it's worth a look. I did start to dabble in Scala (and I have experience with Clojure), but it seemed like I'd want to know some Java before doing Scala, whereas that didn't seem as necessary with Clojure.


An explanation for downvotes would be appreciated... perhaps "poor type system" was too strong wording, and for that I apologize. But it was surprising to hear his opinion re: concurrency, as from what I understand that's one of the biggest features of Go.

"poor type system" isn't too strong, it's just what it is.

I think one reason to choose Go is simplicity. You can run, say, a JSON REST service and build it with TDD out of the box with only the standard libaries. It's also such a small language that you can pick it up quickly.

I haven't done an serious Java development recently but my impression is that if I wanted to get up and running with it quickly there would be a ton of choices to make around frameworks, tooling, which conventions to stick to, etc. and it would all be difficult to navigate. (And maybe that's not even true, but if that's my impression I'm just gonna choose choose Go).


>But I still don't see why you would choose Go over Java (or Scala) for serious backend development.

  1. Less verbose code
  2. Platform Ind. + native binaries, no runtime dependency
  3. Built in unit testing/benching
  4. Fast compile time
  5. Better tooling, no Ant etc needed
  6. Better core language support for multithreading/concurrency
  7. A memory model that makes it easier to read the code and understand how the resulting data will be layed out in memory
  8. Related to 7, better stack vs heap allocation control
>Java has more libraries

Many of which are of low quality / filled with code-rot, I used to play in the Java ecosystem the Go stdlib is cleaner and the Go 3rd party libraries tend to be better, more single function.

>is faster

This is not always the case and is changing for Go's better fast. To paint Go as non-competitive would be unfair as its in the same league as Java and it usually faster than C# Mono.

>has generics (for the love of god)

I used to miss this, but I find I don't anymore... I wrote proxies, databases, systems applications.

>has better IDE support

True. This used to pain me until I found LiteIDE and I started writing unit tests more and using the debugger less. Go's profiler is awesome though...

>and has a larger hiring pool.

Not really, any smart C/C++/C#/Java developer can be highly productive in Go in weeks.

>In summary, the ecosystem is more mature.

A double edged sword mind you, not to mention Go is maturing at faster rate then Java did.

>Java's checked exceptions are less painful then Go's C-style error handling.

No. C++/Java got it wrong, ignoring error paths lead or letting random low level errors bubble up are some of the horrible results of the Java way to handle exceptions.

Forcing programmers to consider which operations may fail- how to handle those failures is one of the best decisions Go made. Multiple returns make this much less painful than C.


> 2. Platform Ind. + native binaries, no runtime dependency

Also available in Java. It is just a matter of choosing the right compiler.

Java like many other languages, enjoys a standard, certification process and multiple implementations to choose from.


GCJ is dead. Are you referring to proprietary implementations?

Yes, who still bothers with GCJ? I really don't understand why GCC still ships it.

However there are also open source implementations like RoboVM and JikesRVM, among a few others.


> 1. Less verbose code

Go is much more verbose than Scala or Clojure. Go is just a language, whereas the JVM is a platform with multiple languages.

> 2. Platform Ind. + native binaries, no runtime dependency

In my opinion Java has a greater degree of platform independence. Wherever it runs, things just work. On runtime dependency, you're wrong, as Golang does have a pretty heavy runtime dependency. It's true that it doesn't get distributed as byte-code that needs a VM, but at the very least you're still dependent on a garbage collector and that makes it unsuitable for all those things one would naturally do in C/C++.

Also, Java being the standard that it is, has multiple implementations and it doesn't necessarily need a VM. The purpose of RoboVM (http://www.robovm.com/) for example being to build apps for iOS in Java meant compiling Java to native and RoboVM does just that. But there are advantages to distributing apps as bytecode - Android ART (the successor to Dalvik) is doing AOT compilation to native upon installing an app on your phone and the cool thing is that you don't have to worry about what processor your app will end up running on.

> 3. Built in unit testing/benching

I don't see how that is an advantage. Does Go have something like YourKit Profiler? Can you easily connect to a remote application for debugging or profiling?

> 4. Fast compile time

One can argue that fast compile times are a direct consequence of the compiler not doing pretty much of anything you'd expect a compiler to do - like optimizations or type-safety. For example the C++ compiler is slow, but the C++ compiler can optimize the shit out of anything. Scala's compiler is slow, but it can catch a lot of errors for which you'd normally have to run expensive third-party tools.

> 5. Better tooling, no Ant etc needed

Nobody is using Ant anymore. Go doesn't have Maven or anything like it (i.e. Gradle, SBT, Leiningen). As a personal opinion, whenever I have to work with other platforms, feels like going back to the nineties.

> 6. Better core language support for multithreading/concurrency

This is a common misconception, when the opposite is factually true.

On the JVM you'll find support for the Erlang-style actor model, Hoare's CSP, Futures/Promises, reactive streams (Rx), STM, parallel collections and the best concurrent data-structures that open-source can provide. See Akka, Quasar, Scala's and Clojure's standard libraries, LMAX Disruptor, etc...

> 8. Related to 7, better stack vs heap allocation control

This has always been a problem for the JVM, however stack-allocated values are coming in the next version. On the other hand the control on memory layout in Go is still weak and the JVM does have much better garbage collectors.


>Go is much more verbose than Scala or Clojure. Go is just a language, whereas the JVM is a platform with multiple languages.

There is a trade-off being verbosity and maintainability, IMGO Go hits that.

>In my opinion Java has a greater degree of platform independence. Wherever it runs, things just work.

LOL. Said no person who has actually distributed a multiplatofrm Java application ever- I should know. Both Java and Go are "write once, test everywhere", but in my XP Go has been smoother.

>On runtime dependency, you're wrong, as Golang does have a pretty heavy runtime dependency.

The key word here was dependency, specifically, external dependency. If Go'd runtime ships with the binary its not really a external dependency is it.

>Does Go have something like YourKit Profiler? Can you easily connect to a remote application for debugging or profiling?

Yes. It comes baked into the stdlib, its "http/pprof"

>Go doesn't have Maven or anything like it

Biggest plus ever, goes native simple tooling doesn't need an external life support system.

>This is a common misconception, when the opposite is factually true.

You are wrong, all the the stuff you are are talking about is library based, Go has channels/select/go build into the language as primitives. I wasn't talking about bolt on libraries.

>On the other hand the control on memory layout in Go is still weak

IMHO This is not the case, if you think it is, explain.


> There is a trade-off being verbosity and maintainability, IMGO Go hits that.

This is where we'll always disagree, because if you like Go, it's natural for you to come up with this argument, however the line you're drawing is completely arbitrary. I have yet to hear an argument about what makes Go strike a fine balance between verbosity and maintainability, when my feelings are the opposite - I find Go code to not be very maintainable in comparison with other static languages, because Go is not very statically type-safe.

> LOL. Said no person who has actually distributed a multiplatofrm Java application ever

Yet it happens all the time and a LOL is not an argument that disproves that. From my own experience, I have built stuff on top of Java / the JVM on OS X / Linux and deployed on Linux, Windows and OS X, without encountering any issues, ever, without worrying that Java's NIO will work or not, without worrying on whether the memory model will suddenly be different, without worrying on whether my app will leak on 32 bits platforms ;-)

Android is the only ugly duckling, but that's only because Android doesn't have a JVM on it. It still works out well though.

But if you have examples, I'd love to hear them out.

> The key word here was dependency, specifically, external dependency. If Go'd runtime ships with the binary its not really a external dependency is it.

Now that's an arbitrary distinction, isn't it? What stops one from bundling the VM in the same deployed binary? If you want this distinction, the only valid argument is one of size, but then again for the server-side (where most of the Go stuff is used) that's completely meaningless.

> Yes. It comes baked into the stdlib, its "http/pprof"

Are you seriously comparing something like YourKit's Profiler and Java's remote attach and debugging capabilities to http/pprof? IMHO, that's not a comparison you can make.

> Biggest plus ever, goes native simple tooling doesn't need an external life support system.

There are many issues wrong with this line of thinking - the simple tooling you're talking about doesn't do what I and many others want it to do. Also if you look throughout history, all the languages that came with batteries included have suffered once the people finally reached the conclusion that the included batteries have been shitty. Which is what happens when you don't let evolution pick a winner with the community acting as the fitness function. But we'll talk in about 5 years.

> You are wrong, all the the stuff you are are talking about is library based, Go has channels/select/go build into the language as primitives. I wasn't talking about bolt on libraries.

But that's the point mate, the JVM is capable enough to build anything you want on top of it as libraries, there's no point for something to be hard-coded in the language. Which is a good thing, because when speaking of concurrency and parallelism, there isn't a one size fits all.

For example, speaking of Go's channels - they are strictly about managing concurrency, they are not about parallelizing a workload and they do not work across address spaces / asynchronous boundaries. And if you think that Go's channels are the answer to everything, well, you would have been better off with Erlang, as there you might have had a valid argument.

> IMHO This is not the case, if you think it is, explain.

Can you take an arbitrary memory location and cast it to anything you want? Can you override how heap allocation happens? Can you allocate an array on the stack? Can you do RAII? Do you have the union type from C?

In practice you have no control on where Golang allocates stuff - the compiler decides that based on really simple rules for escape analysis and as a general rule of thumb AFAIK anything that is allocated with "new" goes on the heap. What you can do with Golang is to use the "unsafe" package. But that's not different than using Java's sun.misc.unsafe ;-)

The only real difference with Golang is that you can have stack allocated structs, as otherwise Java also does escape analysis. But besides this coming to Java 9, the real kicker is that .NET/C# has had stack allocated values since inception, in addition to much more potent "unsafe" constructs - in C# you can even do pointers and pointer arithmetic and the runtime will pin those memory addresses during execution for avoiding GC interference.


I could respond point by point and keep this going, but don't think we are going to change each-other's mind or add constructively to this conversation.

I think we would both like to think we are both right on technical grounds, but I think we would be deceiving ourselves as a great proportion of this is personal taste, ideological, and we are both heavily invested in our respective platform of choice.

Best of luck & code on.


Well yeah, but arguing programming languages is what we do - it's like talking about sports for us, isn't it? :-)

You're right of course.


Java actually doesn't have generics. It has syntactic sugar for generics, but they are so horribly broken they can't be fixed.

For example, because the generics are just sugar for casts, you can't specialize them. Because you can't specialize them, you have to put behavior in the "wrong place". Take for example a hash map from Double -> T. Because IEEE floats don't actually form an equivalence class (NaN != NaN), they don't make great keys to a hash table (if you put NaN in, you can't get it out). But, rather than specializing the hash table for floats to give special NaN handling, Java had to make Double(NaN) == Double(NaN), so when they're boxed, they do form an equivalence class.

And if that were the only inconsistent behavior in primitives versus their boxed counterparts, that would be great...

EDIT: To those who downvote, would you discuss your objections? I understand that I may come off a bit caustic, but having been burned by the myriad correctness issues in Java, it's hard not to. These aren't abstract problems that don't come up in practice -- for a public example, look at what Paul Phillips has to say about the JVM and standard libraries.


It won't be longer true in Java 9, latest Java 10.

Overall that's great to hear, but I can't help but feel that it's too little too late. Once they fix the generics, are they going to go back and fix the secondary issues too (like the issue with Doubles)?

I know this isn't a popular opinion, but these correctness issues really matter. For example, you can see the impact these choices in the JVM and the standard library had on the Scala community, ultimately forcing Paul Phillips to fork the compiler.


When people focus on a language, they tend to think only about the language and not the ecosystem around it. Yes, Java 8 has closures, but then again it will be a very long time until the ecosystem will move to using them. And for example, even though Scala has baked-in features to make functional programming much more pleasant / practical, it's not those features that position it as a functional programming language, but rather the ecosystem around it. In other words, even though you can mostly use a language that has closures in an FP fashion (and people did so with languages like Java or Javascript), it's painful doing so not only because of the language and the standard library, but also because the other people and the supporting libraries are not doing that and then you're the weirdo that swims against the tide.

On the other hand the JVM on the whole is an extremely good platform and given that one can use on top alternative languages that do make a difference, like Scala, Clojure, Ceylon or Groovy, well that's the comparison I'd like to see ... the JVM versus Go.

On your arguments - Java's checked exceptions are deeply broken IMHO, but something that works much better in the context of a static language are types such as `Try[T]`, `Either[L,R]`, `Option[T]` or `Validation[E,A]` from Scala. They achieve their purpose of documenting the error in the function's signature and can do much more than exceptions can, they force you to either deal with it or escalate and their API is very comfortable. Unfortunately whenever you bring these into a discussion, people dismiss them because you know, monads and applicative functors are apparently too "academical". But we keep reinventing broken wheels, because we can't bother to learn anything else that isn't in the gang of four.

On Go my personal opinion is that it is a very poor choice compared to the JVM, even when speaking about Go's strongest points, like performance and concurrency and yes, I believe that the JVM is a strong winner on all points. But then I wouldn't expect people that have chosen Node.js or Python/Gevent to start making good decisions.


I find java's ecosystem to be it's biggest drawback. Yes, there are libraries and frameworks available for everything. The drawback is that every simple task, from building to testing to servers is wrapped in so many useless layers of indirection and configuration I just want to tear my eyes out. If you could throw out all the nonsense that has infected java and just build simple things from scratch on the jvm that would be awesome. But it's too late.

I find that creating go backend services is super easy and simple. The builtin web server is amazingly performant. I've found it super easy to integrate with other services (cassandra, postgres, mysql, mongo, nsq). The result is always high performance apps with a low memory footprint and high test coverage.

When it comes to type systems, I find go's handling of errors to be closer to rust than c. Basically multiple return values encapsulate the same information Rusts's Result<T, E> does. You just deal with:

    if a, err := f(); err == nil {
        // do something with a
    } else {
        // do something with err
    }
 
rather than:

    match f() {
        Ok(a) => { // do something with a }
        Err(err) => { // do something with err }
    }
Rust certainly has the advantage in type safety, but I find the 2 forms mostly equivalent for the things I care about.

In the rust example error handling is enforced via the type system whereas with Go it depends on your (and others) discipline.

You're correct. Go doesn't leave it entirely to discipline, since unused (or unhandled) variables are a compiler error. You can silence that error with _, but it sticks out to the eye as broken code.

However I'm not trying to argue that go gives you the same type safety guarantees that rust does, it doesn't.


Thanks, I forgot about the warnings. It's been a while since I've used Go.

Its not a warning, its a "will not compile" :)

Isn't the technical term "error"?

I suppose the technical term would be "fatal error". I was just clarifying it was a warning since C compilers, for example, will happily spit out many warnings and then hand you binary-

Yeah, it's a worthwhile clarification. Of course, the distinction is less hard than it might be, given that a lot of us build with -Werror.

Here's my take on this as someone who loves both Go and PHP (yeah, I know!). I agree that startups can get entrenched in their legacy code, but I also think there is a false choice here:

1. Write with a system language from the start. Yikes!

2. Do a total rewrite of your application later when you hit scale issues. Yikes!

In my opinion, though, Go is not well-suited (today) for rapid prototyping or web application development, even with some of the frameworks. This shouldn't be a surprise. Go is a systems language.

I think languages like PHP, Ruby, and the lot are much better suited early stage startups. When you hit problems of scale, it's very straight-forward to isolate parts of your application that do not scale well and translate those components to Go.

Introducing Go for only the components that require high availability and guarantee a level of performance / memory safety as an iteration to your original application code is probably a much saner choice.


If your team has a common skillset that can be used to rapidly and efficiently deliver a thing and you don't yet have the same confidence in your collective Go abilities: do not use Go.

Otherwise, feel free. Not sure why this is such a huge point of contention.


Node.js is way better than Go! It's more expressive, more flexible and more portable.

... Thanks for the downvotes. Well worth the bad karma :)


I watched the Rob Pike Concurrency is Not Parallelism video (http://vimeo.com/49718712) a few days ago and thought that "maybe I should be using Go instead of Python." Then I thought about all of the work that would have to be redone, all of the learning that I'd have to do, all of the retooling, all of the etc., just to get back to where I'm at now. If I were starting again Id probably start with Go, probably.

2/3rds of our devs working on juju hadn't written a line of Go before they were hired. Getting up to speed on Go is very far (like a week to get productive). Many of them have very Python heavy backgrounds. Just dive in, it's easy.

at the end of the day, on the first days of (most) startups you focus on showing results as fast as you can. Prototyping languages (Pyhon / Ruby etc) are the right choice.

Nice stories about how iron.io reduced 30 ruby servers to 2 go servers became relevant only after they proven good market fit and working growth engine.

So GO? maybe yes but probably only when the prototyping languages, can't carry weight.


I have found Go to be high level enough to make prototyping very straightforward.

Define "high level enough" python / ruby are much faster...

Exactly what I said. Just like Python/Ruby can be "fast enough" to do many things, Go is "high level enough" that I don't have to spend too much time thinking about the lower level details.

The few seconds of difference is small enough that it effectively does not matter.

For example, I don't have to worry about maps (dicts, hashes, etc); they're in place, but require one additional statement before they use them. I don't have to worry about array lengths; I can just use append(). I don't have to worry about finding a third party library to do network requests, it's part of the standard library (and doesn't require too many convolutions to use).

I do have to think a bit more about pointers when writing function signatures in Go than in Python or Ruby (not that those two languages really free me from that concern: some structures when modified in a function modify the underlying data from the callee as well).


its hard enough to hire decent developers never mind decent go developers

AWS is cheap enough that "throw more hardware at the problem" is a viable option for most startups. So long as you're not being completely stupid with the way you've coded the first version, pretty much any language is going to work, and the cost of people who can code well in more esoteric languages that might be better suited to the problem domain are going to be increasingly expensive. Obviously there is a time to rebuild with technologies that scale better than what you started out with, but I doubt all that many startups ever actually get to that point.

I don't think you've ever calculated just how much that cost is.

Lets say that you have a web service that is serving 30,000 requests per second, with a 1 Kb request size and a 4 Kb response size and you're setting up an elastic load-balancer setup that on average keeps 300 c3.xlarge instances open.

Do the math and you'll find that the cost on AWS, considering the instances used and the bandwidth, is over $80,000 per month. And that's a conservative example, since by my calculations that's about $1,000,000 per year and I know companies paying much more than that.

Don't know what startups you're thinking about, but from where I'm standing, for startups that's a recipe for burning cash.


30,000 requests per second is 2,592,000,000 per day... That's quite a lot. Obviously we're not talking page views (because that'd be crazy successful and well beyond 'startup' territory), so we're presumably in the domain of data logging, analytics, social networking etc. Sure, AWS might not be appropriate for those. But then, the level of traffic you're talking about represents maybe 0.1% of startups. People doing "a CRUD app for a niche", which is most SaaS startups TBH, could run their software on 1 AWS medium instance for the first year or two quite happily.

You're right, we aren't talking about page views or CRUD, but it can happen in a B2B application.

I ended up working for a startup like that, so this was a real anecdotal example. Our stuff was built to run on the JVM and we managed to get away with a variable number of instances between 15 and 30 (at the time we used c1.medium, which are now deprecated) - AWS's ELB is great in such a scenario as it can be configured to bring up new instances in case of traffic spikes, or kill them in case they were unused. So for us, AWS was saving us money, however that's because we were very efficient.

My opinion is that if you're expecting your startup to grow soon (and I'm not talking about wishful thinking, but about requirements that have to happen for survival - i.e. you either get the desired contracts or you don't), then you have to prepare for it.


AWS is not cheap. It's a rather expensive way to rent hardware. It's only "cheap" if you are using some aspect of elastic computing to use 100 machines for a couple hours.

I've worked with several startups who are paying 6 figure a month AWS bills. At that point it's really not a bad idea to take all those python or ruby data processing jobs and convert them to go. I have seen costs reduced by an order of magnitude this way.

The key point here is that some startups need a pretty decent scale before they have a MVP. How many useful search results could google have provided if they weren't crawling most of the web from day 1? Some social media or analytics startups need to process twitter's firehose feed, even when they don't have many customers.


It's not at all surprising that those startups solved their problems with Go: if you switch from a language that doesn't address your problems to one that does, you're going to see a big benefit. But there are lots of languages that address the problems mentioned by those startups, and I think that Go is possibly the worst of the options.

It's telling that none of the startups in question switched out of a language which provides good compile-time type and thread-safety guarantees:

1. iron.io: ruby -> go 2. SendGrid: perl -> python -> go 3. TJ Holowaychuck: node.js -> go

Go would have a reasonable compile-time type system, except that without generics you end up having to cast a lot, which renders your compile-time type system almost irrelevant.

It's also telling that none of the authors mentioned experience with functional programming. Go supports some functional programming, but it doesn't seem to be a very big part of the language. The only one who mentions that they even considered any functional languages is the iron.io guy, and it seems like a big part of his choice was not technical: he mentions that he had to sell the idea of Go to his team by mentioning that Google supports it. A language that was a more serious paradigm shift (OO -> functional) would have been an even harder sell.

(EDIT: Okay, the SendGrid guy did mention considering Scala.)

The fact is, there are a bunch of languages that would have solved their problems, in addition to a few they didn't know they had. Julia has coroutines similar to Go, but is much more expressive, Rust has a more traditional threading model but a type system and focus on immutability that provides better safety guarantees. There are other choices, but those two stand out as the major ones that could have solved their problems better than go.


> Go would have a reasonable compile-time type system, except that without > generics you end up having to cast a lot, which renders your compile-time > type system almost irrelevant.

In my experience of Go, this is not actually true. For example, in the latest project I've been working on, there are 8487 lines of non-test code. In that code, there are a total of 16 dynamic casts, more than half of which are checked (mostly checking for particular error types). There are a total of 4 occurrences which might possibly be amenable to generics.

The type system is totally relevant, and checks 99.9% of our code.


How do you deal with container-type classes? The only way I can see to do this without casts is to duplicate the same container class for each contained type, which is fraught with its own problems.

Legal | privacy