Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I would argue that Go's opinionated style is what makes it elegant. It's a programming language for people who are sick of programming languages. It makes clear promises and delivers on exactly those - it belongs in new code for that reason.


>I would argue that Go's opinionated style is what makes it elegant

I'd say Go is opinionatedly inelegant. It is minimal, I'll give you that, but has several non-orthogonal design decisions, smells, etc.


Please elaborate.


This article [1] explains why I'm not a fan.

[1] - https://www.teamten.com/lawrence/writings/why-i-dont-like-go...


Not compile-time checked repetitive error handling (if null != err), duality of panic and error codes, specially blessed constructs (maps, slices, etc being "generic"), lack of expressivity, specially typed map libs, interface{} type safety escape hatch, etc...


If err != nil everywhere is definitely a code smell and poor language design.


No, being opinionated by itself isn't a good enough reason to belong in new code.


If you don't believe that making clear promises and delivering on them is, then what would you suggest is a better reason?


> If you don't believe that making clear promises and delivering on them is, then what would you suggest is a better reason?

How is "being opinionated" and "making clear promises and delivering on them" equivalent?


I didn't say they were. They weren't even in the same sentence in my original comment.


If the promises you are making are not appealing, even if they are clear and you deliver on them, you can't count that as a reason to use a language in new code.


You're arguing with a point that I'm not making at all.


What is your point then? You're being obtuse.


Go has been carefully designed to solve the problems of today. But relying on solving those problems at the language level means I have very low confidence that the language can adapt to solve the problems of tomorrow. They have built-in language-level support for concurrency, great - that's always going to be slightly more user friendly than a library-based solution. But what about when the next wave comes along? Are they going to be able to rework the whole language to incorporate whatever 2020's equivalent to the concurrency revolution is? While retaining compatibility with existing code?

I would not want to use Go for any codebase that's expected to last more than a couple of years. I'd put a lot more faith in languages that were able to adapt elegantly to the challenges of concurrency at the library level, without requiring language changes - that suggests those languages will be able to adapt similarly to the next revolution. And my impression is that languages that started with a solid theoretical underpinning, and/or a small core language with as much as possible pushed out into libraries, handled the transition a lot better than languages with the more ad-hoc, practical-problem-first approach to design that Go has.


I'm with you in general that golang code is very unmaintainable in the long term.

> Go has been carefully designed to solve the problems of today.

I'd even argue it was "carefully designed" to be in the 70's. Other than "goroutines", the language is stuck in that decade. No generics, no expression based syntax, exposing system-dependent "int" type and encouraging its use, badly designed interfaces that can't be used for tagging, badly designed time package, the list is too long to mention here.


My oldest "big" Go project started in 2010. Last commit date was 2013 - https://asciinema.org/a/cJosP51z0oScKPLmVUhyNKUOj

It still runs today. I have Haskell and Python programs that are somewhat smaller from around the same time that no longer run.

More importantly, I can go into my source code and I can still understand it. I can't say the same for the Haskell and Python programs.

I wonder which is more maintainable in the long term.


I didn't mention Haskell or Python. I'm not really familiar with Haskell, and I definitely wouldn't use Python, or any dynamically typed language for any project spanning more than a couple of files.

You can find old C programs that compile and run fine now, so I don't really see the point of your argument.


Smaller in the problems they solve, or just smaller in code? I wouldn't expect Python codebases to last well (no type safety and the language evolves quite aggressively), but I'm surprised you'd have Haskell that now didn't run (assuming you could reproduce the original build/dependency environment - Haskell package management was a mess until very recently) - can you give any details about what kind of thing goes wrong?


There are several factors as to why the Haskell program no longer worked - first is that I'm a crappy Haskell programmer. A lot of the things I thought I was doing ended up being NOT what I want upon reflection many years later (it was a game that was essentially a spreadsheet in disguise). Second, the ecosystem has changed a lot in the intervening years. Thus, nothing worked. I recently rewrote the game just to keep up my Haskell skills because I don't really write much on a day-to-day basis


And yet, people are solving problems in it, often quite well.

