Help With Go Packaging

xuanbao · · 480 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I&#39;ve been writing Go code in some small / trivial projects for about a month now, and rolled out a few production monitoring applications for some of my teams APIs. I&#39;m mostly managing teams now but still write a lot of code on the side for my own small projects or to help my teams with some ancillary work they need to get done. In the past few years the languages I&#39;ve really been interested in learning have been more academic, so a lot of Haskell / OCaml / StandardML, and despite pining for some features from those languages (pattern matching, Option types, paremeterized functions) in Go I&#39;ve actually found the ability to reason about memory and performance to be pretty nice, and being able to build a fat binary of pure Go code and deploying that is great.</p> <p>Now that we&#39;ve gotten past the supplication phase, though, I&#39;ve really had a ton of problems with the Go packaging and layout system. Go&#39;s insistence on monorepos just rubs me the wrong way, and I&#39;ve had to build up my own little tricks to work around it (bash functions to make it easy to switch the GOPATH in a session). The use of remote repository urls in package names drives me up a wall to the point where I think if I could, I would buy Github and shut it down just to invalidate the package names on hundreds of Go libraries.</p> <p>I&#39;m not sure if I&#39;m going to get over some of these, but I&#39;ve worked with a dozen languages in a serious fashion over the past 20 years, and none of them have been perfect, so I&#39;m sure I can make peace with Go on these things as well. I&#39;d really like to build up a better mental model for this though, so I&#39;m looking for any really top-quality articles or guides anyone can point me to for helping me get through this. It seems like it&#39;s still somewhat contentious even within the Go community, so I&#39;m guessing it&#39;s something a lot of other people have wrestled with and found their own solutions to dealing with, so I&#39;d rather not reinvent the wheel.</p> <hr/>**评论:**<br/><br/>shovelpost: <pre><blockquote> <p>The use of remote repository urls in package names drives me up a wall</p> </blockquote> <p>The import path is an arbitrary string and not specified by the language.</p> <blockquote> <p>to the point where I think if I could, I would buy Github and shut it down just to invalidate the package names on hundreds of Go libraries.</p> </blockquote> <p>The URLs that are used as import paths (by convention) makes the naming of packages decentralized. In theory you can host your Go packages anywhere which makes the system scalable.</p> <blockquote> <p>I&#39;ve really had a ton of problems with the Go packaging and layout system.</p> </blockquote> <p>I was unable to understand the actual problems you are having by your post. Things like &#34;rubs me the wrong way&#34; and &#34;drives me up a wall&#34; are way too vague.</p> <p>I highly recommend you to read <a href="https://talks.golang.org/2012/splash.article" rel="nofollow">Go at Google: Language Design in the Service of Software Engineering</a> to get a better understanding of some of the choices that affected the design of the language. That doesn&#39;t make it perfect or correct. But it gets the job done.</p></pre>JGailor: <pre><p>Thanks for the link, I’ll take a look. With regard to the package naming conventions, I more fully answered the question of why I think it matters.</p> <p>The monorepo question for me is about how I work; I have a lot of locations that I work from based on what I’m trying to accomplish. My working directory at the office is different than my working directory for personal projects and is a different working directory than open source work I contribute to. It means a lot of messing with my environment to switch between projects.</p></pre>shovelpost: <pre><blockquote> <p>I more fully answered the question of why I think it matters.</p> </blockquote> <p>Not in your opening post. If you are talking about your comment</p> <blockquote> <p>but using them as part of the package name feels wrong when you want to, as an example, move from Github to Bitbucket.</p> </blockquote> <p>then you can use <a href="https://golang.org/doc/go1.4#canonicalimports" rel="nofollow">canonical import paths</a> which were designed for this exact case.</p> <blockquote> <p>My working directory at the office is different than my working directory for personal projects and is a different working directory than open source work I contribute to. It means a lot of messing with my environment to switch between projects.</p> </blockquote> <p>If those different working directories are set as the GOPATH in each location then the problem is solved automatically.</p></pre>JGailor: <pre><p>Reading about canonical import paths, is my understanding correct here:</p> <blockquote> <p>&#34;The syntax is simple: put an identifying comment on the package line. For our example, the package clause would read:</p> </blockquote> <p><code>package pdf // import &#34;rsc.io/pdf&#34;</code></p> <blockquote> <p>With this in place, the go command will refuse to compile a package that imports github.com/rsc/pdf, ensuring that the code can be moved without breaking users.&#34;</p> </blockquote> <p>This is something that a repository creator/maintainer would have to anticipate potentially doing and it would break clients if they made the change and a client attempted to fetch the latest package while still importing the package by the old naming scheme, i.e. -</p> <p><code>import github.com/rsc/pdf</code></p></pre>shovelpost: <pre><blockquote> <p>This is something that a repository creator/maintainer would have to anticipate potentially doing and it would break clients if they made the change and a client attempted to fetch the latest package while still importing the old package?</p> </blockquote> <p>Clients are always importing the &#34;vanity&#34; import which is enforced by the go command. So no matter where the project moves the import path of the clients stays the same. For example take a look at the <a href="https://github.com/upspin/upspin/blob/master/upspin/upspin.go" rel="nofollow">Upspin</a> project. The clients import <code>upspin.io</code> even though the project is hosted on GitHub.</p></pre>JGailor: <pre><p>I think I understand that from the perspective of a library that uses the vanity import from the beginning, but my question was around what happens if a client is using a library which used the &#34;github.com/rsc/pdf&#34; package name, but then the maintainer changed the library to use the canonical import path (maybe, in this case, they decided to move the repo to Bitbucket and said, &#34;hey, they added this canonical import path feature in 1.4, maybe I&#39;ll make that change to help ease the transition&#34;).</p> <p>So in this case, my question is whether anyone who has been using the previous import path &#34;github.com/rsc/pdf&#34; and tries to update the library to the latest version, which is using the canonical import path feature, will get an error because their code is still relying on the non-vanity import path?</p></pre>Frakturfreund: <pre><p>Yes: If the library is already developed/used as &#34;github.com/rsc/pdf&#34;, and you introduce a new canonical import, <code>go get -u github.com/rsc/pdf</code> will return an error to please change the import path to the new canonical one. Here it doesn’t matter if the new one will be <code>rsc.io/pdf</code> or <code>bitbucket.org/rsc/pdf</code>, you are forcing your users to update their import paths.</p> <p>The benefit of the <code>rsc.io/pdf</code> is that any future code hosting transition to say &#34;<a href="https://newhub.example.com/rsc/pdf" rel="nofollow">https://newhub.example.com/rsc/pdf</a>&#34; will <em>not</em> force your users to update it, the correct import path will still be &#34;rsc.io/pdf&#34;.</p> <p>You can think of &#34;rsc.io/pdf&#34; as kind of ›symbolic link‹ to the real repository (open <code>view-source:https://rsc.io/pdf</code> in your browser to see it youself).</p> <p>This kind of transition has actually happened in the past; for example, when google code closed, the repo <code>code.google.com/p/go.crypto</code> moved to &#34;go.googlesource.com/crypto&#34;, but it also gained a new canonical import path: <code>golang.org/x/crypto</code>.</p></pre>ms4720: <pre><p>Nice to see go solving &#39;the make bug&#39; issue, even piecemeal</p></pre>tommygeek: <pre><p>It&#39;s been answered already, but monorepo is not what go is trying to make you do. Having a preferred location for all Go projects is a great idea in a highly opinionated language. The fact that you&#39;re saying you have to change that location all the time is troubling... All your Go projects should be in the $GOPATH/src/ folder. I don&#39;t really see a reason why you&#39;d want that to be different in any dev environment. Or why you&#39;d want to isolate projects from each other, really... Maybe your use cases are more advanced than what I&#39;ve encountered.</p></pre>0xjnml: <pre><blockquote> <p>The use of remote repository urls in package names drives me up a wall to the point where I think if I could, I would buy Github and shut it down just to invalidate the package names on hundreds of Go libraries.</p> </blockquote> <p>Both in the quoted above and in your later comments there&#39;s a repeated strange misunderstanding: Package name has nothing to do with any URL. Package name is the single identifier in the package clause, like <code>foo</code> in <code>package foo</code>.</p> <p>Import paths are not connected to package names.</p> <p>And preemptively: import paths are not hard-connected to the URL <code>go get</code> actually downloads the repository either. You can freely move your repository from one provider to another without breaking anyone&#39;s code, see &#39;go help importpath&#39; for info how to provide a stable import path by serving small metadata.</p></pre>014a: <pre><p>Go doesn&#39;t insist on monorepos. Its a nice pattern that you can use if it fits your use cases, but otherwise your GOPATH should just be in some folder like ~/go and your projects should be in ~/go/src/github.com/me/project. Each &#34;project&#34; folder can be its own git repo with its own dependencies.</p> <p>Let&#39;s say someone shuts down Github.com. What impact would this have on third party packages that shutting down, say, npm wouldn&#39;t have on node projects? </p> <ul> <li><p>If npm shut down, a new npm could be created. <em>Maybe</em> it could mirror the old npm, but I&#39;m not aware of any method npm offers to export every single package it is hosting. Every developer that uses npm would have to switch their configured global repository to the &#34;new npm&#34;. </p></li> <li><p>If github shut down, a new github could be created. Actually, hold up, there are plenty of free public git hosting websites, so that&#39;s already done. Package authors would have to transition their packages to a new service, which is a single command from their local repo. They&#39;d have to alert all their users to the change. Go has really good built-in tooling, so we have tools that can rewrite dependency strings across an entire project automatically. </p></li> </ul> <p>Both of these are doomsday scenarios, and both would result in a lot of downtime. The Go one, probably more downtime. The nice thing is, if its a scenario that scares you, you can mirror all the packages you want to have &#34;guaranteed&#34; access to into a self-hosted repo then just reference that. This is <em>much</em> harder to do with npm, though not impossible.</p></pre>JGailor: <pre><p>Thanks for the comment, and you cut to the heart of my problem with baking remote repository URLs into the package name. It means a bunch of semantically invalid names if Github were to go away. There’s nothing wrong with using remote paths to resolve package dependencies, but using them as part of the package name feels wrong when you want to, as an example, move from Github to Bitbucket. Now everyone either has a name that indicates to them that the package is hosted somewhere it isn’t, adding semantic overhead, or clients need to change the package name to reflect its new location.</p> <p>To your point about npm, the mismatch isn’t about centralized lookup; many other package managers allow for specifying remote locations independent of the package name. The dep tools manifests can easily allow for lookup of a package at any source, and if the developer needs to move where it’s hosted then clients can change a manifest instead of their source code if they want to update the dependency. </p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

480 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传