sudhirj 6 years ago

While I think most of the points raised are subjective, the overall theme does make sense to me. Of late my toolbox has become:

Ruby - for problems that are programmer bound - regular web servers / APIs, CRUD.

Go - for problems that are CPU / Memory bound - fast servers, proxies, APIs with lots of long I/O waits or high RPS requirements.

Java - for problems that require modelling - logistics systems, data structures, algorithm heavy or design heavy problems

JS/React - for UI

  • trey-jones 6 years ago

    > I think most of the points raised are subjective

    That was my take away. In fact many of the points made in the negative are actually positives for me :

    - capitalization - I actually think it's much easier to spot the public API with this convention

    - no exceptions - I get the concern about forgetting to handle and I think a compiler error for unhandled unhandled return values would be great. I also think golint probably handles this.

    Other issues can be solved easily with tooling (goimports). I admit, I love the language and I feel very productive working in it. Error handling has NEVER been more successful - that's my number one praise.

    • __david__ 6 years ago

      The problem with capitalization for me comes when interfacing with external json. Suddenly serializable structs have to be exported (since introspection doesn't work on private structs) which means that none of the names match the json names anymore (the web world tends to use lowercase or camel case with the first word uncapitalized). So now every json structure had to not only be public but also has to have introspection hints (`json: "my_field_name"`). It makes everything verbose and ugly. In these cases I'd much rather have "pub" in front of some lowercase names that match the json I'm reading or writing.

      • infogulch 6 years ago

        I feel like changing the implementation of a core feature just to make json serialization a little easier would be the completely wrong thing to optimize for. 99% of go code is not json serialization structs. Are you going to name all your fields with underscores for the same reason? What if you're using the same struct with your database? Are you going all the way and name your database fields based on your json api naming conventions just so you don't have to write some metadata?

        I'll take writing tags, thanks.

        • __david__ 6 years ago

          You're missing the point a little, I think. It's not just JSON, it's anywhere your Go code interfaces with the outside world. That's where you start fighting with Go case conventions vs. the rest of the world. I like the concept of tags in principle, but in practice they end up being very repetitive. Compare it with Rust's "serde" stuff—it's much nicer.

          • infogulch 6 years ago

            Boundary layers will always have naming convention conflicts. Even serde has `#[serde(rename = "name")]` [1] for this purpose. It's unlikely that go will ever be able to approach the powerful and general compile-time code generation/macros that rust avails awesome libraries like serde.

            I guess it's a difference of perspective: do you let the outside world's naming conventions leak into your codebase, or do you translate at the boundary? Go's field tags chooses to keep consistent naming internally and translate at the boundary, in exchange for defining that translation explicitly. Note, in some cases you will have conflicts no matter what you choose (e.g. serializing both json and database).

            The outside world is going to be messy and inconsistent and full of conflicts. I would prefer to keep that external to my codebase as much as possible and follow a consistent naming convention within the language instead of letting the outside world and its whims dictate it.

            [1]: https://serde.rs/field-attrs.html

  • tetha 6 years ago

    I've recently been asked about my choice of language to implement a new backend for some software. Imo, you want two languages + JS for the frontend if you do client-site frontend.

    You want a simple, expressive language, like python with django, or ruby with rails or sinatra. You want to implement most of your application in this language, because these languages allow programmers to be very, very productive. Put in a dumb way - 10 to 20 lines of ruby with modern libraries go a really long way without golfing.

    And if you notice you need performance and low latency, switch to your second language, java or go or something like that. This should be very little code, so you can throw all the really ugly optimizations at it to make it go fast. I've pushed some java services to sub-millisecond response times, but the things you gotta do with netty and lock-free data structures aren't suitable for a general audience anymore.

    And I guess, on top of that you need some kinda request routing, but that's simple to do with nginx/haproxy or some kind of DNS / service discovery provided by an orchestration system.

    • aaron-lebo 6 years ago

      In my experience python and Ruby and their ilk aren't actually that much better for programmer productivity anymore. They do have great libraries, but static languages have easily closed the productivity gap and have huge advantages in other areas, mainly that bugs are much easier to track down in properly typed languages and you gain productivity just from that.

      When I was a cowboy solo coder I'd never use anything but things like python, but having worked in teams, they have limitations.

      • kamaal 6 years ago

        Plus given how much stagnation there has been in mainstream C based languages, most other languages have caught with library ecosystem big time.

        These days you get decent enough libraries even in lisp languages.

  • sudhirj 6 years ago

    Should also note that the Java 8 Streams API and lambdas are a joy to use.

    I used to hate it 8 years ago, but the project I’m working on has a modeling heavy problem, and Java with the immutable data structures in Guava was a good match. Was just blown away by the language now. Still clunky, but there’s something to be said for a compiled language with great tooling, effortless refactoring and budding expressiveness.

    • bunderbunder 6 years ago

      It's a big step up, but man, I really wish Java would introduce extension methods. The streams API starts to get clunky if you need to add any functionality that they didn't think to include in the core implementation. (zip and mapi, for example.)

      • lokedhs 6 years ago

        Have you considered Kotlin? It does address specific pain points of Java, such as extension methods.

        That said, I personally don't think Kotlin went nearly far enough, and some of their design decisions are questionable but if need to be in the Java ecosystem it's a nice choice.

        • bunderbunder 6 years ago

          Kotlin's great, but that's a battle I'm just not willing to spend much social capital on.

          I'm also, let's face it, pretty jaded at this point. Lack of extension methods makes for code that's less clean-looking than I'd like it to be, but otherwise it's NBD. There are plenty of other language features that I straight up bang my head on that I'd like to see change first. Most of them are ones that affect Kotlin every bit as much as they affect Java.

  • zengid 6 years ago

    Interesting distinctions. How do you get them to work together? Http and TCP/IP?

    • inlined 6 years ago

      When we migrated Parse from Ruby to Go, we started with two parallel efforts:

      1. I built a Go implementation of resque. This let us swap any async process. Things that needed async tended to benefit from Go's speedup.

      2. We also moved some internal APIs to Go in a sidecar server to help build up/validate core library implantations before replacing whole endpoints.

    • sudhirj 6 years ago

      Usually, yes. But the model lends itself to other options as well, like different micro services in different languages, or the user facing front end in Go and the back office / management systems in Rails.

randomdata 6 years ago

> It’s difficult to generate Go code automatically.

But, I must say, I do really like that Go makes the AST a first-class citizen and a core part of the standard library. While not strictly a Go thing, in the languages I usually find myself programming in you have to rely on third-party implementations of varying degrees of quality or, even more common from what I see in the wild, messy string building. Being able to focus on generating the tree and have the built-in printer generate the code in the format that Go users expect is a much nicer way to generate code.

  • lazyjones 6 years ago

    > I do really like that Go makes the AST a first-class citizen and a core part of the standard library.

    Seconded. But I wish they would go one step further and make its compilation / code generation a first-class citizen too, including dynamic loading of generated code.

    • bunderbunder 6 years ago

      I wonder if this is really hard to do in a way that works on arbitrary platforms.

      The .NET framework has had it for a while, but it got removed in .NET Core.

anonfunction 6 years ago

> The tried and true approach of providing a compare method works great and has none of these drawbacks.

https://play.golang.org/p/JNhlfYoZgCV

  • z0r 6 years ago

    worth noting the article was published near the end of July 2016 and these methods were only added in the following month (and packaged as part of a Go release in October). i'd argue that since it's a retrospective of a few years of use, it would be fair to include that criticism even if that release had come shortly before publication

    • randomdata 6 years ago

      The criticism is fair given the timeframe, but it equally useful to point out for the readers coming here today how the language has evolved since that time.

markbnj 6 years ago

Wonder why the article isn't attributed? Had to click back to the author's home page on the site to find out who wrote it. Anyway, I think these are all good points but the one that really bothers me is no exception handling. Yeah, it makes a language more complicated to implement, but handling return values all the way up the stack is cumbersome and error prone. The vast majority of the time when something goes south deep in the stack I just want to clean up and send a signal back up to the entry point with whatever information I have. Having the language runtime handle unwinding the call stack is a big benefit in these cases. Much simpler to read and write correctly, imo.

aaronarduino 6 years ago

It really is striking to me that it is so popular to dislike Go on HN. A lot of people seem to have to voice their dislike for it instead of just not using the language.

  • CodeMage 6 years ago

    Maybe I'm not following HN closely enough, but judging from this post, it seems that people are pointing out what they dislike about Go, instead of just heaping abuse on it. In my view, that's a positive and productive thing, for several reasons:

    1) The discussion gives insight to people who have never used Go. The usual way of getting that kind of knowledge is to shoot yourself in the foot and learn from it.

    2) The back-and-forth can provide useful advice on how to work around certain problems in Go.

    3) Language designers can always use these discussions to guide and inform their decisions. "Hmmmm, haven't thought of that, better make sure my language doesn't do this; that other thing is an acceptable tradeoff, though."

    • andyfleming 6 years ago

      Great points!

      Additionally, I think it's important to point out the flaws or, maybe better-put "trade-offs" of technologies, especially when they are very popular. I think it's important to temper the hype and share collective engineering wisdom.

      • aaronarduino 6 years ago

        I agree with both you and the parent comment. It's just off-putting to have titles like "Why I Don't Like Golang" and articles that give no other value except for pointing to the perceived negatives.

        I think more constructive articles and titles would be like "What I Wish I Could Change About Golang" and would include background on how long the author has been writing Go and in what context.

        • andyfleming 6 years ago

          I agree. Using less antagonistic language and providing more context would both be great.

  • camus2 6 years ago

    > It really is striking to me that it is so popular to dislike Go on HN. A lot of people seem to have to voice their dislike for it instead of just not using the language.

    It's normal. After the initial hype 3/4 years ago, developers are taking a harder look at that language and with experience its flaws have become more obvious.

    Go type system definitely has problems that aren't addressed by its designers, IMHO limiting its adoption.

    > A lot of people seem to have to voice their dislike for it instead of just not using the language.

    One can use a language daily while still remaining critical of it. People who don't use Go don't care about Go. Only people using Go will complain about its shortcomings.

    A lot of Go issues have actually been addressed in previous languages such as Ada. Ada tasks for instance are close to go-routines and they use the same "select" system to deal with concurrent messages. However, Ada tasks unlike go-routines are "objects" that can be referenced as variable, they also can scheduled by the developer.

    There is not a single language out there free of criticism, Go isn't different. So it shouldn't really be striking at all.

    • petre 6 years ago

      > Go type system definitely has problems that aren't addressed by its designers

      Wouldn't that break the promise of backwards compatibility that they made with major versions? They could probably do that in Go 2.

      Personally, I think D is a more mature language, design wise, although it's a bit lacking in terms of libraries compared to Go and the tooling is, also lacking compared to Rust.

  • randomdata 6 years ago

    Strange. I've always found HN to be fairly Go positive, and what criticisms you do see tend to be constructive, coming for those who seem to use and are invested in the language. I sometimes visit other technology-focused forums where anything about Go quickly devolves into "No generics, no good" from people who have clearly never even tried the language, so perhaps everything looks positive compared to that.

  • nomel 6 years ago

    Or you could look at it as valid criticism is what inspires change and awareness of shortcomings in the world of programming.

    Even if I don’t us a language, I very much enjoy these sorts of “after x years review” since I definitely won’t be getting x years in each. They force me think in terms of doing things with a computer easily/language design, which is the point of all of this. This perspective help me see the shortcomings in whatever language I’m using and helps me remember to not get stuck in it.

  • z0r 6 years ago

    it's important to voice these concerns to minimize the chance that one will end up having to use these tools in future jobs

    Go and its history shares a lot of similarities with Java, but it hasn't had its 5.0 moment yet

  • crdoconnor 6 years ago

    I've always thought it was a little unfair the amount of exposure and hype technologies like go or mongo get simply because a household brand or a big marketing budget is behind them. There are better technologies out there which languish because they don't have that benefit.

    I think pouring cold water on excessive hype is, on balance, probably a good thing.

  • thawkins 6 years ago

    And dont even bother mentioning golang aps that use mongodb, immeadiate hue and cry, definatly a haters stack.

  • 5ourpu55 6 years ago

    What's your point here exactly?

    A lot of people HAVE to voice their dislike of articles criticizing Go instead of just not reading the article.

    See what I added to the conversation there?

  • zkomp 6 years ago

    Well yes! You might not have that option to not use it (too late).

    Just like this guy you (or your colleges) might actually have been fooled by curiosity and hype to write some code and put it in production, and when you realize how bad it actually is (this was only a personal top 10). At least you should try to fight back against the hype and try to warn people.

    Still think the general sentiment is quite go positive overall, go definitely needs more critique.

  • bartread 6 years ago

    I think it's because there's a relatively large contingent on HN who dislike Google in general and therefore, by extension, anything they build/support.

    EDIT: Why the downvoting? Sure, there are valid issues with golang, but there are also a small but vocal minority on HN who enjoy being rude to Google because they don't like Google, which is what my comment relates to. I certainly don't have any axe to grind with the author, the article, or the commenter to whom I'm responding. It was just a perspective on why, in general, golang might get more of a slating than it perhaps deserves, and I acknowledge that amongst that there will obviously be some people who have many valid reasons not to like golang. Sheesh.

    • stouset 6 years ago

      Or maybe it’s because we’ve tried golang repeatedly, been frustrated the entire way, and are desperately hoping that someone will help us understand what people actually see in the language.

      I work and live in SF. Of people I talk to in real life who’ve used golang for non-Google, non-toy projects, sentiment is at least 4-to-1 against it, and in my anecdata that ratio generally increases as people use it for longer.

      The one consistent praise I’ve heard that seems genuine (and that I don’t entirely disagree with) is that it’s easy for a new team member to jump on board and be productive. Which sounds great, but if this is what you’re optimizing for at (in my opinion) the expense of nearly everything else, then it seems like a self-fulfilling prophecy of high turnover.

      • matt_m 6 years ago

        Sure, I think I can explain some of what people might see in it. Obviously its strengths/weaknesses will depend on what language you compare it to, the article mentioned Java so I'll use that.

        1) Value types - in Java if you want an array of objects of a non-primitive type, each one will be individually heap allocated (with some extra per-object overhead) and stored as an array of pointers (may change in Java 10). Go allows objects to be linear in memory with no overhead.

        2) Slices everywhere - in Go slices are the default list representation. This allows any API that takes a list of objects to be passed a range of a bigger list, without copying/allocating.

        3) Low-latency garbage collector - I believe Go has one of the lowest latency garbage collectors in common use (sub-1ms pauses). I realize Java has several options, but I think Go's is lower latency than all but some commercial/exotic ones like Zing. This is not saying the GC is better all around, just on latency. It's also relatively easy to minimize allocations in Go due to value types.

        4) Low-overhead concurrency - lightweight tasks with no blocking/non-blocking dichotomy in APIs. But threads can scale up a lot, so this might not be a big benefit depending on the application.

        5) Interior pointers - you can lay out structures linearly, and still use interior pointers. Also, you can use them as interfaces without allocating any 'boxed' objects.

        There's probably more, but these are the things that come to mind right now. Looking back on this list, all of them are performance related. So if an application isn't performance sensitive in any of these ways I guess it would be understandable that someone might not see much in it, compared to a language with a higher learning curve but a lot of conveniences like Kotlin. Things like capitalization don't seem that big an issue though... maybe because Go is a simple language the tooling is already pretty good, and you can easily rename to upper/lower case in an IDE like GoLand.

        For people unfamiliar with Go and want to see something more than hello world, I think an interesting project to look at is https://github.com/fogleman/pt. It's not enormous but not trivial either and makes use of interfaces, goroutines etc. The author's other projects are great too.

    • tonyjstark 6 years ago

      I would agree, but then, the author names reasons to dislike Go (even if we all heard them before), does not say anything about Google and is not even exceptionally vulgar about it.

      So after reading about golang over and over, it seems it is going the MongoDB way. A lot of excitement at the start because it's easy and fast to put something out but as soon as maintenance mode needs to kick in, people realize it is not the silver bullet and maybe not even a ok solution.

      But isn't that a problem of the whole industry? First a hype gets build up and a lot of people jump on the band wagon. Then the real world kicks in and some complain overly loud and others chime in with "I told you so". Finally a lot of people change the tech stack silently because nobody likes to talk about their failures too much.

      I can't say if it is the same with golang, I did not use it at all yet, but some design decisions are at least doubtful.

    • eropple 6 years ago

      I think that's an uncharitable explanation. I'm very happy using the Google services I do and I pay them for my personal domain/email (have for the last decade or so). I think Kubernetes is a great idea and I run it in production. But it would be difficult to find a job that would pay me enough to deal with the frustration generated by having to deal with Golang.

      • bartread 6 years ago

        I'm not sure what the downvoting is for. There are verifiably a bunch of people on HN, granted probably a vocal minority, who slag Google off for a variety of reasons (plenty valid, no doubt).

        The author of the article doesn't mention Google, but that's not what my comment was about: it was a (very mild) observation that there are some people, and I'm sure by no means the majority nor anywhere close, who will neg on Google and their tech, because they don't like Google.

    • stouset 6 years ago

      People are downvoting you for claiming that the dislike of Go is primarily due to anti-Google bias as opposed to actual technical concerns about the language, which preemptively discounts the opinions of these people without having to address any of the points they raise.

    • kmicklas 6 years ago

      Nah I worked at Google and even there most engineers didn't like Go.

tschellenbach 6 years ago

While it's not perfect, if you use Dep and VG your vendoring issues are pretty much solved: https://github.com/getstream/vg https://github.com/golang/dep

  • senorsmile 6 years ago

    Thanks for this. I come from a Perl/Python background, and in just starting my golang journey recently, I've really missed something like pipenv/carton. VG and Dep seem to come pretty close to that.

avshyz 6 years ago

The worst thing about go, it's its dev community. Anyone who claims otherwise probably hasn't read any of the GitHub discussions (things like this https://github.com/golang/lint/issues/65 are pretty common; when users are being told they don't understand how amazing Go is.)

  • skrebbel 6 years ago

    I read that entire issue thread and I don't see a single instance of a user being told they don't understand how amazing Go is.

s17n 6 years ago

Implicit interfaces are the single best part of Go. And the “too much magic” comment is so misguided - author complains it is bad for large codebases but it’s exactly the opposite. In the real world everyone uses conventions like those enforced by Go’s so called magic. Having these built into the language means you don’t have to figure them out every time you look at a different programmer / team’s code.

  • stouset 6 years ago

    I repeatedly see this point re: implicit interfaces, and yet it’s never accompanied by an explanation of its actual benefits.

    The one defense I’ve heard is that it allows you to define interfaces that are implemented by types you don’t control, but this completely ignores the fact that doing so implicitly isn’t necessary for such a feature, and other languages (e.g., Rust) elegantly demonstrate why that is.

    • bunderbunder 6 years ago

      I'd go one further and say that the way other languages do it does a better job of letting you define interfaces for types you don't control. Sometimes the type you want to apply your interface/trait to doesn't have a function that does what you need, but could easily be assembled from other members of the type. And sometimes it does have a function that would work, except that the name is different.

      There's an Uncle Bob talk I watched a while back where he suggests that oftentimes language designers will say just about anything to avoid admitting that the real reason a feature is absent or was implemented in a hacky way is for the convenience of the compiler's authors.

  • rcoveson 6 years ago

    > Implicit interfaces are the single best part of Go.

    Help me understand this. The concern raised by the author regarding method signatures versus method contracts seems valid, and I have a hard time envisioning where implicit interfaces would be useful. Do you just hope to get lucky? Somebody, without knowing about the interface, would have to use all the same parameters and return types, the same method name, and implement the contract in a compatible way for it to work, right?

    • andrewprock 6 years ago

      Implicit interfaces reduces compile time dependencies. One of the original target features of Go was that it wouldn't take forever to compile Google-scale programs, like C++ does.

      • stouset 6 years ago

        GP claimed that this feature is the "single best part of Go".

andyfleming 6 years ago

2 additional reasons (of my own) which I don't typically see:

1. No default function parameter values.

2. You can't require struct fields. So, you can make a new struct, and then later try to access a field, you get a runtime error (that the compiler didn't catch).

The second can effectively be solved similarly to the first. If a struct could take a default value (like a class), then you wouldn't miss something like creating an empty slice.

  • vec 6 years ago

    1 is a subset of a smaller issue. Default params are just a way to declare variadic functions more easily, but the language doesn't allow variadic functions at all. In go trying to define `add(int x, int y)` and `add(float64 x, float64 y)` is a compile error, even though the compiler can tell full well which one I want to use where.

    2 is so annoying. Half the sdtlib wants you to use `foo.NewStruct()` and the other half uses `&bar.Struct{}`. As far as I can tell the rule is to use a bare definition where possible and only declare a New function if the zero value isn't meaningful. But there's no way for a library author to force the use of new and/or disable bare struct literals, and there's no way for an API consumer to know which category a given library will fall into other than by rote memorization. It's practically designed to invite user error.

    Both of these seem emblematic of a bigger problem in the design philosophy of go. It's optimized for simplicity, but often at the expense of making idiot proof interfaces difficult or impossible to build. This seems like a fundamental misunderstanding of what makes programming difficult in the first place. My package's users (including future me) aren't going to know or care about how the internals of whatever I'm throwing together work, they just want to use the API to solve their problem with as little extra contextual knowledge as possible. Go doesn't let me write an interface where they don't have to know or care, all in service of a definition of "simplicity" that doesn't seem to actually make anything easier.

    • masklinn 6 years ago

      > 1 is a subset of a smaller issue. Default params are just a way to declare variadic functions more easily, but the language doesn't allow variadic functions at all. In go trying to define `add(int x, int y)` and `add(float64 x, float64 y)` is a compile error, even though the compiler can tell full well which one I want to use where.

      That's function overloading rather than variadic functions. Variadic would be `add(xs int..)` where you can pass in any number of int, and they'll be collected into a slice or whatever.

    • randomdata 6 years ago

      > It's optimized for simplicity, but often at the expense of making idiot proof interfaces difficult or impossible to build.

      But technically speaking it is optimized for simplicity of reading code. The idea, whether it has worked out in practice or not, was that Google could take people with limited developer experience and put them into a Go codebase and have them be able to follow along with the project with minimal introduction and explanation from already busy teammates.

      Your function overloading (Go does support veridic functions!) example is a good example of where the author and compiler know full-well what the intent is, but people coming in five years later may not be entire clear on what you are trying to say. `add` is a simplistic example, but it is easy to see, and I am sure many of us have experienced, how this can be a problem in more complicated cases.

      As you have pointed out, optimizing for the simplicity of reading has resulted in increased complexity of implementation. You've only just scratch the surface of the gotchas in Go. However, that's the tradeoff. Engineering is all about managing tradeoffs and some will value readability (assuming the theory that Google has holds – I don't know that anyone has formally measured this) and others will value writability. Everyone has different goals and is developing in different environments. There is never going to be a solution that fits everyone. If there were, we wouldn't need software engineers anymore.

      • vec 6 years ago

        I actually find go extremely difficult to read. The abstractions tend to be both shallow and leaky, the syntax is noisy, and the very limited feature set forces a particular coding style whether it's appropriate for the problem at hand or not. It limits expressiveness, which I find makes it harder for an author to communicate intent.

        In other words, go makes it extremely clear how a piece of code works at the expense of knowing what a piece of code is trying to accomplish and why I might want to invoke it. I generally think that's a poor tradeoff.

        • randomdata 6 years ago

          Given Google's penchant for being data-driven, it would be interesting to see if their assumptions actually play out in the real-world or not. Everyone has an opinion about programming languages, but rarely does anyone want to look at it scientifically.

          That said, perhaps they have and don't want to admit that Go falls short. But they've been open about being wrong before when applying the scientific method and getting unexpected results.

      • z0r 6 years ago

        it isn't particularly easy to chase logic through lasagna layers of interfaces and structs.

        it isn't even easy to read bog standard code made out of for loops glued together (because that's all you have to work with)

        every time i look at another tedious manually written set operation that would been have a simple expression in another language (python is an excellent example) i am deeply pained. every time failure of abstraction forces you to re-implement such things there are opportunities for bugs to creep in.

        go is designed to be easy to write, and (in my experience so far) the natural consequence is that any project made up of modules spanning more than one or two directories quickly becomes very, very hard to read.

        a common exception to that is when code has to do many set-like operations, which can become very hard to read without having to sprawl out beyond even a single file. very common when dealing with multi-parameter/multi-result RPCs

