aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/tdewolff/minify/benchmarks/sample_blogpost.html
blob: f0b977fb802580cf0198bea8a42707d3e1d62b1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
<!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 doesn’t need it;
responding only to the most common or recent complaints or requests;
or focusing too much on short-term improvements.
It’s important to step back and make sure we’re 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 team’s 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 I’m 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 didn’t work for at least two reasons: we didn’t explain the change well enough,
and we didn’t deliver it on time, so it wasn’t 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 command’s 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 doesn’t cache build results as aggressively as it should.
Many people don’t 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:
you’ll 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 didn’t 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 don’t 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>Go’s <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 Go’s 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 don’t think that will happen this year,
but I’d 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 I’d 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 don’t 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>We’ve <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>It’s 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 don’t think generics will happen this year,
but I’d 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>