Confession From a Go Programmer
notbroken.org
notbroken.org
- Lack of Generics. I know this has been beaten to death but after using a dynamic typed language all this time, it is even more painful.
- Weird dependency management. No way to lock dependency versions, even if I fork something and depend on it, nested dependencies can fuck up at some point. We need something like NPM to manage our dependencies in a sane way. Importing from live git paths seems like the worst possible solution to this. And there seems to be no widely accepted 3rd party package manager.
- Google... At some point, I'd expect the compiler to require a Google+ account to enable optimizations. /s
Then don't do it. Check your dependencies into your repositories and update import paths.
Copy the new version into the repository, run the import rewriting script and check it in.
> Why is it better to spread the responsibility for updates over all Go authors instead of to the authors of the libraries in question?
Because you want to have full control over your dependencies. What if the author introduces a breaking change or removes the repository from the internet? Do you want to risk your business by being at the mercy of someone else's repository?
This is the problem that Maven, RubyGems, etc. have fixed for so very long that I find it really hard to take Go seriously when this is floated as a solution. And that seems to be a regular occurrence in Go: the willing championing of bad but "simple" solutions (error codes as far as the eye can see!) under the mistaken assumption that things are complex just to be complex rather than that they're complex because they solve a bigger problem.
I can imagine a script that's just a few lines that downloads go-gettable dependencies and updates import paths. You run it at exactly the time you want to update.
> have fixed for so very long that I find it really hard to take Go seriously when this is floated as a solution
By a large margin, I spend the least amount of time configuring my Go packages for release than for any other language.
"Write a script" is a poor solution for an endemic problem.
Bear in mind that it is a one field change in a Gemfile or Composer or Maven/SBT/whatever-Java.
Golang's "package" system works more like C's than like Ruby's: when you build a program out of libraries, you have the source to those libraries in a well-known highly-visible place in your build environment.
Think of Golang's package management as a refinement of the "codebase/<package>/third-party" idiom in C, and not as an npm/bundler competitor. Golang third-party packages don't work like gems. They are raw code that you build as part of your application.
You could build an npm-alike for Golang; I'm not sure how widely used it would be. I like having my third party deps laid out in my repo and easy to read/patch.
You can argue that the C third-party idiom is worse than Rubygems, and reasonable people can disagree, but I've had a lot of experience in C (I started my career as a C dev) and a lot of experience with Ruby, and gems have caused me more problems than third-party deps ever have.
Expanding on this --
There are quite a few dependency management packages for Go already that mimic various other ecosystems, usually written by people who just came to Go from those ecosystems. I can't recommend any because I don't use them because like tptacek I would rather just use a simple repo layout system.
I spend most of my time these days in C++ (writing a game), where there's likewise no package management to speak of, and dealing with the slough of git repos (except when it's hg or svn, because reasons) where I have to go find which ones are updated (and then, how), sucks. It's opaque and stupid and takes time out of my day that could be better spent thinking or writing code or hitting myself between the eyes with a hammer. My favorite dependencies in C++ are ones like Boost that I can just get out of Homebrew as a library and come with release notes. (That's rare enough in C++. And maybe I just pick better Java dependencies, but I pretty much always know what changes between Guava 13.0 and Guava 14.0 without vgrepping a bunch of files. Or compiling the world.)
This is poking me in a sore spot right now because, as it happens, I'm stuck modifying a client's former consultant's pet Go project right now, written in it because trendy. Stuff is broken in some of his pulled-in dependencies, so I've been trying to update them while actually understanding them which means having my head in vimdiff all day. It's making me want to set fire to things and I'm sorely skeptical of claims that this is easier or takes less time for...well...anybody.
Idiomatic bundler, on the other hand --- and, just take my word for it that we've seen a lot of different teams Gemfiles --- treats something like "haml" or "eventmachine" as something akin to a system dependency; versions, when specified, are often fuzzy, like "anything from 1.1.0 to 1.1.9 is acceptable". Ultra-specific versioning in Gemfiles is brittle; a "bundle install" on a mostly-rigid Gemfile can be expected to routinely fail as one gem's dependency on another fails a constraint in the file.
There's an upside to the Bundler mechanism, which is that it's very easy to use and doesn't require you to think about the actual code. In fact, Rubygems even hides cross-language dependencies, so that you can easily use libraries that happen to be native C code without even having to know that you're bridging. But there's a downside too, which is that it's opaque and, like I said, brittle.
Basically you have to decide whether tracking your upstreams is more important than having a deterministic build. The C programmer in me is obsessed with deterministic builds, and Golang appeals to the C programmer in me, not the Ruby programmer.
Again, it's totally legitimate to complain that there isn't a widely-supported npm-alike for Golang. I don't necessarily want one of those, but I can see how a competent programmer would! I'm just saying that it's not reasonable to compare "go get" to npm; they aren't systems with the same goals, even though they sort of look like they are.
> Please explain how manual operations are faster
I said that I spend less time managing package trivia for my Go projects than for any other package. It's not like I spend a lot of time on packages for other languages anyway, but you told me my approach "increased friction." But this is contrary to my experience.
It's not like I have a huge problem with how other languages do things. Or even that I think the `go` tool is better. I just know that it works well. So I'm trying to share that experience for people who can't imagine how it might work well.
In my experience the manual operations required by Go (basically just doing a git/mecurial fork into my own repo and git/mercurial updates as desired) may not be "faster" in the sense of requiring less keystrokes or whatever your measurement is, but it is more predictable and understandable, and not too much "slower".
More complicated dependency management systems are great when they work, and then suddenly a huge pain in the ass when they fail in some edge case, the Go way of doing dependency management might require a very tiny bit more effort but pays that off by being much more transparent.
Nothing you can say will change his stance even a single inch.
(Yeah. Go's dependency management is so great that people keep writing dozens of wrappers/extensions/replacements. sarcasm)
And I can imagine an CSP implementation for C. Should we ditch Go then?
A shell script that runs a few `sed` commands isn't.
Need a mature build tool? Then use one and stop complaining.
http://support.thoughtworks.com/entries/20074167-Using-Maven...
A single tool, "go get", pulls code directly from 3rd parties and puts it in $GOPATH. If you're uncomfortable or frustrated using "go get" there are a number of 3rd party options.
Just copy the dependencies into your repo and adjust the import paths. If necessary, flatten the dependencies of dependencies.
(i.e. if you change your major version, start a new branch. if you change your minor version, start a new branch but continue to update the old one also. Actually, without tool support, that's going to get painful, but the idea is sound and requires only local tooling.)
1. Type safety 2. Convenience
(1) is certainly no worse than a dynamic language, where you don't have type-safety anywhere. (2) doesn't seem that bad to me. You'll write code like this:
x := customStack.Pop().(SaysHello) // error here if x isn't a member of the interface SaysHello
x.Hello()
As opposed to a dynamic language: x = customStack.Pop()
x.Hello() // error here if x doesn't define hello
Disclaimer: I've just poked at Go a little bit. I'm thinking about trying it out as a replacement for some Python code I have.Further disclaimer: As a C++ programmer back in the day I used to make a lot of fun of Java for not having generics (it's had them for a long time now, of course). Lately I've been doing Objective-C (where the situation is like Go, but worse -- no generics nor interfaces; it's all just dynamic), and I've been surprised at how not having generics is Not As Bad As You Might Think. It's basically equivalent to a 'dynamic' language.
While I think it's good to know how to write containers, and how they work, how frequently do you really need to write a custom container? What's wrong with the built in ones (provided they exist)?
Custom containers: Well, it's definitely true that you can get pretty far with just arrays and hash tables -- which Go special-cases! -- but you're probably gunna want something fancier eventually...
Heck, I used to do that in C all the time anyway.
However... The dependency management is my pet peeve #1. I see no problem pulling dependencies from external repositories and building them locally. That practice spans back to at least BSD ports. What I dislike is the fact that I can't specify the version or commit I want to depend on.
I find that the current implementation for "go get" assumes everyone is either a hard-core hacker, always living on the edge (and sometime pushing it) - or they have a full-fledged internal repository infrastructure in place to deal with all the mirroring and continuous integration needs. Go decides internally which revision to checkout and build, using a priority list of hardcoded tag/branch names. If those are not available, it defaults to master:HEAD, /trunk or whatever equal alternative is supported by the underlying SCM. You can not specify "I want to use _this_ version, period" which is a crying shame.
I understand that internally Google doesn't use go get at all. They have their own mirrored repos for everything they need during their builds. Understandable. But ignoring the well-established practice of user-specified upstream component versions is just rude. It forces some "makes sense only in very large organisation" type of practices down the developers' throats.
Not a very encouraging notion, considering the issue is quite trivial, solved in 200 other languages, and it's 2014 already.
That goes on to my pile of things to try out.
You don't say.
1. http://commandcenter.blogspot.com/2011/12/esmereldas-imagina...
Ironic domain name.
https://addons.mozilla.org/en-US/firefox/addon/clearly/
Indispensable for coercing over-exuberant webpages into readability.
This Chrome extension adds a right-click menu item "make readable" that fixes the font on pages like this. https://chrome.google.com/webstore/detail/text-fix/ofafkoecd...
I forgot how snappy the internet is when you keep it simple.
edit: I found the fulltext archived elsewhere on fullhn. This honestly just a listing of Go features and there's no "confession" to speak of anywhere. It seems like the OP would like Erlang.
I'm not sure if there were any confessions. It was basically a "hey, you should try out Go. Maybe. If you want. I like it…" kind of post.
There are no objects in Go, given that Go is not an object-oriented language... oops! (pun intended)
In OOP languages the objects contain the subroutines (methods) hence orienting the programming towards the objects.
Do the more pedantically inclined have a better definition?