sp527 6 years ago

Many of the deficiencies he noted are easily mitigated by tightly integrating the Go toolchain (and in particular the metalinter) with your development environment and CD workflow. I highly recommend vim-go for Vim users.

The flat namespacing is rough at times, but you get used to it. It also encourages you to be judicious in what you make global, which is imo a great thing. I haven't had a problem with capitalization. It's jarring at first, but you just get used to it.

There also isn't nearly as much magic as that cherry-picked example might lead you to believe. Then again, having worked with Ruby/RoR, I've seen just how gross magical behavior can get shudders and maybe my definition of 'magical' is a bit more forgiving. I'd like to see a more comprehensive list of such grievances.

It's possible that the Go ecosystem has improved considerably since the author wrote this (~1.66 years ago), so I'd love to hear his take on it in the present day. I do agree entirely about the horrific use of interfaces and lack of generics. I'll also throw in the lack of enums and poor default error convention/semantics as additional glaring issues.

This is all made that much more vexing by the fact that Go is so damn close to being a really great language.

andrewprock 6 years ago

Somewhere in my drafts, I have a 101 problems with Go. I only made it to 43, but I only spent an hour or so on it.

The language they were shooting for feels like "C with garbage collection". The language they were actually aiming for was probably closer to "something we can easily transpile python to".

