TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Go += Package Versioning

336 点作者 bketelsen大约 7 年前

34 条评论

munificent大约 7 年前
I&#x27;m going to comment mostly on the parts of the proposal that I think are wrong, but don&#x27;t take this to be an overall negative response. I&#x27;m excited to see smart folks working on this, and package management is a really hard problem. There are no silver bullets to code reuse.<p>Context for those who don&#x27;t know: I along with Natalie Weizenbaum wrote pub[1], the package manager used for Dart.<p><i>&gt; Instead of concluding from Hyrum&#x27;s law that semantic versioning is impossible, I conclude that builds should be careful to use exactly the same versions of each dependency that the author did, unless forced to do otherwise. That is, builds should default to being as reproducible as possible.</i><p>Right on. Another way to state this is: Changing the version of a dependency should be an explicit user action, and not an implicit side effect of installing dependencies.<p><pre><code> import &quot;github.com&#x2F;go-yaml&#x2F;yaml&#x2F;v2&quot; </code></pre> <i>&gt; Creating v2.0.0, which in semantic versioning denotes a major break, therefore creates a new package with a new import path, as required by import compatibility. Because each major version has a different import path, a given Go executable might contain one of each major version. This is expected and desirable. It keeps programs building and allows parts of a very large program to update from v1 to v2 independently.</i><p>It took me several readings to realize that you encode the major version requirement <i>both</i> in the import string and in the module requirements. The former lets you have multiple copies of the &quot;same&quot; module in your app at different major versions. The latter lets you express more precise version requirements like &quot;I need at least 2.3, not just 2.anything&quot;.<p>I think it&#x27;s really going to confuse users to have the major version in both places. What does it mean if I my code has:<p><pre><code> import &quot;github.com&#x2F;go-yaml&#x2F;yaml&#x2F;v2&quot; </code></pre> But my go.mod has:<p><pre><code> require ( &quot;github.com&#x2F;go-yaml&#x2F;yaml&quot; v1.5.2 ) </code></pre> I don&#x27;t know if the goal of this is to avoid lockfiles, or to allow multiple versions of the same package to co-exist, but I think it&#x27;s going to end up a confusing solution that doesn&#x27;t cleanly solve any problem.<p>For what it&#x27;s worth, Dart does not let you have two versions of the same package in your application, even different major versions. This restriction does cause real pain, but it doesn&#x27;t appear to be insurmountable. Most of the pain seems to be in the performance issues over-constrained dependencies caused in our old version solver and not in the user&#x27;s code itself.<p>In almost all cases, I think there is a single version of a given package that would work in practice, and I think it&#x27;s confusing for users to have an application that has multiple versions of what they think of as the &quot;same&quot; package inside it. This may be less of an issue in Go because it&#x27;s structurally typed, but in Dart you could get weird errors like &quot;Expected a Foo but got a Foo&quot; because those &quot;Foo&quot;s are actually from different versions of &quot;foo&quot;. Requiring a single version avoids that.<p><i>&gt; I believe this is the wrong default, for two important reasons. First, the meaning of “newest allowed version” can change due to external events, namely new versions being published. Maybe tonight someone will introduce a new version of some dependency, and then tomorrow the same sequence of commands you ran today would produce a different result.</i><p>No, I think newest (stable version) is the right default. Every package manager in the world works this way and the odds that they <i>all</i> got this wrong are slim at this point.<p>At the point in time that the user is explicitly choosing to mess with their dependencies, picking the current state of the art right then is likely what the user wants. If I&#x27;m starting a brand new from scratch Ruby on Rails application today, in 2017, there is no reason it should default to having me use Rails 1.0 from 2005.<p><i>Every</i> version of the package is new <i>to me</i> because I&#x27;m changing my dependencies right now. Might as well give me the version that gets me as up-to-date as possible because once I start building on top of it, it gets increasingly hard to change it. Encouraging me to build my app in terms of an API that may already be quite out of date seems perverse.<p><i>&gt; This proposal takes a different approach, which I call minimal version selection. It defaults to using the oldest allowed version of every package involved in the build. This decision does not change from today to tomorrow, because no older version will be published.</i><p>I think this is confusing <i>older</i> versions and <i>lower</i>. You could, I suppose, build a package manager that forbids publishing a version number lower than any previously published version of the package and thus declare this to be true by fiat.<p>But, in practice, I don&#x27;t think most package managers do this. In particular, it&#x27;s fairly common for a package to have multiple simultaneously supported major or minor versions.<p>For example, Python supports both the 2.x and 3.x lines. 2.7 was released two years after 3.0.<p>When a security issue is found in a package, it&#x27;s common to see point releases get released for older major&#x2F;minor versions. So if foo has 1.1.0 and 1.2.0 out today and a security bug that affects both is found, the maintainers will likely release 1.1.1 and 1.2.1. This means 1.1.1 is released later than 1.2.0.<p>I think preferring minimum versions also has negative practical consequences. Package maintainers have an easier job if most of their users are on similar, recent versions of the package&#x27;s own dependencies. It&#x27;s no fun getting bug reports from users who are using your code with ancient versions of its dependencies. As a maintainer, you&#x27;re spending most of your time ensuring your code <i>still</i> works with the <i>latest</i> so have your users in a different universe makes it harder to be in sync with them.<p>Look at, for example, how much more painful Android development is compared to iOS because Android has such a longer tail of versions still in the wild that app developers need to deal with.<p>If you do minimum version selection, my hunch is that package maintainers will just constantly ship new versions of their packages that bump the minimum dependencies to forcibly drag their users forword. Or they&#x27;ll simply state that they don&#x27;t support older versions beyond some point in time even when the package&#x27;s own manifest states that it technically does.<p>There is a real fundamental tension here. Users — once they have their app working — generally want stability and reproducibility. No surprises when they aren&#x27;t opting into them. But the maintainers of the packages those users rely on want all of their users in the same bucket on the latest and greatest, not smeared out over a long list of configurations to support.<p>A good package manager will balance those competing aims to foster a healthy ecosystem, not just pick one or the other.<p>[1]: <a href="https:&#x2F;&#x2F;pub.dartlang.org&#x2F;" rel="nofollow">https:&#x2F;&#x2F;pub.dartlang.org&#x2F;</a>
评论 #16424641 未加载
评论 #16424818 未加载
评论 #16425734 未加载
评论 #16423468 未加载
评论 #16423819 未加载
评论 #16429862 未加载
评论 #16428961 未加载
评论 #16427177 未加载
评论 #16426141 未加载
Animats大约 7 年前
I have misgivings about all this version pinning. At first, it seems to make things easier. Programs don&#x27;t break because some imported package changed. So it looks like a win. At first.<p>Over time, though, version pinning builds up technical debt. You have software locked to old unmaintained versions of packages. If you later try to bring some package up to date, it can break the fragile lace of dependencies locked in through past version pin decisions.<p>Some version pinning systems let you import multiple versions of the same package into the same build to accommodate dependencies on different version. That bloats executable code and may cause problems with multiple copies of the same data.<p>On the other side, once package users are using version pinning, it&#x27;s easier for package maintainers to make changes that aren&#x27;t backwards compatible. This makes it harder for package users to upgrade to the new package and catch up. Three years after you start version pinning, it&#x27;s going to be a major effort to clean up the mess.<p>The Go crowd tries to avoid churn. Their language and libraries don&#x27;t change too much. That&#x27;s a good, practical decision. Go should reject version pinning as incompatible with the goals of Go.
评论 #16423431 未加载
评论 #16423069 未加载
评论 #16423197 未加载
评论 #16423018 未加载
评论 #16423098 未加载
评论 #16423272 未加载
评论 #16423892 未加载
评论 #16428507 未加载
评论 #16423079 未加载
评论 #16423240 未加载
评论 #16423250 未加载
readams大约 7 年前
Damn it. Just when dep seemed like it was going to finally end the horrible nightmare that is go dependency management, this comes along. There&#x27;s this great survey of all the progress that had been made and then &quot;but we&#x27;re doing it in this bizarre terrible way because...&quot;
baq大约 7 年前
this sentence<p>&gt; First, the meaning of “newest allowed version” can change due to external events, namely new versions being published.<p>is the root of what&#x27;s wrong with this proposal - namely conflating time of dependency resolution with the time of build. cargo (using it because it&#x27;s been referenced by the post) solves this problem by telling you to check in the cargo.lock that it generates whenever you &#x27;cargo update&#x27;. this means that your version control preserves the build dependencies, just as it preserves build recipes (e.g. build.rs or travis or whatever). in this world, there&#x27;s no &#x27;newest allowed version&#x27;, because there is only one version.<p>wise men before me said &#x27;as simple as possible, but no simpler&#x27; and I&#x27;m afraid this proposal is too simple.
Sir_Cmpwn大约 7 年前
&gt;End of GOPATH<p>Yes yes yes yes finally! This has been the #1 reason I&#x27;ve avoided Go for years and even my recent forays back into the language were only after I figured out some hacks that I could use to avoid it.
评论 #16422773 未加载
评论 #16426762 未加载
评论 #16422710 未加载
评论 #16422729 未加载
评论 #16422826 未加载
steveklabnik大约 7 年前
Glad to see this! I&#x27;m still digesting the details, but to comment on <a href="https:&#x2F;&#x2F;research.swtch.com&#x2F;cargo-newest.html" rel="nofollow">https:&#x2F;&#x2F;research.swtch.com&#x2F;cargo-newest.html</a><p>Cargo does not use the latest version. Saying<p><pre><code> toml = &quot;0.4.1&quot; </code></pre> is the same as saying<p><pre><code> toml = &quot;^0.4.1&quot; </code></pre> NOT saying<p><pre><code> toml = &quot;=0.4.1&quot; </code></pre> which is what rsc would guess.<p>This decision was made because ^ is the most reasonable default; over-use of `=` destroy&#x27;s Cargo&#x27;s ability to help you upgrade, given that you basically asked it to not think about it at all. Further, it would significantly bloat binaries, as this would mean many more duplicate versions of packages in your project. Basically, idiomatic use of = is only in very specific situations.<p>We could have required that you always specify some operator, but we also like reasonable defaults. Writing `^` everywhere is just more typing.<p>The transitive dependency issue isn&#x27;t any different, really: that&#x27;s due to said packages also not using =.
评论 #16423049 未加载
评论 #16423151 未加载
eximius大约 7 年前
&gt; Minimal Version Selection<p>Means no security fixes at the price of, well, minor developer inconvenience? What is the inconvenience, exactly?<p>&gt; ...tomorrow the same sequence of commands you ran today would produce a different result.<p>I mean, I guess this is technically true. But seems like it shouldn&#x27;t be an issue in practice as the API you&#x27;re calling shouldn&#x27;t have changed, just the implementation. If it has changed, then downgrade the dependency?
评论 #16422712 未加载
评论 #16422597 未加载
评论 #16423759 未加载
xrstf大约 7 年前
A lot of this seems to hinge on &quot;go get&quot; being the best way to get Go source code. Most discussions I&#x27;ve read so far come down to &quot;well, this might be cool, but it would break go get, so we cannot ever do it&quot;.<p>I for one could live without go get alltogether. In 99% of cases it boils down to a simple git clone anyway, which could (should?) be done by the package manager anyway.<p>Maybe it&#x27;s time to re-evaluate the existence of go get, now that we&#x27;re seeing that &quot;just clone master and hope nothing breaks&quot; has obviously not worked for everyone outside of Google? Maybe bundling Go (the compiler and linker) with tools for fetching source code wasn&#x27;t such a good idea after all?<p>Just my 2 cents...
评论 #16426531 未加载
评论 #16425630 未加载
howeyc大约 7 年前
I like the removal of GOPATH, even though I don&#x27;t mind it at all, it can be an annoyance, especially when I don&#x27;t want to co-mingle work&#x2F;personal stuff. Now I don&#x27;t need to worry about setting GOPATH based on what I&#x27;m working on. Plus sometimes I&#x27;d wonder, is it all in vendor, or is it using GOPATH for something.<p>Plus now libraries are &quot;modules&quot; so libraries can have dependencies for specific versions, before the question is what do you do if multiple dependencies have the same dependencies in their own separate vendor directories. This change removes that, as it&#x27;s handled by the vgo tool for all modules in that build.<p>go.mod is kind of a cross between lock-file and dependency listing. I think it will work alright.<p>All together, it seems to be a cross between gb and dep, while also attempting to solve library-packages tracking dependencies too.
gkya大约 7 年前
Highly suggest to read the demo at <a href="https:&#x2F;&#x2F;research.swtch.com&#x2F;vgo-tour" rel="nofollow">https:&#x2F;&#x2F;research.swtch.com&#x2F;vgo-tour</a>, which really clarifies everything. I do not write Go, but I did write some bits in it in the past, and now think that this will be a very useful addition to the Go toolchain. When I looked at Go for the first time I really disliked the simple but sort-of castrated go-build, and didn&#x27;t really follow the developments since then, but this seems to solve quite a bit of problems. I especially like how you can shadow a certain dependency with a given package at a given path, and how it facilitates vendoring. Hope this becomes included in go soon.
teacpde大约 7 年前
If there is neither GOPATH nor vendor directories, where will the downloaded packages be?<p>I digged vgo a bit and found the downloaded packages currently reside in `$GOPATH&#x2F;src&#x2F;v&#x2F;cache`, and seems like vgo won&#x27;t work without GOPATH for now (<a href="https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;vgo&#x2F;blob&#x2F;b6ca6ae975e2b066c002388a896833851a9e54a9&#x2F;vendor&#x2F;cmd&#x2F;go&#x2F;internal&#x2F;vgo&#x2F;init.go#L111" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;vgo&#x2F;blob&#x2F;b6ca6ae975e2b066c002388a8...</a>).
shkkmo大约 7 年前
I think that the choice to use &quot;prefer minimum version by default&quot; going to confuse a lot of new developers used to the industry standard being the opposite. If you are going against the industry default, there should be a strong reasons. I don&#x27;t think reasons provided really justify this.<p>&gt; First, the meaning of “newest allowed version” can change due to external events, namely new versions being published. Maybe tonight someone will introduce a new version of some dependency, and then tomorrow the same sequence of commands you ran today would produce a different result.<p>This is why we have lock files and they work better for this.<p>While vgo&#x27;s approach does allow reproducible builds, it doesn&#x27;t allow you to guarantee reproducibility the way that a lock file that has the specific commit hashes does. With specific commit hashes you can verify the the version you are building with in production is the exact same code as the one your security team audited prior to release (assuming git has fixed its hash collision vulernability).<p>You can get around this by abandoning version constraints in your go.mod file, but then you have to track these version constraints out of band and manually figure out what commit hash to stick in go.mod<p>You could also get around this by storing the hases for the approved versions out of band and creating a build script that verifies these hashes prior to building.<p>Both of these workarounds seem to defeat the point of having a standard package manager in the first point.<p>&gt; Second, to override this default, developers spend their time telling the package manager “no, don&#x27;t use X,” and then the package manager spends its time searching for a way not to use X.<p>If you are concerned with allowing users to override this default, why not have directive to override this default that can optionally be added to each requirement in the go.mod file. This avoids an unexpected default and doesn&#x27;t force people who want the industry standard default to use a script to set which dependencies use or don&#x27;t use the -u flag with &#x27;go get&#x27;.
评论 #16425025 未加载
评论 #16425817 未加载
mCOLlSVIxp6c大约 7 年前
I predict that under the proposed minimum version selection system some package will decide it&#x27;s important and flawless enough that users should always depend on the most recent version. The package will recommend that users depend on version v1.0.0 but the first release will be v1.100.0. Subsequent releases will decrement the minor version to make sure newer releases are selected.
评论 #16425613 未加载
评论 #16424608 未加载
评论 #16424672 未加载
mfer大约 7 年前
As I look this over a couple things really jump out at me...<p>1. VCS tags are mutable. That&#x27;s lock files store revision ids. Go is being used to build immutable infrastructure but the proposed package management system uses mutable versions.<p>2. The proposal is less featureful that dep, npm&#x2F;yarn in JS, composer in PHP, maven, crates for rust, and others. I wonder how people will react to that.
评论 #16427053 未加载
readams大约 7 年前
One that that I&#x27;m not able to tell from the proposal: is the &#x2F;v1 at the end of an import path a magical value that the tool handles, or do I literally need to have that directory in my repo and have a version history represented at the top level of every project?<p>Why not do the symbol mangling in the compiler if the goal is to have multiple simultaneous versions built in? This is easy to make backward compatible since it could default to v1.
icholy大约 7 年前
Like all Go things, it looks kinda strange. But after playing around for a bit, it feels really good. The minimal version selection simplicity is genius.
stock_toaster大约 7 年前
I feel like the Go devs optimized implementation simplicity early on (likely a sensible choice given Google&#x27;s &quot;one giant repo&quot; workflow), and that has resulted in some not-insignificant ecosystem complexity later (for others not using &quot;one giant repo&quot; workflows).<p>It will be interesting to see how this plays out in the longer term.
marcrosoft大约 7 年前
Please don&#x27;t remove vendoring...
评论 #16430339 未加载
评论 #16424015 未加载
评论 #16424909 未加载
mbertschler大约 7 年前
Am I totally missing something in this document or does it not talk about where these modules either as zips or source code are stored? It mentions $GOPATH and vendor as not necessary anymore.<p>Where will the actual code be?
j_bond大约 7 年前
I am curious why go doesn&#x27;t just vendor dependencies like npm does when confronted with conflicting requirements instead of trying to figure out a version that satisfies all worlds? I always found this to be a nice feature when working with npm.<p>I am also firm believer in version-pinning&#x2F;lockfiles. Updating versions should be a separate workflow with first-class built-in tools to support it. I think that is the area where most package managers fall flat. They basically rely on the developer to do all the heavy lifting.
评论 #16425695 未加载
codedokode大约 7 年前
&gt; This proposal ... deprecates GOPATH in favor of a project-based workflow<p>That would be awesome. GOPATH was an awful idea that works only for distribution package managers.
tetraodonpuffer大约 7 年前
How would you specify dependencies on a commit&#x2F;tag in a particular branch (say, during development I always want to build with the HEAD of the development branch for this module)? I know I could clone what I want somewhere and use a replace directive inside the go.mod file, but I was wondering if there&#x27;s any way to do this using only vgo.
评论 #16423847 未加载
Keats大约 7 年前
Will there be an official proxy or will open-source projects still break when someone moves&#x2F;deletes a repository?
评论 #16424088 未加载
teacpde大约 7 年前
On one hand, as a developer, I like a Go builtin package management authored and supported by the Go team; on the other hand, I feel bad for the open source contributors who worked hard on third party package managers. Even dep, the officially supported PDM, seems supposed to fade.
评论 #16424520 未加载
platz大约 7 年前
&gt; A build of a module by itself will always use the specific versions of required dependencies listed in the go.mod file. As part of a larger build, it will only use a newer version if something else in the build requires it.<p>This seems fraught
评论 #16425348 未加载
013a大约 7 年前
This is a well reasoned proposal. I&#x27;ve got a couple qualms.<p>Let&#x27;s say you care about strict build reproducibility. You want some form of manifest + lock file that defines exactly what versions of dependencies your package expects. Great; more power to you.<p>The only reason you&#x27;d want that is if you aren&#x27;t storing your dependencies with your source code in source control. Otherwise, what&#x27;s the point? If you were vendoring and committing it, you already have strict reproducibility, and you have the &quot;supported versions&quot; defined in the git repositories that come alongside your dependencies.<p>So, adding this manifest+lock file allows you to get away with not vendoring+committing. Awesome. You&#x27;ve gained reproducibility, but certainly not <i>strict</i> reproducibility.<p>Dependency package maintainers can rewrite git history. They can force push. They can push breaking changes with minor versions. They can delete their repositories. All of these things have already happened in NPM, either maliciously or accidentally; why do we think they wouldn&#x27;t happen with Go?<p>If you want strict reproducibility but are expecting it with just a manifest+lock file, without dependency vendoring+committing, you&#x27;re not getting it. Full stop.<p>So, really, by adding a manifest+lock file, you&#x27;re adding a &quot;third level&quot; of reproducibility (#2 on this list).<p>1. Low Reproducibility: Pull HEAD on build.<p>2. Partial Reproducibility: Use tooling to pin to a git commitish, pull this on build.<p>3a. Full Reproducibility (Easy+Dirty): Vendor+Commit all dependencies.<p>3b. Full Reproducibility (Hard+Clean): Mirror your dependencies into a new self-controlled git repo.<p>I am struggling to think of a solid use case that would find real value in #2. I have no doubt that people <i>think</i> it would be valuable, but then the moment the left-pad author deletes his repository, you&#x27;re <i>going</i> to second guess yourself. You didn&#x27;t want #2; you wanted #3 and settled for #2 because #3 was too hard or dirty and you convinced yourself that adding tooling and version numbers was keeping you safe. Because semver, right?<p>Moreover, this comes at the cost of complexity, which is strictly against Go&#x27;s core doctrine.<p>Moreover, a #2 solution looks strikingly similar to gopkg.in. Instead of referencing Repository:HEAD we reference Repository:Commitish. The main difference is that gopkg.in is an external service whereas this would be controlled tooling. But by choosing #2 you&#x27;re already exposing yourself to bad actors, accidents, github going down, all of the above. So you&#x27;re willing to accept that exposure, but aren&#x27;t willing to add that little extra exposure of one more service?<p>I agree that the problem today, even with dep, isn&#x27;t perfect. But I still strongly believe that the answer lies somewhere in the ideas we already have, not by importing ideas from NPM. We need a #3 that is Easy and Clean, not a #2.
glasser大约 7 年前
Is the &quot;import compatibility rule&quot; (ie, `&#x2F;v2` suffixes in package paths) implemented in vgo today?
hota_mazi大约 7 年前
Amazing that in 2018, a language team needs to be convinced that versioning packages is a good idea.<p>What&#x27;s next, persuading them that generics are pretty cool too?
评论 #16424293 未加载
评论 #16424524 未加载
merb大约 7 年前
this looks damn complex.
pcj128大约 7 年前
Just use Bazel to build your go code. It already solved this problem.
leshow大约 7 年前
How does Go not have package versioning? What do you guys use to get the appropriate version of a dep?
评论 #16422982 未加载
pcj128大约 7 年前
Just use Bazel to build your go code. It has already solved this problem.
pknopf大约 7 年前
Generics first please, I can live with using tools like vndr and deep.
评论 #16423099 未加载
评论 #16423083 未加载
fiatjaf大约 7 年前
&gt; we also must not remove the best parts of the current go command: its simplicity, speed, and understandability.<p>Then you propose to introduce the concept of modules and make the world a hell?<p>I believe versioning should be left of to third-party tools. For example, no one is complaining about the lack of versioning built in Node.js.