I say this as one who has basically mastered Haskell, so it's not like I'm not aware of all these things: Fans of all these complicated abstractions really need to take some time and grapple with that fact. It will improve your programming in the more complicated languages as well.

No, seriously. Stop for a moment and think about that. Consider the advanced features as a scientific prediction: "If you do not use these features, you can't have a good program come out the other end." This prediction is falsified by the concrete existence of a lot of good Go programs. This matters. It is something that should be grappled with intellectually, if you are a language fan.

It will bring you to a deeper understanding of all the fancy features. By a deeper understanding, I mean that quite directly, with no attempt to be subtly saying something like "Oh, you'll find they're all useless in the end." That would not be true. They are not even remotely useless. They are incredibly useful. I would even go so far as to say that the development of these complicated sorts of features is legitimately among some of the most simultaneously interesting and useful intellectual work being done in our time, and greatly contributing to our ability to hold our software world together. It's just that the shape of that usefulness is more complicated than a lot of people realize, and a deeper understanding of that complication is very useful for developers.

One of the things that I think really comes out of it is a yet deeper understanding of matching tools to problems. I use a lot of Go, because I write a lot of things that are at a size and complexity where those other language features just aren't that helpful. Yet, there are tasks I could be assigned where I wouldn't dream of using Go, because I know I would need all that fancy stuff to hold the program together. I can easily imagine ways in which my career trajectory would change in the next couple of years and I'd go primarily Rust; I can equally easily imagine ways in which I will stay primarily Go. I can imagine ways in which I'd need to go with some other language. I think a lot of programmers who find these fancy features and fall in love with them end up overestimating the scope of the set of programs where they can be helpful. To give a degenerate example, my six line shell script does not need to be written in the Rust type system. It is not only not helpful, it would be actively harmful. The scope of programs that don't really need those features and where they quite easily become actively harmful is larger than a lot of people think. Especially if you consider them in the context of a heterogeneous team of developers who may not all be in the 5+ years of experience range, or when you may not be able to guarantee that the project is going to stay in those hands.


> Consider the advanced features as a scientific prediction: "If you do not use these features, you can't have a good program come out the other end." This prediction is falsified by the concrete existence of a lot of good Go programs.

I'd claim that programs built without those features have a ceiling on how complex a problem they can solve before maintainability collapses under its own weight. Go is popular for microservices, which makes a certain amount of sense (if you believe that microservices are an effective way of doing systems architecture - I don't, but I can see why people would). I've yet to see a Go system that I found genuinely impressive/innovative in terms of the functionality it provided.

> To give a degenerate example, my six line shell script does not need to be written in the Rust type system. It is not only not helpful, it would be actively harmful. The scope of programs that don't really need those features and where they quite easily become actively harmful is larger than a lot of people think.

Disagree. In my experience a significant proportion of production incidents happen because a six line shell script gets modified incorrectly, or does not handle an unexpected condition properly.

I've seen plenty of ineffective solving of business problems in e.g. Haskell, which I think boils down to a failure to appreciate how low the reliability requirements actually are in most businesses (exacerbated because many organisations are dishonest with themselves about such things, even in internal communications). I do think that someone who knows the advanced features but is willing to write "YOLO Haskell" (or similar language) will be more effective at solving business problems and creating value than someone using Go or similar (and at this point I've built my career on the effectiveness of fancier languages, even for 6-line-script-like tasks).


"Disagree. In my experience a significant proportion of production incidents happen because a six line shell script gets modified incorrectly, or does not handle an unexpected condition properly."

"My" six-line shell script isn't on production. It's something I wrote to rearrange my mp3 collection, or whatever. Then I deleted it.

My personal threshold for leaving shell is quite low. We may make fun of Perl, but it's really a lot, lot better than shell for any serious task. It's even lower for "production" tasks.

But whipping out the Rust because I want a shell script to increase the brightness of my screen through the /proc file system is massive overkill. I can write the thing in the amount of time it takes you to compile the Rust, and I'm not particularly trying to make fun of Rust here... it's just massive overkill.