In the end, the language they got is a bit of a mess, with fairly arbitrary hyper-pedantry causing more problems than it solves.

I still use it, but so far only in the small.

  • vec 6 years ago

    Go's a great language for Google. Their use case needs very high througput but can tolerate GC pauses, their code is a giant single-repo monolith with thousands of contributors where pedantry prevents conflict, and they hire a bunch of people straight out of college who haven't figured out how not to be clever yet. "C, but with unremovable training wheels" is a really good tradeoff for their specific situation.

    Why anyone who doesn't share Google's unique issues would want to use it, though, is beyond me.

    • pasabagi 6 years ago

      I like it because I genuinely don't have opinions about many of the things Go is opinionated about.

      As I see it, programming is something of a craft, people have different opinions about how to do it, and the only real way to evaluate these opinions is to have a lot of experience.

      Not having a great deal of experience, I like that Go essentially proscribes a lot of the stuff people normally have opinions about. It pushes you to write in a way that, for better or worse, some people think is good. I trust their understanding of the tradeoffs involved in engineering software better than mine - and I also trust that, when I outgrow them, I'll notice.

  • masklinn 6 years ago

    Go feels a bit like an alt.history version of Java 1, where the fanfic writer thought Java was not convenient enough but also not patronising enough.

baby 6 years ago

> 1. Go uses capitalization to determine identifier visibility

This complaint sounds like it's more about Go doing it differently than the language the writer is used to.

> 2. Structs do not explicitly declare which interfaces they implement.

It sounds like this is probably to have structs that will please several interfaces, but I can't find a good example of that in the go std lib. Anyone?

> 3. It’s far too easy to forget to check errors

use a linter that warns you when you do this

> 4. if I name my source file i_love_linux.go

That's actually a pretty cool and light way to implement something for multiple platforms I thought...

> If I accidentally name a function init()

Go has so few forbidden keywords that I can't really appreciate this complaint.

> In Java [...]. Sometimes I find it hard to read Go

So Java is easier to read than Go? Come on!

> I see no good argument for omitting this [ternary] operator

Less ways to write the same thing. Improve code readability.

> Import versioning and vendoring is terrible

I would say Go has the best standard tools. It's not perfect yes, but it's better than other languages.

> No generics

that's a good thing

This post really feels weird when in another thread of HN's FP you have people arguing that a 35 LOC package is a good thing in js.

  • stouset 6 years ago

    I don't mean to be rude, but did you only read the headers and skip the actual explanations underneath?

    • baby 6 years ago

      Yes

gherlein 6 years ago

Two years old. Could have been titled "I reject the goals of golang" - many of the things he hates were actual design objectives of the language. Some are so minor it's silly. Bottom line is if you don't like it then don't code in it.

vesak 6 years ago

> 7. There’s no ternary (?:) operator.

I didn't realise there are people who prefer this thing.

