Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1264)

Unified Diff: app/views/doc/versioning.html

Issue 162403002: Remove docs and point to ones on dartlang.org. (Closed) Base URL: https://github.com/dart-lang/pub-dartlang.git@master
Patch Set: Re-upload. Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: app/views/doc/versioning.html
diff --git a/app/views/doc/versioning.html b/app/views/doc/versioning.html
deleted file mode 100644
index 76c8b93a0531e7d2bb17dd4f9c54ebcd0882a5f5..0000000000000000000000000000000000000000
--- a/app/views/doc/versioning.html
+++ /dev/null
@@ -1,372 +0,0 @@
-<ol class="toc">
- <li><a href="#a-name-and-a-number">A name and a number</a></li>
- <li><a href="#shared-dependencies-and-unshared-libraries">Shared dependencies and unshared libraries</a></li>
- <li><a href="#version-lock">Version lock</a></li>
- <li><a href="#version-constraints">Version constraints</a></li>
- <li><a href="#semantic-versions">Semantic versions</a></li>
- <li><a href="#constraint-solving">Constraint solving</a></li>
- <li><a href="#constraint-context">Constraint context</a></li>
- <li><a href="#lockfiles">Lockfiles</a></li>
- <li><a href="#when-things-go-wrong">When things go wrong</a></li>
- <li><a href="#summary">Summary</a></li>
-</ol>
-
-<p>One of pub&rsquo;s main jobs is helping you work with versioning. Here, I&rsquo;ll
-explain a bit about the history of versioning and pub&rsquo;s approach to it.
-Consider this to be advanced information. If you want a better picture of <em>why</em>
-pub was designed the way it was, read on. If you just want to <em>use</em> pub, the
-<a href="index.html">other docs</a> will serve you better.</p>
-
-<p>Modern software development, especially web development, leans heavily on
-reusing lots and lots of existing code. That includes code <em>you</em> wrote in the
-past, but also stuff from third-parties, everything from big frameworks to tiny
-little utility libraries. It&rsquo;s not uncommon for an application to depend on
-dozens of different packages and libraries.</p>
-
-<p>It&rsquo;s hard to understate how awesome this is. When you see stories of tiny web
-startups building a site in a few weeks that gets millions of users, the
-only reason they can pull that off is because the open source community has
-laid a feast of software at their feet.</p>
-
-<p>But there&rsquo;s still no such thing as a free lunch. There&rsquo;s a challenge to code
-reuse, especially reusing code you don&rsquo;t maintain. When your app uses tons of
-code being developed by other people, what happens when they change it? They
-don&rsquo;t want to break your app, and you certainly don&rsquo;t either.</p>
-
-<h2 id="a-name-and-a-number">A name and a number</h2>
-
-<p>We solve this by <em>versioning</em>. When you depend on some piece of outside code,
-you don&rsquo;t just say &ldquo;My app uses <code>widgets</code>.&rdquo; You say, &ldquo;My app uses
-<code>widgets 2.0.5</code>.&rdquo; That combination of name and version number uniquely
-identifies an <em>immutable</em> chunk of code. The people hacking on <code>widgets</code> can
-make all of the changes they want, but they promise to not touch any already
-released versions. They can put out <code>2.0.6</code> or <code>3.0.0</code> and it won&rsquo;t affect you
-one whit because the version you use is unchanged.</p>
-
-<p>When you <em>do</em> want to get those changes, you can always point your app to a
-newer version of <code>widgets</code> and you don&rsquo;t have to coordinate with those
-developers to do it. So, problem solved, right?</p>
-
-<h2 id="shared-dependencies-and-unshared-libraries">Shared dependencies and unshared libraries</h2>
-
-<p>Well, no. Depending on specific versions works fine when your dependency <em>graph</em>
-is really just a dependency <em>tree</em>. If your app depends on a bunch of stuff, and
-those things in turn have their own dependencies and so on, that all works fine
-as long as none of those dependencies <em>overlap</em>.</p>
-
-<p>But let&rsquo;s consider an example:</p>
-
-<pre><code> myapp
- / \
- / \
-widgets templates
- \ /
- \ /
- collections
-</code></pre>
-
-<p>So your app uses <code>widgets</code> and <code>templates</code>, and <em>both</em> of those use
-<code>collections</code>. This is called a <strong>shared dependency</strong>. Now what happens when
-<code>widgets</code> wants to use <code>collections 2.3.5</code> and <code>templates</code> wants
-<code>collections 2.3.7</code>? What if they don&rsquo;t agree on a version?</p>
-
-<p>One option is to just let the app use both
-versions of <code>collections</code>. It will have two copies of the library at different
-versions and <code>widgets</code> and <code>templates</code> will each get the one they want.</p>
-
-<p>This is what <a href="https://npmjs.org/">npm</a> does for node.js. Would it work for Dart? Consider this
-scenario:</p>
-
-<ol>
- <li><code>collections</code> defines some <code>Dictionary</code> class.</li>
- <li><code>widgets</code> gets an instance of it from its copy of <code>collections</code> (<code>2.3.5</code>).
-It then passes it up to <code>myapp</code>.</li>
- <li><code>myapp</code> sends the dictionary over to <code>templates</code>.</li>
- <li>That in turn sends it down to <em>its</em> version of <code>collections</code> (<code>2.3.7</code>).</li>
- <li>The method that takes it has a <code>Dictionary</code> type annotation for that object.</li>
-</ol>
-
-<p>As far as Dart is concerned, <code>collections 2.3.5</code> and <code>collections 2.3.7</code> are
-entirely unrelated libraries. If you take an instance of class <code>Dictionary</code> from
-one and pass it to a method in the other, that&rsquo;s a completely different
-<code>Dictionary</code> type. That means it will fail to match a <code>Dictionary</code> type
-annotation in the receiving library. Oops.</p>
-
-<p>Because of this (and because of the headaches of trying to debug an app that
-has multiple versions of things with the same name), we&rsquo;ve decided npm&rsquo;s model
-isn&rsquo;t a good fit.</p>
-
-<h2 id="version-lock">Version lock</h2>
-
-<p>Instead, when you depend on a package, your app will only use a single copy of
-that package. When you have a shared dependency, everything that depends on it
-has to agree on which version to use. If they don&rsquo;t, you get an error.</p>
-
-<p>That doesn&rsquo;t actually solve your problem though. When you <em>do</em> get that error,
-you need to be able to resolve it. So let&rsquo;s say you&rsquo;ve gotten yourself into
-that situation in the above example. You want to use <code>widgets</code> and <code>templates</code>,
-but they are using different versions of <code>collections</code>. What do you do?</p>
-
-<p>The answer is to try to upgrade one of those. <code>templates</code> wants
-<code>collections 2.3.7</code>. Is there a later version of <code>widgets</code> that you can upgrade
-to that works with that version?</p>
-
-<p>In many cases, the answer will be &ldquo;no&rdquo;. Look at it from the perspective of the
-people developing <code>widgets</code>. They want to put out a new version with new changes
-to <em>their</em> code, and they want as many people to be able to upgrade to it it as
-possible. If they stick to their <em>current</em> version of <code>collections</code> then anyone
-who is using the current version <code>widgets</code> will be able to drop in this new one
-too.</p>
-
-<p>If they were to upgrade <em>their</em> dependency on <code>collections</code> then everyone who
-upgrades <code>widgets</code> would have to as well, <em>whether they want to or not.</em> That&rsquo;s
-painful, so you end up with a disincentive to upgrade dependencies. That&rsquo;s
-called <strong>version lock</strong>: everyone wants to move their dependencies forward, but
-no one can take the first step because it forces everyone else to as well.</p>
-
-<h2 id="version-constraints">Version constraints</h2>
-
-<p>To solve version lock, we loosen the constraints that packages place on their
-dependencies. If <code>widgets</code> and <code>templates</code> can both indicate a <em>range</em> of
-versions for <code>collections</code> that they will work with, then that gives us enough
-wiggle room to move our dependencies forward to newer versions. As long as there
-is overlap in their ranges, we can still find a single version that makes them
-both happy.</p>
-
-<p>This is the model that <a href="http://gembundler.com/">bundler</a> follows, and is pub&rsquo;s
-model too. When you add a dependency in your pubspec, you can specify a <em>range</em>
-of versions that you can accept. If the pubspec for <code>widgets</code> looked like this:</p>
-
-<div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</span>
- <span class="l-Scalar-Plain">collections</span><span class="p-Indicator">:</span> <span class="s">&#39;&gt;=2.3.5</span><span class="nv"> </span><span class="s">&lt;2.4.0&#39;</span>
-</code></pre></div>
-
-<p>Then we could pick version <code>2.3.7</code> for <code>collections</code> and then both <code>widgets</code>
-and <code>templates</code> have their constraints satisfied by a single concrete version.</p>
-
-<h2 id="semantic-versions">Semantic versions</h2>
-
-<p>When you add a dependency to your package, you&rsquo;ll sometimes want to specify a
-range of versions to allow. How do you know what range to pick? You need to
-forward compatible, so ideally the range encompasses future versions that
-haven&rsquo;t been released yet. But how do you know your package is going to work
-with some new version that doesn&rsquo;t even exist yet?</p>
-
-<p>To solve that, you need to agree on what a version number <em>means</em>. Imagine that
-the developers of a package you depend on say, &ldquo;If we make any backwards
-incompatible change, then we promise to increment the major version number.&rdquo;
-If you trust them, then if you know your package works with <code>2.5.7</code> of theirs,
-you can rely on it working all the way up to <code>3.0.0</code>. So you can set your range
-like:</p>
-
-<div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</span>
- <span class="l-Scalar-Plain">collections</span><span class="p-Indicator">:</span> <span class="s">&#39;&gt;=2.3.5</span><span class="nv"> </span><span class="s">&lt;3.0.0&#39;</span>
-</code></pre></div>
-
-<p>To make this work, then, we need to come up with that set of promises.
-Fortunately, other smart people have done the work of figuring this all out and
-named it <a href="http://semver.org/"><em>semantic versioning</em></a>.</p>
-
-<p>That describes the format of a version number, and the exact API behavioral
-differences when you increment to a later version number. Pub requires versions
-to be formatted that way, and to play well with the pub community, your package
-should follow the semantics it specifies. You should assume that the packages
-you depend on also follow it. (And if you find out they don&rsquo;t, let their
-authors know!)</p>
-
-<p>We&rsquo;ve got almost all of the pieces we need to deal with versioning and API
-evolution now. Let&rsquo;s see how they play together and what pub does.</p>
-
-<h2 id="constraint-solving">Constraint solving</h2>
-
-<p>When you define your package, you list its
-<a href="glossary.html#immediate-dependency"><strong>immediate dependencies</strong></a>&mdash;the
-packages it itself uses. For each one, you specify the range of versions it
-allows. Each of those dependent packages may in turn have their own
-dependencies (called
-<a href="glossary.html#transitive-dependency"><strong>transitive dependencies</strong></a>. Pub will
-traverse these and build up the entire deep dependency graph for your app.</p>
-
-<p>For each package in the graph, pub looks at everything that depends on it. It
-gathers together all of their version constraints and tries to simultaneously
-solve them. (Basically, it intersects their ranges.) Then it looks at the
-actual versions that have been released for that package and selects the best
-(most recent) one that meets all of those constraints.</p>
-
-<p>For example, let&rsquo;s say our dependency graph contains <code>collections</code>, and three
-packages depend on it. Their version constraints are:</p>
-
-<pre><code>&gt;=1.7.0
-&gt;=1.4.0 &lt;2.0.0
-&lt;1.9.0
-</code></pre>
-
-<p>The developers of <code>collections</code> have released these versions of it:</p>
-
-<pre><code>1.7.0
-1.7.1
-1.8.0
-1.8.1
-1.8.2
-1.9.0
-</code></pre>
-
-<p>The highest version number that fits in all of those ranges is <code>1.8.2</code>, so pub
-picks that. That means your app <em>and every package your app uses</em> will all use
-<code>collections 1.8.2</code>.</p>
-
-<h2 id="constraint-context">Constraint context</h2>
-
-<p>The fact that selecting a package version takes into account <em>every</em> package
-that depends on it has an important consequence: <em>the specific version that
-will be selected for a package is a global property of the app using that
-package.</em></p>
-
-<p>I&rsquo;ll walk through an example so you can see what this means. Let&rsquo;s say we have
-two apps. Here are their pubspecs:</p>
-
-<div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">my_app</span>
-<span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</span>
- <span class="l-Scalar-Plain">widgets</span><span class="p-Indicator">:</span>
-</code></pre></div>
-
-<div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">other_app</span>
-<span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</span>
- <span class="l-Scalar-Plain">widgets</span><span class="p-Indicator">:</span>
- <span class="l-Scalar-Plain">collections</span><span class="p-Indicator">:</span> <span class="s">&#39;&lt;1.5.0&#39;</span>
-</code></pre></div>
-
-<p>They both depend on <code>widgets</code>, whose pubspec is:</p>
-
-<div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">widgets</span>
-<span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</span>
- <span class="l-Scalar-Plain">collections</span><span class="p-Indicator">:</span> <span class="s">&#39;&gt;=1.0.0</span><span class="nv"> </span><span class="s">&lt;2.0.0&#39;</span>
-</code></pre></div>
-
-<p>The <code>other_app</code> package uses depends directly on <code>collections</code> itself. The
-interesting part is that it happens to have a different version constraint on
-it than <code>widgets</code> does.</p>
-
-<p>What this means is that you can&rsquo;t just look at the <code>widgets</code> package in
-isolation to figure out what version of <code>collections</code> it will use. It depends
-on the context. In <code>my_app</code>, <code>widgets</code> will be using <code>collections 1.9.9</code>. But
-in <code>other_app</code>, <code>widgets</code> will get saddled with <code>collections 1.4.9</code> because of
-the <em>other</em> constraint that <code>otherapp</code> places on it.</p>
-
-<p>This is why each app gets its own &ldquo;packages&rdquo; directory: The concrete version
-selected for each package depends on the entire dependency graph of the
-containing app.</p>
-
-<h2 id="lockfiles">Lockfiles</h2>
-
-<p>So once pub has solved your app&rsquo;s version constraints, then what? The end
-result is a complete list of every package that your app depends on either
-directly or indirectly and the best version of that package that will work with
-your app&rsquo;s constraints.</p>
-
-<p>Pub takes that and writes it out to a <strong>lockfile</strong> in your app&rsquo;s directory
-called <code>pubspec.lock</code>. When pub builds the &ldquo;packages&rdquo; directory your app, it
-uses the lockfile to know what versions of each package to pull in. (And if
-you&rsquo;re curious to see what versions it selected, you can read the lockfile to
-find out.)</p>
-
-<p>The next important thing pub does is it <em>stops touching the lockfile</em>. Once
-you&rsquo;ve got a lockfile for your app, pub won&rsquo;t mess with it until you tell it to.
-This is important. It means you won&rsquo;t spontanteously start using new versions
-of random packages in your app without intending to. Once your app is locked,
-it stays locked until you manually tell it to update the lockfile.</p>
-
-<p>If your package is for an app, you take your lockfile <em>check that bad boy
-into your source control system!</em> That way, everyone on your team will be using
-the exact same versions of every dependency when they hack on your app. You&rsquo;ll
-also use this when you deploy your app so you can ensure that your production
-servers are using the exact same packages that you&rsquo;re developing with.</p>
-
-<h2 id="when-things-go-wrong">When things go wrong</h2>
-
-<p>Of course, all of this presumes that your dependency graph is perfect and
-flawless. Oh, to be so fortunate. Even with version ranges and pub&rsquo;s constraint
-solving and semantic versioning, you can never be entirely spared from the
-dangers of version hell.</p>
-
-<p>There are a couple of problems you can run into:</p>
-
-<h3 id="you-can-have-disjoint-constraints">You can have disjoint constraints</h3>
-
-<p>Lets say your app uses <code>widgets</code> and
-<code>templates</code> and both use <code>collections</code>. But <code>widgets</code> asks for a version
-of it between <code>1.0.0</code> and <code>2.0.0</code> and <code>templates</code> wants something
-between <code>3.0.0</code> and <code>4.0.0</code>. Those ranges don&rsquo;t even overlap. There&rsquo;s no
-possible version that would work.</p>
-
-<h3 id="you-can-have-ranges-that-dont-contain-a-released-version">You can have ranges that don&rsquo;t contain a released version</h3>
-
-<p>Let&rsquo;s say after
-putting all of the constraints on a shared dependency together, you&rsquo;re
-left with the narrow range of <code>&gt;=1.2.4 &lt;1.2.6</code>. It&rsquo;s not an empty range.
-If there was a version <code>1.2.4</code> of the dependency, you&rsquo;d be golden. But maybe
-they never released that and instead when straight from <code>1.2.3</code> to <code>1.3.0</code>.
-You&rsquo;ve got a range but nothing exists inside it.</p>
-
-<h3 id="you-can-have-an-unstable-graph">You can have an unstable graph</h3>
-
-<p>This is, by far, the hairiest part of
-pub&rsquo;s version solving process. I&rsquo;ve described the process as &ldquo;build up the
-dependency graph and then solve all of the constraints and pick versions&rdquo;.
-But it doesn&rsquo;t actually work that way. How could you build up the <em>whole</em>
-dependency graph before you&rsquo;ve picked <em>any</em> versions? <em>The pubspecs
-themselves are version-specific</em>. Different versions of the same package
-may have different sets of dependencies.</p>
-
-<p>As you&rsquo;re selecting versions of packages, they are changing the shape of
-the dependency graph itself. As the graph changes, that may change
-constraints, which can cause you to select different versions, and then you
-go right back around in a circle.</p>
-
-<p>Sometimes this process never settles down into a stable solution. Gaze into
-the abyss:</p>
-
-<div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">my_app</span>
-<span class="l-Scalar-Plain">version</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">0.0.0</span>
-<span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</span>
- <span class="l-Scalar-Plain">yin</span><span class="p-Indicator">:</span> <span class="s">&#39;&gt;=1.0.0&#39;</span>
-</code></pre></div>
-
-<div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">yin</span>
-<span class="l-Scalar-Plain">version</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">1.0.0</span>
-<span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</span>
-</code></pre></div>
-
-<div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">yin</span>
-<span class="l-Scalar-Plain">version</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">2.0.0</span>
-<span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</span>
- <span class="l-Scalar-Plain">yang</span><span class="p-Indicator">:</span> <span class="s">&#39;1.0.0&#39;</span>
-</code></pre></div>
-
-<div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">yang</span>
-<span class="l-Scalar-Plain">version</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">1.0.0</span>
-<span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</span>
- <span class="l-Scalar-Plain">yin</span><span class="p-Indicator">:</span> <span class="s">&#39;1.0.0&#39;</span>
-</code></pre></div>
-
-<p>In all of these cases, there is no set of concrete versions that will work for
-your app, and when this happens pub will report an error and tell you what&rsquo;s
-going on. It definitely will not try to leave you in some weird state where you
-think things can work but won&rsquo;t.</p>
-
-<h2 id="summary">Summary</h2>
-
-<p>Wow, that&rsquo;s a lot to get through. Here&rsquo;s the important bits:</p>
-
-<ul>
- <li>Code reuse is great, but in order to let developers move quickly, packages
-need to be able to evolve independently.</li>
- <li>Versioning is how you enable that. But depending on single concrete versions
-is too precise and with shared dependencies leads to version lock.</li>
- <li>To cope with that, you depend on <em>ranges</em> of versions. Pub will then walk
-your dependency graph and pick the best versions for you. If it can&rsquo;t, it
-tells you.</li>
- <li>Once your app has a solid set of versions for its dependencies, that gets
-pinned down in a <em>lockfile</em>. That ensures that every machine your app is
-on is using the same versions of all of its dependencies.</li>
-</ul>
« no previous file with comments | « app/views/doc/pubspec.html ('k') | app/views/index.mustache » ('j') | app/views/index.mustache » ('J')

Powered by Google App Engine
This is Rietveld 408576698