github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/talks/2012/splash.slide (about) 1 Go at Google 2 SPLASH, Tucson, Oct 25, 2012 3 4 Rob Pike 5 Google, Inc. 6 @rob_pike 7 http://golang.org/s/plusrob 8 http://golang.org 9 10 * Preamble 11 12 * What is Go? 13 14 Go is: 15 16 - open source 17 - concurrent 18 - garbage-collected 19 - efficient 20 - scalable 21 - simple 22 - fun 23 - boring (to some) 24 25 .link http://golang.org http://golang.org 26 27 * History 28 29 Design began in late 2007. 30 31 Key players: 32 33 - Robert Griesemer, Rob Pike, Ken Thompson 34 - Later: Ian Lance Taylor, Russ Cox 35 36 Became open source in November 2009. 37 38 Developed entirely in the open; very active community. 39 Language stable as of Go 1, early 2012. 40 41 * Go at Google 42 43 Go is a programming language designed by Google to help solve Google's problems. 44 45 Google has big problems. 46 47 * Big hardware 48 49 .image splash/datacenter.jpg 50 51 * Big software 52 53 - C++ (mostly) for servers, plus lots of Java and Python 54 - thousands of engineers 55 - gazillions of lines of code 56 - distributed build system 57 - one tree 58 59 And of course: 60 61 - zillions of machines, which we treat as a modest number of compute clusters 62 63 Development at Google can be slow, often clumsy. 64 65 But it _is_ effective. 66 67 * The reason for Go 68 69 Goals: 70 71 - eliminate slowness 72 - eliminate clumsiness 73 - improve effectiveness 74 - maintain (even improve) scale 75 76 Go was designed by and for people who write—and read and debug and maintain—large software systems. 77 78 Go's purpose is _not_ research into programming language design. 79 80 Go's purpose is to make its designers' programming lives better. 81 82 * Today's theme 83 84 A talk about software engineering more than language design. 85 86 To be more accurate: 87 88 - Language design in the service of software engineering. 89 90 In short: 91 92 - How does a language help software engineering? 93 94 * Features? 95 96 Reaction upon launch: 97 My favorite feature isn't in Go! Go Sucks! 98 99 This misses the point. 100 101 * Pain 102 103 What makes large-scale development hard with C++ or Java (at least): 104 105 - slow builds 106 - uncontrolled dependencies 107 - each programmer using a different subset of the language 108 - poor program understanding (documentation, etc.) 109 - duplication of effort 110 - cost of updates 111 - version skew 112 - difficulty of automation (auto rewriters etc.): tooling 113 - cross-language builds 114 115 Language _features_ don't usually address these. 116 117 * Focus 118 119 In the design of Go, we tried to focus on solutions to _these_ problems. 120 121 Example: indentation for structure vs. C-like braces 122 123 * Dependencies in C and C++ 124 125 * A personal history of dependencies in C 126 127 `#ifdef` 128 129 `#ifndef` "guards": 130 131 #ifndef _SYS_STAT_H_ 132 133 1984: `<sys/stat.h>` times 37 134 135 ANSI C and `#ifndef` guards: 136 137 - dependencies accumulate 138 - throw includes at the program until it compiles 139 - no way to know what can be removed 140 141 * A personal history of dependencies in Plan 9's C 142 143 Plan 9, another take: 144 145 - no `#ifdefs` (or `#ifndefs`) 146 - documentation and topological sort 147 - easy to find out what can be removed 148 149 Need to document dependencies, but much faster compilation. 150 151 In short: 152 153 - _ANSI_C_made_a_costly_mistake_ in requiring `#ifndef` guards. 154 155 * A personal history of dependencies in C++ 156 157 C++ exacerbated the problem: 158 159 - one `#include` file per class 160 - code (not just declarations) in `#include` files 161 - `#ifndef` guards persist 162 163 2004: Mike Burrows and Chubby: `<xxx>` times 37,000 164 165 1984: Tom Cargill and pi 166 167 * A personal history of dependencies at Google 168 169 Plan 9 demo: a story 170 171 Early Google: one `Makefile` 172 173 2003: `Makefile` generated from per-directory `BUILD` files 174 175 - explicit dependencies 176 - 40% smaller binaries 177 178 Dependencies still not checkable! 179 180 * Result 181 182 To build a large Google binary on a single computer is impractical. 183 184 In 2007, instrumented the build of a major Google binary: 185 186 - 2000 files 187 - 4.2 megabytes 188 - 8 gigabytes delivered to compiler 189 - 2000 bytes sent to compiler for every C++ source byte 190 - it's real work too: `<string>` for example 191 - hours to build 192 193 * Tools can help 194 195 New distributed build system: 196 197 - no more `Makefile` (still uses `BUILD` files) 198 - many buildbots 199 - much caching 200 - much complexity (a large program in its own right) 201 202 Even with Google's massive distributed build system, a large build still takes minutes. 203 (In 2007 that binary took 45 minutes; today, 27 minutes.) 204 205 Poor quality of life. 206 207 * Enter Go 208 209 While that build runs, we have time to think. 210 211 Want a language to improve the quality of life. 212 213 And dependencies are only one such problem.... 214 215 * Primary considerations 216 217 Must work at scale: 218 219 - large programs 220 - large teams 221 - large number of dependencies 222 223 Must be familiar, roughly C-like 224 225 * Modernize 226 227 The old ways are _old_. 228 229 Go should be: 230 231 - suitable for multicore machines 232 - suitable for networked machines 233 - suitable for web stuff 234 235 * The design of Go 236 237 From a software engineering perspective. 238 239 * Dependencies in Go 240 241 * Dependencies 242 243 Dependencies are defined (syntactically) in the language. 244 245 Explicit, clear, computable. 246 247 import "encoding/json" 248 249 Unused dependencies cause error at compile time. 250 251 Efficient: dependencies traversed once per source file... 252 253 * Hoisting dependencies 254 255 Consider: 256 `A` imports `B` imports `C` but `A` does not directly import `C`. 257 258 The object code for `B` includes all the information about `C` needed to import `B`. 259 Therefore in `A` the line 260 261 import "B" 262 263 does not require the compiler to read `C` when compiling `A`. 264 265 Also, the object files are designed so the "export" information comes first; compiler doing import does not need to read whole file. 266 267 Exponentially less data read than with `#include` files. 268 269 With Go in Google, about 40X fanout (recall C++ was 2000x) 270 Plus in C++ it's general code that must be parsed; in Go it's just export data. 271 272 * No circular imports 273 274 Circular imports are illegal in Go. 275 276 The big picture in a nutshell: 277 278 - occasional minor pain, 279 - but great reduction in annoyance overall 280 - structural typing makes it less important than with type hierarchies 281 - keeps us honest! 282 283 Forces clear demarcation between packages. 284 285 Simplifies compilation, linking, initialization. 286 287 * API design 288 289 Through the design of the standard library, great effort spent on controlling dependencies. 290 291 It can be better to copy a little code than to pull in a big library for one function. 292 (A test in the system build complains if new core dependencies arise.) 293 294 Dependency hygiene trumps code reuse. 295 296 Example: 297 The (low-level) `net` package has own `itoa` to avoid dependency on the big formatted I/O package. 298 299 * Packages 300 301 * Packages 302 303 Every Go source file, e.g. `"encoding/json/json.go"`, starts 304 305 package json 306 307 where `json` is the "package name", an identifier. 308 Package names are usually concise. 309 310 To use a package, need to identify it by path: 311 312 import "encoding/json" 313 314 And then the package name is used to qualify items from package: 315 316 var dec = json.NewDecoder(reader) 317 318 Clarity: can always tell if name is local to package from its syntax: `Name` vs. `pkg.Name`. 319 (More on this later.) 320 321 Package combines properties of library, name space, and module. 322 323 * Package paths are unique, not package names 324 325 The path is `"encoding/json"` but the package name is `json`. 326 The path identifies the package and must be unique. 327 Project or company name at root of name space. 328 329 import "google/base/go/log" 330 331 Package name might not be unique; can be overridden. These are both `package`log`: 332 333 import "log" // Standard package 334 import googlelog "google/base/go/log" // Google-specific package 335 336 Every company might have its own `log` package; no need to make the package name unique. 337 338 Another: there are many `server` packages in Google's code base. 339 340 * Remote packages 341 342 Package path syntax works with remote repositories. 343 The import path is just a string. 344 345 Can be a file, can be a URL: 346 347 go get github.com/4ad/doozer // Command to fetch package 348 349 import "github.com/4ad/doozer" // Doozer client's import statement 350 351 var client doozer.Conn // Client's use of package 352 353 * Go's Syntax 354 355 * Syntax 356 357 Syntax is not important... 358 359 - unless you're programming 360 - or writing tools 361 362 Tooling is essential, so Go has a clean syntax. 363 Not super small, just clean: 364 365 - regular (mostly) 366 - only 25 keywords 367 - straightforward to parse (no type-specific context required) 368 - easy to predict, reason about 369 370 * Declarations 371 372 Uses Pascal/Modula-style syntax: name before type, more type keywords. 373 374 var fn func([]int) int 375 type T struct { a, b int } 376 377 not 378 379 int (*fn)(int[]); 380 struct T { int a, b; } 381 382 Easier to parse—no symbol table needed. Tools become easier to write. 383 384 One nice effect: can drop `var` and derive type of variable from expression: 385 386 var buf *bytes.Buffer = bytes.NewBuffer(x) // explicit 387 buf := bytes.NewBuffer(x) // derived 388 389 For more information: 390 391 .link http://golang.org/s/decl-syntax 392 393 * Function syntax 394 395 Function on type `T`: 396 397 func Abs(t T) float64 398 399 Method of type `T`: 400 401 func (t T) Abs() float64 402 403 Variable (closure) of type `T`: 404 405 negAbs := func(t T) float64 { return -Abs(t) } 406 407 In Go, functions can return multiple values. Common case: `error`. 408 409 func ReadByte() (c byte, err error) 410 411 c, err := ReadByte() 412 if err != nil { ... } 413 414 More about errors later. 415 416 * No default arguments 417 418 Go does not support default function arguments. 419 420 Why not? 421 422 - too easy to throw in defaulted args to fix design problems 423 - encourages too many args 424 - too hard to understand the effect of the fn for different combinations of args 425 426 Extra verbosity may happen but that encourages extra thought about names. 427 428 Related: Go has easy-to-use, type-safe support for variadic functions. 429 430 * Naming 431 432 * Export syntax 433 434 Simple rule: 435 436 - upper case initial letter: `Name` is visible to clients of package 437 - otherwise: `name` (or `_Name`) is not visible to clients of package 438 439 Applies to variables, types, functions, methods, constants, fields.... 440 441 That Is It. 442 443 Not an easy decision. 444 One of the most important things about the language. 445 446 Can see the visibility of an identifier without discovering the declaration. 447 448 Clarity. 449 450 * Scope 451 452 Go has very simple scope hierarchy: 453 454 - universe 455 - package 456 - file (for imports only) 457 - function 458 - block 459 460 * Locality of naming 461 462 Nuances: 463 464 - no implicit `this` in methods (receiver is explicit); always see `rcvr.Field` 465 - package qualifier always present for imported names 466 - (first component of) every name is always declared in current package 467 468 No surprises when importing: 469 470 - adding an exported name to my package cannot break your package! 471 472 Names do not leak across boundaries. 473 474 In C, C++, Java the name `y` could refer to anything 475 In Go, `y` (or even `Y`) is always defined within the package. 476 In Go, `x.Y` is clear: find `x` locally, `Y` belongs to it. 477 478 * Function and method lookup 479 480 Method lookup by name only, not type. 481 A type cannot have two methods with the same name, ever. 482 Easy to identify which function/method is referred to. 483 Simple implementation, simpler program, fewer surprises. 484 485 Given a method `x.M`, there's only ever one `M` associated with `x`. 486 487 * Semantics 488 489 * Basics 490 491 Generally C-like: 492 493 - statically typed 494 - procedural 495 - compiled 496 - pointers etc. 497 498 Should feel familiar to programmers from the C family. 499 500 * But... 501 502 Many small changes in the aid of robustness: 503 504 - no pointer arithmetic 505 - no implicit numeric conversions 506 - array bounds checking 507 - no type aliases 508 - `++` and `--` as statements not expressions 509 - assignment not an expression 510 - legal (encouraged even) to take address of stack variable 511 - many more 512 513 Plus some big ones... 514 515 * Bigger things 516 517 Some elements of Go step farther from C, even C++ and Java: 518 519 - concurrency 520 - garbage collection 521 - interface types 522 - reflection 523 - type switches 524 525 * Concurrency 526 527 * Concurrency 528 529 Important to modern computing environment. 530 Not well served by C++ or even Java. 531 532 Go embodies a variant of CSP with first-class channels. 533 534 Why CSP? 535 536 - The rest of the language can be ordinary and familiar. 537 538 Must be able to couple concurrency with computation. 539 540 Example: concurrency and cryptography. 541 542 * CSP is practical 543 544 For a web server, the canonical Go program, the model is a great fit. 545 546 Go _enables_ simple, safe concurrent programming. 547 It doesn't _forbid_ bad programming. 548 549 Focus on _composition_ of regular code. 550 551 Caveat: not purely memory safe; sharing is legal. 552 Passing a pointer over a channel is idiomatic. 553 554 Experience shows this is a practical design. 555 556 * Garbage collection 557 558 * The need for garbage collection 559 560 Too much programming in C and C++ is about memory allocation. 561 But also the design revolves too much about memory management. 562 Leaky abstractions, leaky dependencies. 563 564 Go has garbage collection, only. 565 566 Needed for concurrency: tracking ownership too hard otherwise. 567 Important for abstraction: separate behavior from resource management. 568 A key part of scalability: APIs remain local. 569 570 Use of the language is much simpler because of GC. 571 Adds run-time cost, latency, complexity to the implementation. 572 573 Day 1 design decision. 574 575 * Garbage collection in Go 576 577 A garbage-collected systems language is heresy! 578 Experience with Java: Uncontrollable cost, too much tuning. 579 580 But Go is different. 581 Go lets you limit allocation by controlling memory layout. 582 583 Example: 584 585 type X struct { 586 a, b, c int 587 buf [256]byte 588 } 589 590 Example: Custom arena allocator with free list. 591 592 * Interior pointers 593 594 Early decision: allow interior pointers such as `X.buf` from previous slide. 595 596 Tradeoff: Affects which GC algorithms that can be used, but in return reduces pressure on the collector. 597 598 Gives the _programmer_ tools to control GC overhead. 599 600 Experience, compared to Java, shows it has significant effect on memory pressure. 601 602 GC remains an active subject. 603 Current design: parallel mark-and-sweep. 604 With care to use memory wisely, works well in production. 605 606 * Interfaces 607 608 Composition not inheritance 609 610 * Object orientation and big software 611 612 Go is object-oriented. 613 Go does not have classes or subtype inheritance. 614 615 What does this mean? 616 617 * No type hierarchy 618 619 O-O is important because it provides uniformity of interface. 620 Outrageous example: the Plan 9 kernel. 621 622 Problem: subtype inheritance encourages _non-uniform_ interfaces. 623 624 * O-O and program evolution 625 626 Design by type inheritance oversold. 627 Generates brittle code. 628 Early decisions hard to change, often poorly informed. 629 Makes every programmer an interface designer. 630 (Plan 9 was built around a single interface everything needed to satisfy.) 631 632 Therefore encourages overdesign early on: predict every eventuality. 633 Exacerbates the problem, complicates designs. 634 635 * Go: interface composition 636 637 In Go an interface is _just_ a set of methods: 638 639 type Hash interface { 640 Write(p []byte) (n int, err error) 641 Sum(b []byte) []byte 642 Reset() 643 Size() int 644 BlockSize() int 645 } 646 647 No `implements` declaration. 648 All hash implementations satisfy this implicitly. (Statically checked.) 649 650 * Interfaces in practice: composition 651 652 Tend to be small: one or two methods are common. 653 654 Composition falls out trivially. Easy example, from package `io`: 655 656 type Reader interface { 657 Read(p []byte) (n int, err error) 658 } 659 660 `Reader` (plus the complementary `Writer`) makes it easy to chain: 661 662 - files, buffers, networks, encryptors, compressors, GIF, JPEG, PNG, ... 663 664 Dependency structure is not a hierarchy; these also implement other interfaces. 665 666 Growth through composition is _natural_, does not need to be pre-declared. 667 668 And that growth can be _ad_hoc_ and linear. 669 670 * Compose with functions, not methods 671 672 Hard to overstate the effect that Go's interfaces have on program design. 673 674 One big effect: functions with interface arguments. 675 676 func ReadAll(r io.Reader) ([]byte, error) 677 678 Wrappers: 679 680 func LoggingReader(r io.Reader) io.Reader 681 func LimitingReader(r io.Reader, n int64) io.Reader 682 func ErrorInjector(r io.Reader) io.Reader 683 684 The designs are nothing like hierarchical, subtype-inherited methods. 685 Much looser, organic, decoupled, independent. 686 687 * Errors 688 689 * Error handling 690 691 Multiple function return values inform the design for handling errors. 692 693 Go has no `try-catch` control structures for exceptions. 694 Return `error` instead: built-in interface type that can "stringify" itself: 695 696 type error interface { Error() string } 697 698 Clear and simple. 699 700 Philosophy: 701 702 Forces you think about errors—and deal with them—when they arise. 703 Errors are _normal_. Errors are _not_exceptional_. 704 Use the existing language to compute based on them. 705 Don't need a sublanguage that treats them as exceptional. 706 707 Result is better code (if more verbose). 708 709 * (OK, not all errors are normal. But most are.) 710 711 .image splash/fire.jpg 712 713 * Tools 714 715 * Tools 716 717 Software engineering requires tools. 718 719 Go's syntax, package design, naming, etc. make tools easy to write. 720 721 Standard library includes lexer and parser; type checker nearly done. 722 723 * Gofmt 724 725 Always intended to do automatic code formatting. 726 Eliminates an entire class of argument. 727 Runs as a "presubmit" to the code repositories. 728 729 Training: 730 731 - The community has always seen `gofmt` output. 732 733 Sharing: 734 735 - Uniformity of presentation simplifies sharing. 736 737 Scaling: 738 739 - Less time spent on formatting, more on content. 740 741 Often cited as one of Go's best features. 742 743 * Gofmt and other tools 744 745 Surprise: The existence of `gofmt` enabled _semantic_ tools: 746 Can rewrite the tree; `gofmt` will clean up output. 747 748 Examples: 749 750 - `gofmt`-r`'a[b:len(a)]`->`a[b:]'` 751 - `gofix` 752 753 And good front-end libraries enable ancillary tools: 754 755 - `godoc` 756 - `go`get`, `go`build`, etc. 757 - `api` 758 759 * Gofix 760 761 The `gofix` tool allowed us to make sweeping changes to APIs and language features leading up to the release of Go 1. 762 763 - change to map deletion syntax 764 - new time API 765 - many more 766 767 Also allows us to _update_ code even if the old code still works. 768 769 Recent example: 770 771 Changed Go's protocol buffer implementation to use getter functions; updated _all_ Google Go code to use them with `gofix`. 772 773 * Conclusion 774 775 * Go at Google 776 777 Go's use is growing inside Google. 778 779 Several big services use it: 780 781 - golang.org 782 - youtube.com 783 - dl.google.com 784 785 Many small ones do, many using Google App Engine. 786 787 * Go outside Google 788 789 Many outside companies use it, including: 790 791 - BBC Worldwide 792 - Canonical 793 - Heroku 794 - Nokia 795 - SoundCloud 796 797 * What's wrong? 798 799 Not enough experience yet to know if Go is truly successful. 800 Not enough big programs. 801 802 Some minor details wrong. Examples: 803 804 - declarations still too fussy 805 - `nil` is overloaded 806 - lots of library details 807 808 `Gofix` and `gofmt` gave us the opportunity to fix many problems, ranging from eliminating semicolons to redesigning the `time` package. 809 But we're still learning (and the language is frozen for now). 810 811 The implementation still needs work, the run-time system in particular. 812 813 But all indicators are positive. 814 815 * Summary 816 817 Software engineering guided the design. 818 But a productive, fun language resulted because that design enabled productivity. 819 820 Clear dependencies 821 Clear syntax 822 Clear semantics 823 Composition not inheritance 824 Simplicity of model (GC, concurrency) 825 Easy tooling (the `go` tool, `gofmt`, `godoc`, `gofix`) 826 827 * Try it! 828 829 .link http://golang.org http://golang.org 830 831 .image splash/appenginegophercolor.jpg 832