Generally speaking, what should we think about languages that are theoretically weak but are quite successful? Does that imply that the theories are wrong?

  • andyfleming 6 years ago

    The traditional way is more readable, I agree. I think it has more to do with statefulness.

        let example
    
        if (someCondition) {
            example = 3
        } else {
            example = 4
        }
    
    In javascript, for example, like above, I'm initializing a variable (with let, allowing reassign-ability). Its value can be modified later by other code.

    Alternatively, I could use a ternary operator and a const to avoid potential unwanted reassignments.

        const example = (someCondition) ? 3 : 4
    
    ------------

    Some languages, like Kotlin, actually let you use an if-else expression in a single line...

        val max = if (a > b) a else b
    
    ... or even allow you to return the last line of a block to assign a value:

        val max = if (a > b) {
            print("Choose a")
            a
        } else {
            print("Choose b")
            b
        }
    
    *val, in Kotlin, is similar to const in javascript; it's not reassignable.
  • pdpi 6 years ago

    If you come from a functional background (or otherwise just prefer expression-based languages), the if statement-based version is just horrible. Several languages work around this by not having ?: but instead having `if` be an expression.

  • dingo_bat 6 years ago

    Ternary operators are the best! Highly expressive and concise, and everybody instantly understands it. Is there a single drawback about it?

    • citrin_ru 6 years ago

      Ternary operators can be abused. E. g. somebody can write code with nested ternary operator and long expressions. If/else will be more readable in this case. Go is a nanny language - Go authors give to coders on Go as little foredoom as possible.

      • drdaeman 6 years ago

        Anything can be abused. There is no technological or design measure that can prevent one from writing crappy code in Go or any other language. I'm certain of this as I had personally written some.

        Except for esoteric languages, of course. I've yet to see someone claiming some code in Malbodge is crappy and offering a refactored version. ;) Just kidding.

    • vesak 6 years ago

      I've been programming in languages that have them, and almost every time I have to read code that has a ternary operator, I have to stop and think what's the condition, what's the "true" branch and what's the "false" branch.

      This is even worse in languages that have truthy values, since you don't even have the "== True" thing to help.

    • bluedino 6 years ago

      They're easily abused:

          H = (C == 0 ? null : V == r ? (g - b) / C : V == g ? (b - r) / C + 2 : (r - b) / C + 4);
    • code_sloth 6 years ago

      Have you seen what atrocities people can do with nested ternaries?

      • masklinn 6 years ago

        The only language in which you can't see atrocities is whitespace, because you can't see the atrocities.

    • sethammons 6 years ago

      Nested ternary

      • masklinn 6 years ago

        Even more so.

        Between

            var v T 
            if (cond0) {
                v = value0
            } else if (cond1) {
                v = value1
            } else if (cond2) {
                v = value2
            } else {
                v = default
            }
        
        and

            val v T = cond0 ? value0
                    : cond1 ? value1
                    : cond2 ? value2
                    : default
        
        I'd much rather have the latter.
        • randomdata 6 years ago

          However, your if statement is unidiomatic and quite unlike how you would normally write that particular logic in Go. If you really want to make a fair comparison, you might consider writing it in the way that Go is normally written, not the way that someone familiar with another C-style language might write the code if the ternary operator was taken from them.

          • masklinn 6 years ago

            Please do go ahead and demonstrate how you would normally write that particular logic in Go. Would it perchance be this piece of finery?

                var v T 
                switch {
                case cond0:
                    v = value0
                case cond1:
                    v = value1
                case cond2:
                    v = value2
                default:
                    v = default
                }
            • baby 6 years ago

              I think GP pointed out the if () construction that doesn't make sense in Go. There are no parenthesis in Go. Shows that you pretty much never used it?

              • masklinn 6 years ago

                Yes I'm sure

                > However, your if statement is unidiomatic and quite unlike how you would normally write that particular logic in Go. If you really want to make a fair comparison, you might consider writing it in the way that Go is normally written, not the way that someone familiar with another C-style language might write the code if the ternary operator was taken from them.

                meant

                > the parens are unnecessary

                and they didn't just write that because reasons, which would also be the why they commented an other half dozen times since then but just couldn't come around to showing "how you would normally write that particular logic in Go" because it would take all of 5 minutes.

        • baby 6 years ago

          Maybe because you're used to it, but your second example looks unreadable to me and I know ternaries.

  • tschellenbach 6 years ago

    Yes I don't get the authors argument. Now you need 4 lines of code instead of 1 in some cases. On the flip side it's easier to read for anyone looking at your code.

    The weirdest part is that the author seems to prefer Java. Which is one of the more verbose languages out there.

    • vec 6 years ago

      The problem is that I can't declare the variable and set it's value as part of the same operation. I'm forced to declare a variable with a nonsensical or incorrect value then correct it later as part of a logically distinct statement. This introduces a window into my code where some piece of memory is known to be wrong and puts the onus on me to not use it between its declaration and it's being set.

      It's a small nitpick in the grand scheme of things, but it forces me to allow a class of user error (and, in some cases, concurrency issues) that other styles of programming make impossible.

      And also it usually adds to the line count, which is annoying.

      • randomdata 6 years ago

        > The problem is that I can't declare the variable and set it's value as part of the same operation.

        Care to elaborate? Consider the following:

            var foo = func() struct{ Bar int } {
                if os.Getenv("BAR") == "1" {
        	    return struct{ Bar int }{1}
        	}
        	return struct{ Bar int }{2}
            }()
        
        Is there a case where the foo variable can be assigned to something other than one of the two conditional-dependent values?
        • vec 6 years ago

          Okay, "can't" is too strong a word. But I don't know a good word for "it's technically possible but is cumbersome, is not idiomatic, and requires introducing another stack frame for no good reason".

          • randomdata 6 years ago

            > and requires introducing another stack frame for no good reason

            With a given implementation or is there something in the Go specification that prevents this from being compiled away? If I were to write something similar in, say, C++ with a good compiler I would expect the generated code to be equivalent to using a ternary operator.

    • __david__ 6 years ago

      I don't understand this meme I see from go folks that ternery is hard to understand. From my perspective it's much more straightforward than a bundle of ifs and variable definitions. With go I have to look at a jumble of lines and decompile it in my head back into the original intention (what's all this? Oh that's just a ternery). Practically every language had a ternery (even python!), and there's really no reason for Go to skip out on an obvious and useful abstraction.

    • nickm12 6 years ago

      People definitely differ on the "easier to read" part. I find the 4 line if statement version more difficult to read in most cases. When things get long, my favorite formatting for a c-style ternary is:

          my_variable = (my_very_long_condition)
                        ? value_if_my_condition_is_true
                        : value_if_my_condition_is_false;
      
      This is 3 lines, but there is almost no noise, just the condition and alternate values. Also, the variable is never assigned a dummy value (or left unassigned).
simula67 6 years ago

Is no one else annoyed about the GOPATH pedantry ?

  • sonaltr 6 years ago

    That's one of the first issues I've had with Go. To the point where, all my go projects are something along the following lines:

    projectname:

      |- go
      |-- src
      |--- domain.com
      |---- username
      |----- projectname
      |------ Actual Code goes here...
      |-- pkg
      |-- bin
    
    It's a fun time explaining this to anyone new on the team...
    • sethammons 6 years ago

      Is that what you are checking into source control? For every project I work on, the projectname directory is where .git lives. It so happens that when I 'go get', it goes into the whole structure you reference above based on my one GOPATH that I never, ever change. For those new to Go, you just show them how it works once. For those used to Go, there are no surprises.

      • sonaltr 6 years ago

        I'd check the internal folder (projectname/go/src/domain.com/username/projectname) into source control (domain.com/username/projectname).

        Everyone has a different way they like to setup their environment and I didn't want to push my ideas onto other users.

        • sethammons 6 years ago

          I acknowledge that everyone has a different way they like to setup their environment. If they choose to do it the way that the designers intended, then they suddenly don't have many of the issues that many folks complain about around GOPATH and standard build tooling works as expected.

          The way you reference is a valid way, but is unorthodox and requires altering GOPATH for each project. If one is worried about polluting a global space of packages as they pull in dependencies (the standard objection), that is what vendoring is for. If someone is not liking all the fuss with altering GOPATHs, that particular grumbling is easy to fix: don't alter it :)

          When I first started with Go, I did the whole "alter the GOPATH for each project," until I finally gave in. After, things just got simpler. To each their own.

  • randomdata 6 years ago

    Are you referring to how modern versions of the Go toolchain do not require GOPATH to be set and are able to build projects in any directory? I don't see an issue with it.

    • andyfleming 6 years ago

      I knew that there was now a default for GOPATH, but I didn't know you are able to build in any directory. When was that added?

      • randomdata 6 years ago

        Honestly, I'm not sure. I don't follow development that closely. It works with 1.10, possibly earlier versions.

  • __david__ 6 years ago

    I am too. I spend way too much of my time hacking around stupid GOPATH issues.

    • sethammons 6 years ago

      I've been using Go as my primary language now for a few years. I never change nor have issues with GOPATH. Now, older applications that are using godep for vendoring still, that is something I have lost far too much time against.

