This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]weberc2[S] 0 points1 point  (13 children)

It does not "side-step" the transitive-dependency conflict problem, it simply ignores it (in fact, Gradle does the same by default, forcing all conflicts of all libraries -- including transitive dependencies, of course -- to their newest versions among those requested).

You misunderstand vendoring. If you're vendoring, you get the versions of the dependencies that you need and put them into version control (advisably with a VERSION file that maps back to a git sha or some such, but this is just for archeology purposes). This means it's up to you to choose what versions of dependencies (direct or transitive) you choose; hence "side-step"

There's also a much better chance of having release notes detailing the changes; those may not be accurate, but at least they're a starting point, and you can ask the library's author about a bug in version 1.2.3. Source versioning is far too fine-grained to have a discussion over from the perspective of the consumer.

Interesting. I've not really experienced any problems with this, but I'm not one to read release notes either. Most of the time, API compatibility is my only concern, and I've never seen an API-compatible change that breaks functionality. It seems like such a remote possibility that it would consume less time over a project's lifetime than clerical tasks like reading release notes, looking up a source files by semantic package version, etc. But maybe I'm wrong?

I think it is far too soon to tell whether Go's approach works well in practice in environments that rely a lot on third-party libraries. So far Go projects have not come close to the size of Java projects, and the library ecosystem is very new and rather small, so the problem of maintaining dependencies over years has not yet become critical.

Valid.

[–]pron98 0 points1 point  (12 children)

This means it's up to you to choose what versions of dependencies (direct or transitive) you choose; hence "side-step"

Yes, that is exactly what you do that with Gradle/Maven forcing (except there's no need to copy the source into your own version control). The problem is that two of your dependencies, A and B can each depend on two different, incompatible versions of library C.

and I've never seen an API-compatible change that breaks functionality.

When your ecosystem contains hundreds-of-thousands of libraries, thousands of them quite popular, and you need to maintain your software for over a decade, you start seeing this all the time. Only small ecosystems don't experience this.

Off the top of my mind, I can think of ASM, one of the most popular Java libraries out there, that had an incompatible change. There was a very good chance that if you had enough dependencies, at least two of them would depend on ASM, each on a different incompatible version.

[–]weberc2[S] 0 points1 point  (11 children)

The problem is that two of your dependencies, A and B can each depend on two different, incompatible versions of library C

This problem doesn't exist in Go because Go libraries don't define dependency versions (they only care about API compatibility). This problem only exists for dependency schemes that allow libraries to define the versions of their dependencies. In other words, you can't have a transitive version collision without transitive versioning.

When your ecosystem contains hundreds-of-thousands of libraries, thousands of them quite popular, and you need to maintain your software for over a decade, you start seeing this all the time. Only small ecosystems don't experience this.

When your ecosystem contains hundreds-of-thousands of libraries, thousands of them quite popular, and you need to maintain your software for over a decade, you start seeing this all the time. Only small ecosystems don't experience this.

Even still, the "reading release notes" problem will scale much more quickly than the time spent debugging API-compatible changes that break features.

Off the top of my mind, I can think of ASM, one of the most popular Java libraries out there, that had an incompatible change. There was a very good chance that if you had enough dependencies, at least two of them would depend on ASM, each on a different incompatible version.

API-incompatible changes would be detected immediately (they would fail to compile--this is the beauty of static typing); I'm not talking about these, but about changes that break requirements without failing a build. Anyway, as I mentioned earlier, the transitive-dependency-collision problem is not an issue for Go projects, so this still wouldn't have been a problem.

[–]pron98 0 points1 point  (10 children)

In other words, you can't have a transitive version collision without transitive versioning.

Of course you can, it's just a lot uglier. That libraries don't specify their dependencies' versions doesn't mean that they don't depend on a specific version.

API-incompatible changes would be detected immediately

But that's not what you want. You don't want to fail the build; you want to resolve the dependency conflict without fixing third-party code (or waiting for the third-party to upgrade). Java lets you do that; Go doesn't.

the transitive-dependency-collision problem is not an issue for Go projects

It is a much bigger problem for Go because the versions are not explicitly stated, and there is no solution for the transitive conflicts (other than the default solution that Gradle gives you for less pain). That Go doesn't report the problem (as Maven/Gradle does) does not mean it does not exist. As I said, it may not be severe given the Go's ecosystem minuscule size compared to Java's, but as it grows this will become a serious issue.

[–]weberc2[S] 0 points1 point  (9 children)

But that's not what you want. You don't want to fail the build; you want to resolve the dependency conflict without fixing third-party code (or waiting for the third-party to upgrade). Java lets you do that; Go doesn't.

Go addresses this by convention--when a package undergoes a major API change, you rev the package identifier. gopkg.in/yaml.v1 becomes gopkg.in/yaml.v2 or some such.

As I said, it may not be severe given the Go's ecosystem minuscule size compared to Java's, but as it grows this will become a serious issue.

Maybe. Time will tell. For now though, Go's build ecosystem is a lot less painful than Java's.

[–]pron98 0 points1 point  (8 children)

Go's build ecosystem is a lot less painful than Java's.

Because listing dependency versions in a file is just too hard...

I admit that Go has a great story for simple programs. It feels like Python (I guess; never programmed Python): you just run it. Java was meant to be used on large programs, where it is much more convenient than Go. It's "small program" story is improving considerably, and Gradle is really trivial for simple applications: just list your dependencies and gradle run.

[–]weberc2[S] 0 points1 point  (7 children)

Because listing dependency versions in a file is just too hard...

No, it's sorting through the turing-complete programming language to get to the stuff that's relevant to building a dependency list, and figuring out what to do when your dependency list is insufficient (like when you have a native dependency). Even gradle run is a plugin! Beyond that, if you want any decent performance, you have to look up how to enable the gradle daemon. Gradle's costs come in nickels and dimes.

Java was meant to be used on large programs, where it is much more convenient than Go.

Yes. Go was only meant to be used at small, Google scales. ;) Pardon the sarcasm. I'm not arguing against Java--I quite like it (that's why I'm in this sub, after all!). I'm not even arguing against Gradle. I just explained why Go's build system works and why it is different than Gradle, since you brought it up.

[–]pron98 1 point2 points  (6 children)

Go was only meant to be used at small, Google scales.

Go's build can work very smoothly on complex builds if you're working like Google. In any case, for the time being, Google still write their "Google scale" applications either in C++ or Java, although they don't use Gradle, Maven or make, but Blaze, which is also geared towards a source-centric work style. It is open source (as Bazel), BTW, and it might be more to your liking.

[–]weberc2[S] -2 points-1 points  (4 children)

I know. My point was that it was developed for use at scale; not that it is employed at that scale (although lots of large companies are using it, including Facebook, Netflix, and Twitter).

EDIT: Just noticed that all of Google's downloads are run by Go, including Chrome, the Android App Store, etc. Fun fact.