miniflux/vendor/github.com/tdewolff/minify/benchmarks/sample_blogpost.html

581 lines
20 KiB
HTML
Raw Normal View History

2017-11-20 06:10:04 +01:00
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>research!rsc: My Go Resolutions for 2017</title>
<link rel="alternate" type="application/atom+xml" title="research!rsc - Atom" href="http://research.swtch.com/feed.atom" />
<link href='https://fonts.googleapis.com/css?family=Inconsolata:400,700' rel='stylesheet' type='text/css'>
<script type="text/javascript" src="https://use.typekit.com/skm6yij.js"></script>
<script type="text/javascript">try{Typekit.load();}catch(e){}</script>
<style>
body {
padding: 0;
margin: 0;
font-size: 100%;
}
.header {
height: 1.25em;
background-color: #dff;
margin: 0;
padding: 0.1em 0.1em 0.2em;
border-top: 1px solid black;
border-bottom: 1px solid #8ff;
}
.header h3 {
margin: 0;
padding: 0 2em;
display: inline-block;
padding-right: 2em;
font-style: italic;
font-family: "adobe-text-pro" !important;
font-size: 90%;
}
.rss {
float: right;
padding-top: 0.2em;
padding-right: 2em;
display: none;
}
.toc {
margin-top: 2em;
}
.toc-title {
font-family: "caflisch-script-pro";
font-size: 300%;
line-height: 50%;
}
.toc-subtitle {
display: block;
margin-bottom: 1em;
font-size: 83%;
}
@media only screen and (max-width: 550px) { .toc-subtitle { display: none; } }
.header h3 a {
color: black;
}
.header h4 {
margin: 0;
padding: 0;
display: inline-block;
font-weight: normal;
font-size: 83%;
}
@media only screen and (max-width: 550px) { .header h4 { display: none; } }
.main {
padding: 0 2em;
}
@media only screen and (max-width: 479px) { .article { font-size: 120%; } }
.article h1 {
text-align: center;
}
.article h1, .article h2, .article h3 {
font-family: 'Myriad Pro';
}
.normal {
font-size: medium;
font-weight: normal;
}
.when {
text-align: center;
font-size: 100%;
margin: 0;
padding: 0;
}
.when p {
margin: 0;
padding: 0;
}
.article h2 {
font-size: 100%;
padding-top: 0.25em;
}
pre {
margin-left: 4em;
margin-right: 4em;
}
pre, code {
font-family: 'Inconsolata', monospace;
font-size: 100%;
}
.footer {
margin-top: 10px;
font-size: 83%;
font-family: sans-serif;
}
.comments {
margin-top: 2em;
background-color: #ffe;
border-top: 1px solid #aa4;
border-left: 1px solid #aa4;
border-right: 1px solid #aa4;
}
.comments-header {
padding: 0 5px 0 5px;
}
.comments-header p {
padding: 0;
margin: 3px 0 0 0;
}
.comments-body {
padding: 5px 5px 5px 5px;
}
#plus-comments {
border-bottom: 1px dotted #ccc;
}
.plus-comment {
width: 100%;
font-size: 14px;
border-top: 1px dotted #ccc;
}
.me {
background-color: #eec;
}
.plus-comment ul {
margin: 0;
padding: 0;
list-style: none;
width: 100%;
display: inline-block;
}
.comment-when {
color:#999;
width:auto;
padding:0 5px;
}
.old {
font-size: 83%;
}
.plus-comment ul li {
display: inline-block;
vertical-align: top;
margin-top: 5px;
margin-bottom: 5px;
padding: 0;
}
.plus-icon {
width: 45px;
}
.plus-img {
float: left;
margin: 4px 4px 4px 4px;
width: 32px;
height: 32px;
}
.plus-comment p {
margin: 0;
padding: 0;
}
.plus-clear {
clear: left;
}
.toc-when {
font-size: 83%;
color: #ccc;
}
.toc {
list-style: none;
}
.toc li {
margin-bottom: 0.5em;
}
.toc-head {
margin-bottom: 1em !important;
font-size: 117%;
}
.toc-summary {
margin-left: 2em;
}
.favorite {
font-weight: bold;
}
.article p {
line-height: 144%;
}
sup, sub {
vertical-align: baseline;
position: relative;
font-size: 83%;
}
sup {
bottom: 1ex;
}
sub {
top: 0.8ex;
}
.main {
position: relative;
margin: 0 auto;
padding: 0;
width: 900px;
}
@media only screen and (min-width: 768px) and (max-width: 959px) { .main { width: 708px; } }
@media only screen and (min-width: 640px) and (max-width: 767px) { .main { width: 580px; } }
@media only screen and (min-width: 480px) and (max-width: 639px) { .main { width: 420px; } }
@media only screen and (max-width: 479px) { .main { width: 300px; } }
</style>
</head>
<body>
<div class="header">
<h3><a href="/">research!rsc</a></h3>
<h4>Thoughts and links about programming,
by <a href="https://swtch.com/~rsc/" rel="author">Russ Cox</a> </h4>
<a class="rss" href="/feed.atom"><img src="/feed-icon-14x14.png" /></a>
</div>
<div class="main">
<div class="article">
<h1>My Go Resolutions for 2017
<div class="normal">
<div class="when">
Posted on Wednesday, January 18, 2017.
</div>
</div>
</h1>
<p class=lp>Tis the season for resolutions,
and I thought it would make sense to write a little
about what I hope to work on this year as far as Go is concerned.</p>
<p class=pp>My goal every year is to <em>help Go developers</em>.
I want to make sure that the work we do on the Go team
has a significant, positive impact on Go developers.
That may sound obvious, but there are a variety of common ways to fail to achieve that:
for example, spending too much time cleaning up or optimizing code that doesnt need it;
responding only to the most common or recent complaints or requests;
or focusing too much on short-term improvements.
Its important to step back and make sure were focusing
our development work where it does the most good.</p>
<p class=pp>This post outlines a few of my own major focuses for this year.
This is only my personal list, not the Go teams list.</p>
<p class=pp>One reason for posting this is to gather feedback.
If these spark any ideas or suggestions of your own,
please feel free to comment below or on the linked GitHub issues.</p>
<p class=pp>Another reason is to make clear that Im aware of these issues as important.
I think too often people interpret lack of action by the Go team
as a signal that we think everything is perfect, when instead
there is simply other, higher priority work to do first.</p>
<h2><a name="alias"></a>Type aliases</h2>
<p class=lp>There is a recurring problem with moving types
from one package to another during large codebase refactorings.
We tried to solve it last year with <a href="https://golang.org/issue/16339">general aliases</a>,
which didnt work for at least two reasons: we didnt explain the change well enough,
and we didnt deliver it on time, so it wasnt ready for Go 1.8.
Learning from that experience,
I <a href="https://www.youtube.com/watch?v=h6Cw9iCDVcU">gave a talk</a>
and <a href="https://talks.golang.org/2016/refactor.article">wrote an article</a>
about the underlying problem,
and that started a <a href="https://golang.org/issue/18130">productive discussion</a>
on the Go issue tracker about the solution space.
It looks like more limited <a href="https://golang.org/design/18130-type-alias">type aliases</a>
are the right next step.
I want to make sure those land smoothly in Go 1.9. <a href="https://golang.org/issue/18130">#18130</a>.</p>
<h2><a name="package"></a>Package management</h2>
<p class=lp>I designed the Go support for downloading published packages
(“goinstall”, which became “go get”) in February 2010.
A lot has happened since then.
In particular, other language ecosystems have really raised the bar
for what people expect from package management,
and the open source world has mostly agreed on
<a href="http://semver.org/">semantic versioning</a>, which provides a useful base
for inferring version compatibility.
Go needs to do better here, and a group of contributors have been
<a href="https://blog.gopheracademy.com/advent-2016/saga-go-dependency-management/">working on a solution</a>.
I want to make sure these ideas are integrated well
into the standard Go toolchain and to make package management
a reason that people love Go.</p>
<h2><a name="build"></a>Build improvements</h2>
<p class=lp>There are a handful of shortcomings in the design of
the go commands build system that are overdue to be fixed.
Here are three representative examples that I intend to
address with a bit of a redesign of the internals of the go command.</p>
<p class=pp>Builds can be too slow,
because the go command doesnt cache build results as aggressively as it should.
Many people dont realize that <code>go</code> <code>install</code> saves its work while <code>go</code> <code>build</code> does not,
and then they run repeated <code>go</code> <code>build</code> commands that are slow
because the later builds do more work than they should need to.
The same for repeated <code>go</code> <code>test</code> without <code>go</code> <code>test</code> <code>-i</code> when dependencies are modified.
All builds should be as incremental as possible.
<a href="https://golang.org/issue/4719">#4719</a>.</p>
<p class=pp>Test results should be cached too:
if none of the inputs to a test have changed,
then usually there is no need to rerun the test.
This will make it very cheap to run “all tests” when little or nothing has changed.
<a href="https://golang.org/issue/11193">#11193</a>.</p>
<p class=pp>Work outside GOPATH should be supported nearly as well
as work inside GOPATH.
In particular, it should be possible to <code>git</code> <code>clone</code> a repo,
<code>cd</code> into it, and run <code>go</code> commands and have them work fine.
Package management only makes that more important:
youll need to be able to work on different versions of a package (say, v1 and v2)
without having entirely separate GOPATHs for them.
<a href="https://golang.org/issue/17271">#17271</a>.</p>
<h2><a name="corpus"></a>Code corpus</h2>
<p class=lp>I think it helped to have concrete examples from real projects
in the talk and article I prepared about codebase refactoring (see <a href="#alias">above</a>).
We&rsquo;ve also defined that <a href="https://golang.org/src/cmd/vet/README">additions to vet</a>
must target problems that happen frequently in real programs.
I&rsquo;d like to see that kind of analysis of actual practice—examining
the effects on and possible improvements to real programs—become a
standard way we discuss and evaluate changes to Go.</p>
<p class=pp>Right now there&rsquo;s not an agreed-upon representative corpus of code to use for
those analyses: everyone must first create their own, which is too much work.
I&rsquo;d like to put together a single, self-contained Git repo people can check out that
contains our official baseline corpus for those analyses.
A possible starting point could be the top 100 Go language repos
on GitHub by stars or forks or both.</p>
<h2><a name="vet"></a>Automatic vet</h2>
<p class=lp>The Go distribution ships with this powerful tool,
<a href="https://golang.org/cmd/vet/"><code>go</code> <code>vet</code></a>,
that points out correctness bugs.
We have a high bar for checks, so that when vet speaks, you should listen.
But everyone has to remember to run it.
It would be better if you didnt have to remember.
In particular, I think we could probably run vet
in parallel with the final compile and link of the test binary
during <code>go</code> <code>test</code> without slowing the compile-edit-test cycle at all.
If we can do that, and if we limit the enabled vet checks to a subset
that is essentially 100% accurate,
we can make passing vet a precondition for running a test at all.
Then developers dont need to remember to run <code>go</code> <code>vet</code>.
They run <code>go</code> <code>test</code>,
and once in a while vet speaks up with something important
and avoids a debugging session.
<a href="https://golang.org/issue/18084">#18084</a>,
<a href="https://golang.org/issue/18085">#18085</a>.</p>
<h2><a name="error"></a>Errors &amp; best practices</h2>
<p class=lp>Part of the intended contract for error reporting in Go is that functions
include relevant available context, including the operation being attempted
(such as the function name and its arguments).
For example, this program:</p>
<pre><code>err := os.Remove(&quot;/tmp/nonexist&quot;)
fmt.Println(err)
</code></pre>
<p class=lp>prints this output:</p>
<pre><code>remove /tmp/nonexist: no such file or directory
</code></pre>
<p class=lp>Not enough Go code adds context like <code>os.Remove</code> does. Too much code does only</p>
<pre><code>if err != nil {
return err
}
</code></pre>
<p class=lp>all the way up the call stack,
discarding useful context that should be reported
(like <code>remove</code> <code>/tmp/nonexist:</code> above).
I would like to try to understand whether our expectations
for including context are wrong, or if there is something
we can do to make it easier to write code that returns better errors.</p>
<p class=pp>There are also various discussions in the community about
agreed-upon interfaces for stripping error context.
I would like to try to understand when that makes sense and
whether we should adopt an official recommendation.</p>
<h2><a name="context"></a>Context &amp; best practices</h2>
<p class=lp>We added the new <a href="https://golang.org/pkg/context/">context package</a>
in Go 1.7 for holding request-scoped information like
<a href="https://blog.golang.org/context">timeouts, cancellation state, and credentials</a>.
An individual context is immutable (like an individual string or int):
it is only possible to derive a new, updated context and
pass that context explicitly further down the call stack or
(less commonly) back up to the caller.
The context is now carried through APIs such as
<a href="https://golang.org/pkg/database/sql">database/sql</a>
and
<a href="https://golang.org/pkg/net/http">net/http</a>,
mainly so that those can stop processing a request when the caller
is no longer interested in the result.
Timeout information is appropriate to carry in a context,
but—to use a <a href="https://golang.org/issue/18284">real example we removed</a>—database options
are not, because they are unlikely to apply equally well to all possible
database operations carried out during a request.
What about the current clock source, or logging sink?
Is either of those appropriate to store in a context?
I would like to try to understand and characterize the
criteria for what is and is not an appropriate use of context.</p>
<h2><a name="memory"></a>Memory model</h2>
<p class=lp>Gos <a href="https://golang.org/ref/mem">memory model</a> is intentionally low-key,
making few promises to users, compared to other languages.
In fact it starts by discouraging people from reading the rest of the document.
At the same time, it demands more of the compiler than other languages:
in particular, a race on an integer value is not sufficient license
for your program to misbehave in arbitrary ways.
But there are some complete gaps, in particular no mention of
the <a href="https://golang.org/pkg/sync/atomic/">sync/atomic package</a>.
I think the core compiler and runtime developers all agree
that the behavior of those atomics should be roughly the same as
C++ seqcst atomics or Java volatiles,
but we still need to write that down carefully in the memory model,
and probably also in a long blog post.
<a href="https://golang.org/issue/5045">#5045</a>,
<a href="https://golang.org/issue/7948">#7948</a>,
<a href="https://golang.org/issue/9442">#9442</a>.</p>
<h2><a name="immutability"></a>Immutability</h2>
<p class=lp>The <a href="https://golang.org/doc/articles/race_detector.html">race detector</a>
is one of Gos most loved features.
But not having races would be even better.
I would love it if there were some reasonable way to integrate
<a href="https://www.google.com/search?q=%22reference+immutability%22">reference immutability</a> into Go,
so that programmers can make clear, checked assertions about what can and cannot
be written and thereby eliminate certain races at compile time.
Go already has one immutable type, <code>string</code>; it would
be nice to retroactively define that
<code>string</code> is a named type (or type alias) for <code>immutable</code> <code>[]byte</code>.
I dont think that will happen this year,
but Id like to understand the solution space better.
Javari, Midori, Pony, and Rust have all staked out interesting points
in the solution space, and there are plenty of research papers
beyond those.</p>
<p class=pp>In the long-term, if we could statically eliminate the possibility of races,
that would eliminate the need for most of the memory model.
That may well be an impossible dream,
but again Id like to understand the solution space better.</p>
<h2><a name="generics"></a>Generics</h2>
<p class=lp>Nothing sparks more <a href="https://research.swtch.com/dogma">heated arguments</a>
among Go and non-Go developers than the question of whether Go should
have support for generics (or how many years ago that should have happened).
I dont believe the Go team has ever said “Go does not need generics.”
What we <em>have</em> said is that there are higher-priority issues facing Go.
For example, I believe that better support for package management
would have a much larger immediate positive impact on most Go developers
than adding generics.
But we do certainly understand that for a certain subset of Go use cases,
the lack of parametric polymorphism is a significant hindrance.</p>
<p class=pp>Personally, I would like to be able to write general channel-processing
functions like:</p>
<pre><code>// Join makes all messages received on the input channels
// available for receiving from the returned channel.
func Join(inputs ...&lt;-chan T) &lt;-chan T
// Dup duplicates messages received on c to both c1 and c2.
func Dup(c &lt;-chan T) (c1, c2 &lt;-chan T)
</code></pre>
<p class=lp>I would also like to be able to write
Go support for high-level data processing abstractions,
analogous to
<a href="https://research.google.com/pubs/archive/35650.pdf">FlumeJava</a> or
C#s <a href="https://en.wikipedia.org/wiki/Language_Integrated_Query">LINQ</a>,
in a way that catches type errors at compile time instead of at run time.
There are also any number of data structures or generic algorithms
that might be written,
but I personally find these broader applications more compelling.</p>
<p class=pp>Weve <a href="https://research.swtch.com/generic">struggled</a> off and on
<a href="https://golang.org/design/15292-generics">for years</a>
to find the right way to add generics to Go.
At least a few of the past proposals got hung up on trying to design
something that provided both general parametric polymorphism
(like <code>chan</code> <code>T</code>) and also a unification of <code>string</code> and <code>[]byte</code>.
If the latter is handled by parameterization over immutability,
as described in the previous section, then maybe that simplifies
the demands on a design for generics.</p>
<p class=pp>When I first started thinking about generics for Go in 2008,
the main examples to learn from were C#, Java, Haskell, and ML.
None of the approaches in those languages seemed like a
perfect fit for Go.
Today, there are newer attempts to learn from as well,
including Dart, Midori, Rust, and Swift.</p>
<p class=pp>Its been a few years since we ventured out and explored the design space.
It is probably time to look around again,
especially in light of the insight about mutability and
the additional examples set by newer languages.
I dont think generics will happen this year,
but Id like to be able to say I understand the solution space better.</p>
</div>
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
this.page.url = "https://research.swtch.com/go2017";
this.page.identifier = "blog/go2017";
};
(function() {
var d = document, s = d.createElement('script');
s.src = '//swtch.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-3319603-2");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>