Erm, yes it did. The civilized world (Java, Ruby, Python, Clojure, Scala, Haskell, OCaml) has version numbers in their dependency management. Albeit out-of-band from the source files (pom.xml, gemfile, requirements.txt, project.clj, sbt, .cabal, OPAM version pinning) but it does work.
Hell with Clojure and Leiningen (the standard choice for dependency mgmt) even the language version is a per project dependency ala:
[org.clojure/clojure "1.5.1"]
So you can still build jars that "just work" even if it's some legacy stuff that you haven't updated to the latest Clojure version yet.
That's not to say Clojure would've helped here - it's a game. And one that's aiming for better graphics - JVM isn't a good idea.
But that doesn't excuse Go's poor package management design that decided being facile and hid complexity of the real problems (changes breaking existing code) was more important than working builds.
The decision to make it facile, weak, and fragile was egregious and very out-of-character with the rest of their design decisions. I think Go can be faulted for failing at their own goals on this particular matter.
Go has localised dependencies: you package your code with exactly the versions you need.
> So you can still build jars that "just work" even if it's some legacy stuff that you haven't updated to the latest Clojure version yet.
And with a Go project, one would have a complete system which 'just works,' complete with all dependencies, regardless of how old those dependencies actually are.
> But that doesn't excuse Go's poor package management design that decided being facile and hid complexity of the real problems (changes breaking existing code) was more important than working builds.
Go doesn't do what you think it does (probably not your fault: the article is misleading). It only pulls down updates if you tell it to. It sounds like the developer of the original code was doing the wrong thing, not using GOPATH the way it was designed, not checking his entire source tree—including dependencies—into version control. I could be wrong, of course: it's possible that he really did use it properly but discovered a misfeature I've not yet found.
I think the fact that every Go proponent attacks the developer of the game is one thing which keeps me from using Go. The community seems to be incredibly closed-minded and hostile.
From the perspective of one developer's checkout it can't. But a new clone of the project since dependencies have moved yields a new product where the libraries have "moved" since a previous clone. I think that counts as "changing underneath you" for some definition of that term.
That being said I don't really think it is Go's fault for the developer not understanding that they need to keep a clone of dependencies if they don't want them to move.
No, because a project's tree contains the source code of all dependencies. Why do folks keep on saying this?
Here's how it works: you create a directory foo-proj, then export GOPATH=/path/to/foo-proj:$GOPATH (or whatever you like); then you run 'go get github.com/baz/bar example.org/quux'. Go downloads the current version of the bar and quux libraries, and then creates foo-proj/src/github.com/baz/bar and foo-proj/src/example.org/quux, putting the right files in the right place; it then builds each package, putting the object files in foo-proj/pkg.
As the developer, you configure your VCS to ignore foo-proj/pkg, then you commit foo-proj. You might put your own code in foo-proj/src/fooproj, or foo-proj/src/example.com/foo or whatever.
When another developer clones your project, he gets foo-proj, which includes foo-proj/src, which contains foo-proj/github.com/bar/baz and foo-proj/example.org/quux and everything else.
I suspect what happened in this case is that the developer was building his code as another library, rather than as a project, and pulling it into his GOROOT, letting Go grab his dependencies but not putting them into version control.
It's also possible that he was doing the right thing, but didn't realise that git wasn't tracking submodules without his involvement.
Nah, not that I like Go very much but while reading this article I was like "oh, and how is this Go's fault?". It is like I'd depend on some library and then the library gets pulled from the internet or updated in an incompatible way, how is this a problem of the language that I develop in.
I might as well blame my text editor for allowing me to do stupid things.
The difference is whether the editor turns around and deletes /home as a punishment (Go community) or tries to educate the user about a better approach without acting like an asshole (pretty much all other language communities).
It _does_ do it by default; the problem in this case appears to be (although I could be wrong) that the developer went out of his way to do the wrong thing. As I've noted elsethread, I could be wrong; possibly he was misled by something else.
But the default way Go handles dependencies is exactly the way one would expect: you code against one version of a dependency, and have to manually pull in a new one.
use Moose 2.08;
That's valid Perl and will blow up if you have Moose 1.02 installed. Of course, it'd be even better if you could be more specific than just "2.08 or greater", but it's still useful as is.I'm not a Perl user, I don't consider running sed on my source code to be a "bonus".
Still better than Go though.
I'm sure Perl isn't unique here, of course.
That was completely unnecessary.
M4? Make + C preprocessor? Perl generating Perl? I tried to guess the least-absurd option for updating a library.
Please inform the rest of us what the standard tooling for handling this in the Perl community is.
I agree that, if this problem had been foreseen during development, better version control could have helped.
> Go didn't screw anything over
This is where I disagree. Having a language feature to fetch dependencies from mutable online sources means that you're practically asking for programs to break unpredictably based on external changes. The local cache makes it worse, because every machine will have a slightly different version of the library, and bugs won't be reproducible.
Go devs always said that Go is designed to solve Google problems in Googley ways. All Google code builds from HEAD, at least it did when I was last there. The reasoning for this is that breaking changes can be discovered ASAP, instead of depending on code several versions back that might be much more painful to upgrade should the need arise.
This is another case of the Google way having a sane reasoning, but perhaps does not work in other cases. I'd personally prefer some versioning system, but I can see why they've done it the way they did.
Looks like Google should not advertize Go as general purpose language for everyone to use? Especially the tone of Go related postings here on HN is that everyone should replace C, PHP, Python, Java, JavaScript, etc. with Go because it's better, faster, more scalable on server.
Do I understand you correctly?
Yes, you are trusting Google not to maliciously change the file to something evil, but that is quite different to linking to the trunk of a repository that is expected to change.
Visiting http://golang.org/doc/code.html I see examples like this:
import "code.google.com/p/go.example/newmath"
There is no discussion about versioning in the 'Remote Packages' section - instead we are told "This convention is the easiest way to make your Go packages available for others to use.” My reading is that importing from HEAD is a Go convention.Again, as I mentioned elsethread, I'm pretty new to Go, so perhaps I've been misusing it.
How would you guarantee that known version? Using the normal import above would not do this, esp. if you are working with other developers or have to switch computer/reinstall your dev environment/update. You'd get the current head (not a known version) of all dependencies whenever you run go get on a fresh install, because there is no package versioning in go import statements or go get.
The only way currently to guarantee you get a known version is to fork your dependencies, put all the code in your own repository and update them manually. That's not the end of the world but it's not as elegant as the rest of the go build system.
Because that's the source code sitting in your src tree. That's actually exactly what 'go get' will do: pull the source code of the current version of the dependency into your src tree and build objects in your pkg tree.
> The only way currently to guarantee you get a known version is to fork your dependencies, put all the code in your own repository and update them manually.
Nope, you just use (e.g.) a git submodule for the dependency. When you need to, but only when you need to, you can update each dependency or all at once.
Using go get on its own is not enough to end up with a known version - each go get can pull different code, unless you have manually set up dependencies first as part of the package or checked in the entire src tree and shared that. This works fine for one person working on code but obviously requires a bit more work if you're sharing code with dependencies with others.
I not trying to say it's impossible to manage or a huge flaw in go get, but it does require you to deal with dependency versions explicitly yourself, unlike many other packaging systems.
That's what I was describing. The developer of the dependent code pulls in the dependency with go get, and then other developers see both his dependent code and the dependency he was using.
No it doesn't. Go get or import doesn't let you specify a tag of a repo - if it had the developers would have an easy way out of this situation as they could specify their dependencies on import when first importing. That's not to say this is the go developers fault, but it does highlight a weakness in go dependency management:
Go get always checks out the HEAD. They have a scheme for checking out tags only for golang versions so they have the code to handle tags etc in popular repos, but hardly anyone uses the language versioning support because it just isn't (and shouldn't be) required, and requires a specific scheme of tag names to work anyway. At present golang versioning is only used for this, and it's not widely used as a result.
Of course you can work around this, and it's hardly a showstopper - at the simplest level you could go get then checkout a specific branch with git instead before building, or fork the repo, keep local copies in your source control etc. you only have to do this once for dependencies and then they won't change unless you decide to update them.
The bizarre thing is that go get does know about git tags and versioning it just refuses to make that useful for users unless they want to version the language, not the libraries they use - I imagine this was useful in early language development, but now that they've hit 1.0 and are promising to be backwards compatible it seems pretty pointless.
I'm not sure why you think that. It's perfectly reasonable to want to use new features in Go 1.1 while maintaining backward compatibility (or an older version) for Go 1.0.
I haven't seen much use of the go language auto-versioning feature in the wild, whereas lots of people have noticed the lack of support for versioning packages/imports and the implications for unpredictable builds - any dependency imported the normal way could break at some time in the future or for different coworkers who checked out at different times, unless you fork which has its own problems for maintenance. Personally I think versioning packages is more important, and would prefer to have that option rather than the option to maintain branches for different versions of go (which can be done manually where really required and is unlikely to be an issue in the 1.x series).
The features have nothing to do with each other---it's not an "either or" deal.
I haven't used the `go1.0` or `go1.1` tags myself.
People have tried setting up versioned packages, but it hasn't taken. As for me, I'm quite happy with the simplicity of `go get`. It's been working great for me for over a year.
I also like the simplicity of go get and don't feel this is big deal, but having used other packaging systems suspect that go will start versioning packages eventually as it makes life a lot easier if you are building on code from elsewhere and want to share code. The present setup works fine, with the caveat that if you don't fork all dependencies, other users might see different build results for the same code.
I strongly disagree. I've used other packaging systems and they are a constant source of grief. I very rarely need to pin dependencies so it doesn't make sense to work with a super-powerful tool that allows dependency management at the version level. If I did, then I understand the need for the power.
> The present setup works fine, with the caveat that if you don't fork all dependencies, other users might see different build results for the same code.
That's not a caveat; that's a strength. When this happens, I get a bug report from a user, and I fix my software. Then it works.
Bitrot is a damn hard problem to solve. I'd rather it smack me in the face then creep up on me and strike when I least expect it.
N.B. I fully understand there are scenarios when reliability of builds is important. If I were in that scenario, I'd accept the pain of pinning dependencies or writing my own tool to do so. The great thing about Go is that I could do that with relatively little pain. (Its standard library contains amazing tools for analyzing Go source files.)
An equivalent would be linking to a HEAD version of a library.
My links to documents on SGI don't seem to work...
https://groups.google.com/forum/?fromgroups=#!topic/golang-n...
Yes and it is only the fault of these devs that they did not do that. One of the first things I did when starting a job programming Go full time was go- woah, we need to clone our dependencies so we can manage upgrades. It was just common sense and easy.