013a 6 years ago

Every day someone publishes their snowflake opinion on why Go is terrible. Every day, hundreds of highly productive engineering teams write millions of lines of Go, powering web services and developer tools you use on a daily basis.

So I'm inclined to side with the engineers actually putting the hours in instead of the talking mouth bloggers. If there comes a day when Google, or Uber, or Twitch, or Cloudflare comes out and says "Go was a mistake and we're starting to replace our old Go code with this new thing", then I'll start listening.

  • crdoconnor 6 years ago

    From python to go and back again, by mozilla:

    https://docs.google.com/presentation/d/1LO_WI3N-3p2Wp9PDWyv5...

    • 013a 6 years ago

      There's also a good writeup from Asciinema [1] with a similar theme. These are valuable articles from people who have clear domain knowledge in their problem area, which accurately discuss the pros and cons of both approaches.

      There's a huge difference between "Go doesn't work for us, here's why, here's what works" and "I don't like Go". The latter should be a Facebook post and has no place on HN.

      [1] http://blog.asciinema.org/post/and-now-for-something-complet...

  • cwyers 6 years ago

    There are many more people being productive in Not Go than there are in Go. Taking this argument to the logical conclusion, we should all be using... what, C++ or Java?

  • drdaeman 6 years ago

    It's very simple. There is no contradiction and no reason for name-calling. Go is terrible, but it's also one of the good things we have that can get shit done. Another - and quite notorious - example of "worse is better" principle at works.

  • aaronblohowiak 6 years ago

    This kind of comment makes me not want to visit HN. You can make your point without being so off-putting.

    • CodeMage 6 years ago

      Not to mention that the point in question boils down to argumentum ad populum fallacy. The same reasoning could have been applied to Java in its heyday.

      • cwyers 6 years ago

        In its heyday? Java is still scads more popular than Go.

miguelmota 6 years ago

All the things listed are the reasons why I personally LOVE Go. Convention over configuration.

flavio81 6 years ago

I have read many "criticism of Go" articles and this one is one of the most direct-to-the point.

TL;DR: topics covered:

1. capitalization rules create inconsistent behavior

2. Structs do not explicitly declare which interfaces they implement.

3. No exceptions

4. A very good one: "Here’s far too much magical behavior. For example, if I name my source file i_love_linux.go, it won’t get compiled on my Mac. If I accidentally name a function init() it’ll get run automatically. (...) It’s fine for small projects but bites you on large ones, and Go was meant to address the problem of “programming in the large”."

5. Identifier name clashes

6. It’s difficult to generate Go code automatically due to the compiler being picky on imports, etc.

7. No ternary operator.

8. (complaint about sort.interface{} that could have been solved using generics)

9. "Import versioning and vendoring is terrible. "

10. No generics.

11. "The append() function modifies the array in-place when it can, and only returns a different array if it has no place left. You couldn’t ask for worse API design. How many bugs are caused by forgetting to assign the result? A lot, because initial testing may not trigger a resize."

I would personally replace (6) with "absolutely no half-decent metaprogramming abilities (nor an expressive type system that could give you a workaround here.)"

  • drdaeman 6 years ago

    You forgot URLs as import namespaces.

    It makes it literally impossible to swap one library for another (a rename or fork). A simple example that had caused tons of grief and had probably wasted lots of man-hours is when github.com/Sirupsen/logrus became github.com/sirupsen/logrus.

    Vendoring sort of works for simpler "I need a patched version of this" cases, but is not a real solution.

  • kardianos 6 years ago

    1. Capitalization. Author cited they didn't want to change how they named things and it conflicted with Go export rules. Okay then.

    > 4. A very good one: "Here’s far too much magical behavior. For example, if I name my source file i_love_linux.go, it won’t get compiled on my Mac. If I accidentally name a function init() it’ll get run automatically. (...) It’s fine for small projects but bites you on large ones, and Go was meant to address the problem of “programming in the large”."

    4. is great for large projects. Once you learn the convention, it is super easy to see which files are for which platforms. It makes it to navigate large trees.

    6. Look at how protobufs do it. Easy to work around.

    11. Understand how Go works, run go vet.

  • pdpi 6 years ago

    The capitalisation issue is the sort of thing you'd tell a junior developer to avoid in code review: By tying one design decision (what access levels are possible) to another (code style), they effectively made it impossible to cleanly change the design around the former, because the latter won't admit any more values.

    • andyfleming 6 years ago

      The language design choice to use capitalization instead of a public/private keywords is, in my opinion, a poor one. It seems like they've made choices to minimize keywords rather than be explicit and intuitive.

      I'm not saying that it can't be learned/taught. Also, IDEs like GoLand help, but at the end of the day the capitalization approach seems like an unnecessary annoyance

      • pdpi 6 years ago

        It's awkward but can absolutely be learned and taught. What makes it really idiotic is that the spec literally ties visibility to a single, specific unicode character class. This has the hilarious effect that, for example, Latin, Greek, Cyrillic identifiers are allowed to be public, but Arabic, Korean (Hangul) or Thai are not!

      • tschellenbach 6 years ago

        Python does something similar with the _hidden __morehidden syntax. Some people will like the syntax, others won't. It doesn't really change anything about what you can achieve with Go.

      • s17n 6 years ago

        Nope, the point is consistency in large organizations. In other languages, teams develop naming conventions like these. Having them in the language reduces the overhead of reading a new codebase.

        • andyfleming 6 years ago

          There's a difference between consistent code style and forced language conventions.

          Also, I'm not sure you'll be able to convince me that reading "public" and "private" add meaningful cognitive load to reading code.

          • s17n 6 years ago

            Right, the difference is that the former isn’t real. When you have millions to billions of LoC developed by thousands to hundreds of thousands of developers anything not forced isn’t going to be consistent.

            • andyfleming 6 years ago

              You can enforce code style through linting and CI. In some projects I've worked on, code doesn't get merged if it doesn't pass code style checks.

    • s17n 6 years ago

      They could easily add more visibility levels (by using keywords like Java). They haven’t because it’s unnecessary and confusing.

      • andyfleming 6 years ago

        I wasn't necessarily advocating they add _additional_ visibility levels, but they already have at least 2. They are just implicit by capitalization as opposed to explicit with "public" and "private" keywords.

        • zaphar 6 years ago

          Both are explicit. One uses a keyword the other uses capitalization. The compiler will still complain if you use a private method in either one. You can argue about whether one is more or less readable than the other but you can't say they aren't explicit.

          • andyfleming 6 years ago

            Yeah, I guess you are technically correct as far as being explicit. Maybe intuitive is a better description. A newcomer could read public/private and quickly understand its meaning as opposed to capitalization being a learned convention.

      • pdpi 6 years ago

        Let’s say they add keywords. What happens then? How does that interact with the current rules, and with people’s ability to interpret code?