I actually ended up writing a Rust program to change screen brightness through /proc myself. Previously, I used a Python script. Understandably, the Rust program is very significantly faster than Python, and I was surprised by the difference it made for interactive use (changing brightness by a scrolling keybind). For comparison, here are two iterations of the Python code, and the Rust code: https://gist.github.com/FreeFull/1e5873f0b13ec291158176db9d7...


> "My" six-line shell script isn't on production. It's something I wrote to rearrange my mp3 collection, or whatever. Then I deleted it.

Which is fine unless it deletes your mp3s, or dumps them all in the same folder, or something. A script inherently has the potential to do a lot of damage, because it can take a lot of actions very quickly. So it's worth being safe even if that means being a little slower.

> But whipping out the Rust because I want a shell script to increase the brightness of my screen through the /proc file system is massive overkill. I can write the thing in the amount of time it takes you to compile the Rust, and I'm not particularly trying to make fun of Rust here...

If your point is that a REPL or shell is a worthwhile feature then I agree with that. But you can have that in a safe language too.


> Consider the advanced features as a scientific prediction: "If you do not use these features, you can't have a good program come out the other end." This prediction is falsified by the concrete existence of a lot of good Go programs. This matters. It is something that should be grappled with intellectually, if you are a language fan.

I didn't mention anything about fancy features such as the likes of what Haskell and gang bring. I'm referring to much more "basic" things like generics, good error handling, non-nullable by default pointers, and so on. Things that one has come to expect in a modern language (which golang isn't in general).

Having the ability to provide abstractions does not mean must use them to write software, but that they are available when required, and when used correctly, they end up simplifying the overall system architecture. I think the world has moved on from writing abstractions for the sake of writing abstractions, and I agree that it's not the way to go if such code is still being written. But the solution is not to get rid of the ability completely, resulting in a different sort of mess. At least we have tools that make navigating large code bases easier.

I feel it's actually golang people end up reinventing things differently just for the sake of writing things differently. Take the builder pattern for instance. For some reason, golang code I see uses a different, more convoluted pattern of passing an options struct that gets returned in a closure to emulate that. It's a bigger mess to understand, and probably ends up generating more work for the GC since closures keep getting allocated.


I was also solving problems in Z80 Assembly, once upon a time.


The sort of deeper understanding I'm talking about will actually integrate that as a point in a more comprehensive picture, rather than thinking of it as some sort exceptional case. To the extent that you have a model in your head where that point doesn't fit (and, I assume, believe that would somehow challenge the model in my head), I'd say that is also a point to consider and ponder and try to integrate, rather than having it sit outside of the model that only fits a fraction of the code out there, and has places where it actively mismatches existing code bases.


I would argue that the select is the more important feature. Goroutines are just lightweight threads, and go isn't the first language to have them.

No generics suck, unfortunately. I don't care that most things aren't expressions, and tbh, I don't know a lot of people that do. System-depdendent int is not a problem for me, but I recognize that it is a problem in some fields. I like how interfaces are designed and used in the language, so I don't share your opinion there. For the time package, the only thing that's badly designed is the American-centric parsing system. Everything else is, for me, ahead of the various package I've used in other languages.


The fact that duration is basically an int wrapper around nanoseconds, and converting between different units is very awkward are just the beginning. Take a look at Joda time (JVM, which served as the basis of what later was integrated into the standard lib) or Noda time (.NET) to see examples of properly designed time libraries. It's no wonder that golang's badly designed time library caused an outage at cloudflare.


The codebase of Go itself (which is in Go of course) has been there for multiple "couple of years" already.


> Are they going to be able to rework the whole language to incorporate whatever 2020's equivalent to the concurrency revolution is?

This is why i'm sad that Rust has baked async/await into the language. Somewhere in the RFCs, it is stated that "async/await is now known to be the right way to do concurrency" or something like that, but to me it is clear that it is at least a decade too soon to say that.


I would be curious if you could find a link for that quote, because Rust has always been of the mind that there is no one correct approach for concurrency, and has good support for channels, threads, work-stealing task pools, etc., all intended to serve different use cases. If there is a line like that somewhere in the RFCs, I would expect it to be in the context of "the design of async/await proposed herein is now known to be the right way to do asynchronous I/O in Rust, given Rust's other design choices and constraints [in contrast to the years of other experiments have been tried, including Go-style green threads]". In particular the long term goal is not to make async/await the end-all be-all, but rather to expose a generalized concept of generators which async/await is then built upon.


It turns out to be hard to do concurrency in a library, if you need both absolute correctness (e.g. works with all system calls) and scale (more threads than the OS native threading will allow).

Afaik only Go and Erlang currently meet (at least my) criteria. No JVM solution currently does.


You have solutions like Akka, Vertx, and Reactor/RxJava on the JVM. Not to mention that the JVM is getting a green thread (fiber) implementation by means of project Loom.


"a programming language for people who are sick of programming languages" is nonsense.


Is it nonsense? Makes perfect sense to me. There are programmers who don't get excited about languages as a topic and would rather just get on with it. "People who are sick of programming languages" seems like an apt description for that crowd.

I personally dislike Go, precisely for many of the reasons why those "people who are sick of programming languages" would like it!


I like the phrase, too. I'm on the "sick of programming languages" side, and I like go, for the things I'm using it for: CLIs, simple debug web-servers, calling out to RPC services. (Read a CSV file, run everything through translate / grammar parsing / etc.)

I'm in that age of folks that did pascal in high school, C and Scheme in college, C++ and python in grad school while futzing around with ocaml and common lisp and sather and other fun things. Programming languages are fun.

But, oh, I have so much other stuff to pay attention to. I write C++ a few days a week, which is barely enough to keep move semantics in my head. I also write SQL and analysis docs and internal DSLs and configuration files and python.

At this point, C++ is barely earning its keep, in terms of mental complexity for reward. Go feels a lot nicer, since I can just get in, do my thing, get out, and it'll at least work and give me a compile error if one of the APIs change when I don't look at it for a year.

I'm not about to jump into rust.

So, at least for me, go hits a pretty good sweet spot.

[Edit: I'm not trying to point fingers at rust in particular. It looks fun. If I weren't still working on getting my hobbyist-Haskell better, I'd probably be playing with it. But that would be at home, for fun, not where I have to have the thing in my head for production issues.

It reminds me a bit of the old statement about perl, that it was a fantastic language if you used it every day, but not if you don't. And I don't get to use these things every day any more.]


Please give me this nonsense. I'm sick of programming languages.


Protip: You can write FORTRAN in any language!


Of course, you can (re)write code in any Turing-complete language in any other Turing-complete language.


Why?


Look at Java. Look at Spring and look at all the other junk out there. Every corner you go around you see smart people trying to outsmart each other rather than solve problems. Go makes that harder.


Spring and Java aren't junk.

I like Go for some things, but when using it I miss many things from Java:

* I can connect to the running JVM and change log levels, and other parameters live.

* I can debug a Java file that has compilation errors in it and fix them as I go in some cases. (In Go you can't even compile a file with an unused import)

* Java libraries and frameworks are mature. Some have been around for decades with all the testing and refinement that implies.

For some applications, like a REST server connecting to a database, why would I use Go and use all it's brand new, limited libraries when I could use dropwizard instead and get an easy to deploy JAR file?

Sure Java has some esoteric features, but you don't have to use them.

If you can't keep your team from being clever in Java, I doubt you'll be able to do so just because they use Go.

I've seen many Go libraries attempt to use introspection and backtick 'annotations' to very confusing and buggy effect.



Spring boot is fantastic if you havent checked it out.


Spring Boot is precisely the magical nonsense the GP was complaining about.


I like Java and Spring, but I don't use Spring boot.

Note that just because the recent tutorials out there mention Spring Boot, doesn't mean you can't wire together a Spring app either through config files or programatically.


In my opinion, its not any more magical than any other framework.

What it is though is something that solves problems and has a great ecosystem, instead of reinventing the wheel.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: