Text file
talks/2015/how-go-was-made.slide
1 How Go was made
2 GopherCon Closing Keynote
3 9 Jul 2015
4
5 Andrew Gerrand
6 adg@golang.org
7
8
9 * Video
10
11 A video of this talk was recorded at GopherCon in Denver.
12
13 .link https://www.youtube.com/watch?v=0ht89TxZZnk Watch the talk on YouTube
14
15
16 * This talk
17
18 How was Go made?
19
20 What was its development process?
21
22 How has the process changed?
23
24 What is its future?
25
26 .image how-go-was-made/gopherswrench.jpg 300 _
27
28
29 * The early days
30
31
32 * Three friends
33
34 Robert Griesemer, Rob Pike, and Ken Thompson's thought experiment:
35
36 "What should a modern, practical programming language look like?"
37
38
39 * The early process
40
41 Design discussions by mail and in-person.
42
43 Consensus-driven:
44 A feature was accepted only when *all* the three authors agreed it necessary.
45
46 Most proposed changes were rejected.
47
48
49 * The initial spec
50
51 The first artifact of Go was the language specification.
52
53 The first commit (now git hash `18c5b48`) was a draft of that spec:
54
55 Author: Robert Griesemer <gri@golang.org>
56 Date: Sun Mar 2 20:47:34 2008 -0800
57
58 Go spec starting point.
59
60 Go's entire history is preserved in the core reposistory.
61
62
63 * The first Go program
64
65 The first Go program was a Prime Sieve, and was included in the spec.
66
67 func Filter(in *chan< int, out *chan> int, prime int) {
68 for {
69 i := <in; // Receive value of new variable 'i' from 'in'.
70 if i % prime != 0 {
71 >out = i // Send 'i' to channel 'out'.
72 }
73 }
74 }
75
76 func Sieve() {
77 ch := new(chan int); // Create a new channel.
78 go Generate(ch); // Start Generate() as a subprocess.
79 for {
80 prime := <ch;
81 printf("%d\n", prime);
82 ch1 := new(chan int);
83 go Filter(ch, ch1, prime);
84 ch = ch1
85 }
86 }
87
88
89 * Version control
90
91 Subversion was the project's first version control system. (no code review!)
92 The trio made 400 commits to Subversion.
93
94 The last Subversion commit (git hash `777ee7`, 21 July 2008) contained:
95
96 - the spec,
97 - a Go compiler (linux/darwin amd64),
98 - a few packages (fmt, rand, and math),
99 - some test programs.
100
101 `test/helloworld.go`:
102
103 package main
104
105 func main() {
106 print "hello, world\n";
107 }
108
109
110 * Getting serious
111
112 In July 2008 the project migrated from Subversion to Perforce,
113 to use Google's excellent code review system.
114
115 The team grew:
116
117 - Russ Cox joined in August 2008,
118 - Ian Lance Taylor joined in September,
119 - ~20 other Googlers got involved in their 20% time.
120
121
122 * Early changes
123
124 It was easy to make changes in those days.
125 Everyone knew each other.
126 There were ~0 users.
127 All the source code in one place.
128
129 Workflow informal, but design-oriented.
130
131
132 * Waiting for good design (1/2)
133
134 Many problems don't have obvious solutions.
135
136 The team were prepared to wait until they found the correct design.
137
138 For example:
139
140 The `fmt` package was written long before `reflect`.
141 Before then, `fmt` had an awkward chaining API:
142
143 fmt.New().s("i = ").d(i).putnl()
144
145 Now:
146
147 fmt.Println("i = ", i)
148
149
150 * Waiting for good design (2/2)
151
152 Another example:
153
154 Slices took more than a year to figure out.
155 Before then, there were "open arrays" but they were awkward.
156
157 `src/lib/container/vector.go` @ `f4dcf51`:
158
159 // BUG: workaround for non-constant allocation.
160 // i must be a power of 10.
161 func Alloc(i int) *[]Element {
162 switch i {
163 case 1:
164 return new([1]Element);
165 case 10:
166 return new([10]Element);
167 case 100:
168 return new([100]Element);
169 case 1000:
170 return new([1000]Element);
171 }
172 print "bad size ", i, "\n";
173 panic "not known size\n";
174 }
175
176
177 * An early language change
178
179 `chan` and `map` were originally spelled `*chan` and `*map`.
180
181 The team had a meeting to discuss removing the asterisks.
182
183 Russ implemented the compiler change (`dc7b2e9`),
184 and updated ~every Go file in existence (`08ca30b`).
185
186 .code how-go-was-made/mapchan.diff
187
188 This rapid approach works well at a small scale.
189
190
191 * Toward open source
192
193 In mid-2009 the team prepared for the open source release.
194
195 Moved to their third version control system:
196 Mercurial, with Rietveld for code review.
197 # (We would go on to use these tools for five years.)
198
199 The last Perforce commit (`9e96f25`, Oct 29) contained
200
201 - a mature spec and compiler,
202 - a broad standard library (82 packages),
203 - gofmt, godoc, cgo,
204 - the testing framework,
205 - the FAQ, Effective Go, and more.
206
207
208 * Open source
209
210
211 * The release
212
213 10 November 2009: Go was released. (`78c47c3`)
214
215 .image how-go-was-made/website.png 500 _
216
217
218 * The response
219
220 There was a huge response to the release. The team was overwhelmed.
221
222 People sent changes from day one. The first non-Googler change:
223
224 commit 022e3ae2659491e519d392e266acd86223a510f4
225 Author: Kevin Ballard <kevin@sb.org>
226 Date: Tue Nov 10 20:04:14 2009 -0800
227
228 Fix go-mode.el to work on empty buffers
229
230 Fixes #8.
231
232 R=agl, agl1, rsc
233 https://golang.org/cl/153056
234
235 In the first month, 32 people from outside Google contributed to Go.
236
237 The contribution process worked.
238
239
240 * Changes after the release
241
242 The team continued to make big changes after the release.
243
244 But the process was now different, as they now had a community.
245
246
247 * The first major public change (1/2)
248
249 On December 9th, Rob Pike sent the first public change proposal.
250
251 He proposed to remove semicolons at line endings.
252 [[/s/semicolon-proposal][go.dev/s/semicolon-proposal]]
253
254 The proposal was a "design doc" that included:
255
256 - background,
257 - rationale,
258 - a formal specification of the change,
259 - an implementation plan, and
260 - examples (including a copy of the Prime Sieve program without semicolons).
261
262
263 * The first major public change (2/2)
264
265 The design doc was shared with the community for feedback.
266
267 "Please read the proposal and think about its consequences.
268 We're pretty sure it makes the language nicer to use and sacrifices almost nothing in precision or safety."
269
270 The response was positive.
271
272 The proposal was implemented.
273
274 Most of the changes were made mechanically (thanks `gofmt`)).
275
276 This would be the shape of things to come.
277
278
279 * Curating change
280
281 * Curating change
282
283 The team was careful to curate the changes that made it into the language.
284 (Remember: "Wait for good design.")
285
286 There were many proposed changes and additions to Go.
287
288 As before, many more were declined than accepted.
289
290 Some fit with the project's goals, others did not.
291
292 An early accepted proposal:
293
294 - Make the upper and lower bounds of slice operations optional. (`x[lo:]`, `x[:hi]`)
295
296 And a declined proposal:
297
298 - Allow negative indices in slice operations. (`x[-n]` `==` `x[len(x)-n]`)
299
300
301 * Communicating goals
302
303 At first, we did a poor job explaining the project's goals and development process.
304
305 This caused frustration. ("Why don't they accept my suggestions?")
306
307 It took us a while to articulate it:
308 Rob Pike's [[/talks/2012/splash.article][talk]] in October 2012
309 "Go at Google: Language Design in the Service of Software Engineering"
310 was the first thorough explanation of Go's _raison_d'ĂȘtre_.
311
312 I wish we'd had this document written in 2009.
313 (But we couldn't have written it then.)
314
315 Read it, if you haven't already.
316
317
318 * A thought on openness
319
320 What if Go has been open source from day one?
321
322 It may have been easier for the public to understand the project.
323
324 But it's not that simple:
325
326 Ideas are fragile in their early stages; they need to be nurtured before exposed to the world.
327
328
329 * Managing change
330
331 * Weekly snapshots
332
333 Attempt to keep everyone in sync.
334
335 - Apply a Mercurial tag to a specific, stable revision.
336 - Announce to user mailing list with detailed changelog.
337
338 Great for early adopters and core developers.
339
340
341 * Problems with weeklies
342
343 Contributors work at tip; users sync to weeklies.
344
345 Burden on users:
346
347 - annoying to update weekly,
348 - painful to update less often.
349
350 Version skew results because users are at different weeklies.
351
352 Skew fragments the community and slows adoption.
353
354
355 * Formal release process
356
357 March 2011: introduced releases every 1-2 months.
358
359 - Pick the most stable of the past few snapshots and tag it.
360 - Announce with abridged "must read" release notes.
361
362 Keeps the community more in sync. Reduces churn.
363
364 Popular with users.
365
366 But skew still prevalent: adventurers and core devs still use weeklies (or tip!).
367
368
369 * Introducing Gofix
370
371 A tool to mechanically update code to accommodate language and library changes.
372
373 gofix prog.go
374
375 Announced in May 2011.
376
377 Eases the burden of staying current.
378 Release notes now mostly say "run gofix."
379
380 Not a sed script. Works on the AST.
381
382
383 * A gofix example
384
385 The `reflect` API was completely redesigned in 2011.
386 Gofix made most of the changes:
387
388 .image how-go-was-made/reflect1.png _ 1000
389 .image how-go-was-made/reflect3.png _ 1000
390 .image how-go-was-made/reflect2.png _ 1000
391
392
393 * Versioning issues persist
394
395 Gofix is no panacea.
396
397 As the root of the dependency graph, a programming language can suffer acutely from version skew.
398
399 The fundamental issue remains:
400 Code you write today may not compile tomorrow.
401
402 Some companies unwilling to bet on Go as they saw it as unstable.
403
404
405 * A need for stability
406
407 Gofix makes changes very easy, and also makes it easy to experiment.
408 But it can't do everything.
409
410 Priorities: If change is easy, what change is important?
411
412 Wanted to make major changes to the language and libraries,
413 but this requires planning.
414
415 Decision: design and implement a stable version of Go, its libraries, and its tools.
416
417
418 * Go 1
419
420 * What is Go 1?
421
422 A specification of the language and libraries that will be supported for years.
423
424 Available as downloadable binary packages.
425
426 An opportunity to:
427
428 - fix minor language irritations,
429 - fix inconsistencies in the standard library,
430 - focus on bug fixing and cleaning up TODOs,
431 - design and build a strong build tool set (get rid of make),
432 - bring Windows support up to par.
433
434 Polish and refine, not redesign.
435
436
437 * Planning Go 1
438
439 The team at Google prepared a detailed design document.
440
441 Implemented (but did not commit) many of the proposed changes.
442
443 Met for a week to discuss and refine the document (October 2011).
444
445 Presented the document to the community for discussion.
446
447 Community feedback essential in refining the document.
448
449 .link /blog/preview-of-go-version-1 go.dev/blog/preview-of-go-version-1
450
451
452 * An example: errors (1/5)
453
454 Before Go 1, there was no error type.
455 Instead, the `os` package provided an `Error` type:
456
457 package os
458
459 type Error interface {
460 String() string
461 }
462
463 References to `os.Error` were ubiquitous.
464
465 package io
466
467 type Reader interface {
468 Read(p []byte) (n int, err os.Error)
469 }
470
471 type Closer interface {
472 Close() os.Error
473 }
474
475
476
477 * An example: errors (2/5)
478
479 Before the Go 1 meeting, Russ raised the issue in the design document:
480
481 .image how-go-was-made/errors-issue.png 500 _
482
483
484 * An example: errors (3/5)
485
486 At the meeting the team discussed the issue,
487 Russ presented data from his experiments with the change,
488 and we made a tentative decision:
489
490 .image how-go-was-made/errors-discussion.png 350 _
491
492
493 * An example: errors (4/5)
494
495 On the list, the community made some keen suggestions:
496
497 .image how-go-was-made/errors-rog.png 500 _
498
499
500 * An example: errors (5/5)
501
502 Many of those suggestions were rolled into the Go 1 design document:
503
504 .image how-go-was-made/errors-final.png 500 _
505
506
507 * Implementing Go 1
508
509 Create many new issues on the tracker.
510
511 Contributors nominate themselves to address specific issues.
512
513 Stop developing new features; prioritize stability.
514
515
516 * The success of Go 1
517
518 The Go 1 release in March 2012 heralded a new era for the project.
519
520 Users appreciated the stability. Huge uptick in community growth.
521
522 .image how-go-was-made/trends.png
523
524 Contributors focused on implementation, tools, and ecosystem.
525
526
527 * The release cycle
528
529 The next release was Go 1.1, more than a year after Go 1.
530
531 This is too long; switch to a 6-month release cycle.
532
533 Stuck to this plan for 1.2, 1.3, and 1.4, and we're (almost) on track for 1.5.
534
535
536 * The future of change
537
538
539 * A question
540
541 Go's development process emphasizes up-front design.
542
543 The project has ~450 contributors and many committers from outside Google.
544
545 But most change proposals
546 (despite being driven by community feedback)
547 were made by the Go team at Google.
548
549 Why is this?
550
551
552 * Contribution guidelines
553
554 The Go contribution guidelines are thorough on the code review process.
555
556 But on design, just this:
557
558 "Before undertaking to write something new for the Go project, send mail to the mailing list to discuss what you plan to do."
559
560 Does this describe the project's approach to design? Only superficially.
561
562 Successful proposals include design docs
563 that discuss rationale, tradeoffs, and implementation.
564
565 There is a gap in our documented process.
566
567
568 * Go Change Proposal Process: a proposal
569
570 Brad Fitzpatrick and I recently proposed a formal Change Proposal Process.
571
572 Its goals:
573
574 - Make the design process clear to new contributors.
575 - Commit to timely evaluations of proposals.
576 - Build a recorded history of proposals.
577
578
579 * How does it work?
580
581 The new change process, in brief:
582
583 - File an issue.
584 - The contributors triage the issue.
585 - Write a design document (following a template).
586 - The contributors review the document.
587 - If the proposal is accepted, implement it.
588
589 [[/s/proposal-process][go.dev/s/proposal-process]]
590
591
592 * An experimental process
593
594 The new process is an experiment.
595
596 We're still discussing exactly how it should work.
597
598 I hope it will make Go's design process more accessible to the community.
599
600
601 * Conclusion
602
603 Go's design-driven process has served us well.
604
605 But as Go is more widely used,
606 the community needs a larger role in shaping its future.
607
608 With your help, we can make Go's next 5 years more spectacular than the last.
609
610 .image how-go-was-made/5years.png 350 _
611
View as plain text