dingo_bat 6 years ago

> For example, if I name my source file i_love_linux.go, it won’t get compiled on my Mac

What could be the reason for this?

  • sudhirj 6 years ago

    Go enforces the convention of using the architecture name as the last part of the filename as a way to compile code specific to that platform. For example, code that used epoll would be in _linux.go, and the windows and mac versions would be named appropriately.

    • cesarb 6 years ago

      That sounds fragile. Does that mean that, whenever golang is ported to a new platform, code which happened to have the same filename suffix as that new platform's short name will stop working everywhere else?

      • randomdata 6 years ago

        Idiomatically, underscores are reserved for files that are given special treatment, like architecture-specific code or test files. It is not strictly enforced by the compiler, so theoretically you could cause this scenario, but if you write Go the Go way, it will not be an issue.

      • encoderer 6 years ago

        Golang wouldn’t be “ported” to a new platform like, say, python. You would need to re-compile for that platform, and address any platform specific code at that point.

myf01d 6 years ago

I tried hard to like Golang but I couldn't. The only good thing about Golang is that's it's a high level compiled language that's suitable to replace Python in many use cases especially in the web, there's no other popular language in this category. However, the lack of features and forcing specific design patterns for a c-like language is totally annoying.

lima 6 years ago

Needs a (2016)

  • sctb 6 years ago

    Updated. Thanks!

  • eropple 6 years ago

    Has anything in it changed?

    • randomdata 6 years ago

      2. Not a change per-se, but the core team are now often seen using var _ InterfaceType = Struct{} to declare that a type conforms to an interface (which will also generate a compiler error if it fails to). This seems to convey the same intent to the reader. Neither solution, as originally noted, will catch bugs in the implementation.

      3. Tooling will catch when you are not appropriately handling errors, although I'm a little bit surprised this didn't already exist in 2016. But I'll assume it didn't. It certainly does now.

      6. Again, not a change, but the patterns to make this a non-issue are perhaps better understood now. The points are short on intimate details, so it is difficult to determine if the problem is a result of the author not being entirely familiar with the language the way that people are today, or if there is a particular edge case that the rest of us might not consider.

      8. The sort package has addressed this concern.

      9. Go has had a solution for versioning from the very start, so I'm not quite sure what the parent is referring to. It was indeed a terrible solution for many organizations, but a lot of work has been done to improve on that. For all intents and purposes this is no longer an issue.

      • parenthephobia 6 years ago

        > The sort package has addressed this concern.

        How? Looking at the documentation, you still have to write at least three functions for each type you want to sort.

        • randomdata 6 years ago

          An example from the docs:

              sort.Slice(people, func(i, j int) bool { return people[i].Name < people[j].Name })
kayall 6 years ago

Has anyone here tried using panic/recover?

I think they are pretty similar to exceptions.

jhillyerd 6 years ago

I think this article is a great illustration of the things a Java developer will struggle with while they are learning Go. I no longer write Java, and I now view many of these as strengths.

1. Capitalization rules vary by language, I remember struggling with camel cased naming in Java in some scenarios. I also thing the example given is bad, User.user is a poor name in any language.

2. Structs w/ implicit interfaces. I like this feature of Go, and it's never bitten me in the way the author describes. I never liked having to declare them in Java. And there is an easy way to ensure your particular type implements an interface in Go.

3. I prefer not having exceptions, and linters will tell you when you are not checking returned errs. I do wish Go would offer tools to reduce the amount of if err != nil {} blocks, particularly in IO heavy code.

4. Go's build system is very easy to understand compared to something like Makefiles or Maven. I don't consider a few conventions "magic." I have mixed feelings about init(), but I think it's much better than trying to come up with thread-safe alternatives to compile regexp, etc.

5. Naming. Writing unit tests from an outside perspective (package xyz_test) will help you pick better names, and you will run into less conflicts. In Java you see hideous combinations of Abstract, Singleton, Factory, etc. I much prefer Go's concise/pragmatic naming style.

6. I don't do much code generation, can't comment.

7. I do miss ternary sometimes, but I have seen it abused with very long statements in other languages. I would note that "else" has become a code smell in Go, it's more normal to assign a value and then change it.

8. Sorting. I like that not everything needs to be an object in Go. Having to add a few extra lines of code the rare occasion I need to make something sortable is much better than a project full of Java class/getter/setter boiler plate for what should have been a struct.

9. Yes, dependency management is a mess. No argument. Looking forward to dep becoming official.

10. I do sometimes miss generics, but I started writing Java before it had generics so I can live without them :P. I think they can lead to readability problems when overused.

11. append is a bit confusing, but hiding how it works should be considered "magic." linters will help you here.

  • parenthephobia 6 years ago

    I don't understand your point about sorting. What sort-related Java boiler plate are you referring to?

    • jhillyerd 6 years ago

      Boiler plate in my example would be everything that needs to be written for a class in Java, not specific to sorting: new file, imports, getters, setters etc. compared to a few lines in an existing file for a struct in Go.