The past, present and future of Go

QCon大会

2018/10/19 发布于 技术 分类

文字内容
1. THE PAST, PRESENT, AND FUTURE OF GO 2 QCON SHANGHAI 2018
4. TODAY Where Go came from? How Go has evolved since it was launched? What’s happening in Go 2?
5. THE PAST 2007–2009
6. WHY GO? Why is their a language called Go? We have C++, Java, C#, Python, Ruby, PHP, and Javascript Why did Rob Pike, Ken Thompson, and Robert Griesemer decide to write a new language?
7. THE GO PROGRAMMING LANGUAGE, 2009
8. LANGUAGE DESIGN IN THE SERVICE OF SOFTWARE ENGINEERING
9. A LANGUAGE FOR DEVELOPER PRODUCTIVITY Together these presentations provide a rationale for a new language, originally designed for Google's software development needs. As it turns out—because we all need software—Go has become a pretty good fit for anyone writing large scale server software. Because, at its core, the goal of Go is to improve developer productivity.
10. THE DIFFERENCE BETWEEN PROGRAMMING AND SOFTWARE ENGINEERING “Software engineering is what happens to programming when you add time and other programmers.” —Russ Cox
11. THE DIFFERENCE BETWEEN PROGRAMMING AND SOFTWARE ENGINEERING The difference between software programming and software engineering is not the size of the program, but how long the program will live for. Sitting down and writing a script or a throw away program for a single computation is software programming. That’s totally fine, sometimes that is all the problem calls for.
12. THE DIFFERENCE BETWEEN PROGRAMMING AND SOFTWARE ENGINEERING On the other hand, Software engineering is a more deliberate, considered, act. It requires a broader view of the software development lifecycle than just focusing on lines of code, syntax, and algorythms. When Go launched it was with the explicit intent to improve the life of the software engineer.
13. THE PRESENT 2009–2018
14. THE PLATFORMS When Go was open sourced on the 11th of November 2009 it supported Linux, Mac OS X, on 386, amd64, and if you were running Linux, ARMv5 and v6. By the time Go 1.0 was launched in March of 2012 we added support for Windows, FreeBSD, OpenBSD
15. THE PLATFORMS In Go 1.3 we added support for FreeBSD, DragonfyBSD, OpenBSD, and NetBSD, Plan 9 on 386 and Native Client (NaCl), and Solaris on amd64 Go 1.4 added support for cross compling to Android, NaCl on ARM, and Plan 9 amd64 Go 1.5 added support for arm64 on Linux and OS X. Go 1.6 added support for 64bit MIPS on Linux, and Android on 386 Go 1.7 added support for IBM System/z and 64 bit PowerPC Go 1.8 added support for 32 bit MIPS Go 1.11 added support for web assembly and plans are in the works for a RISC-V port
16. THE PERFORMANCE
17. THE COMPANIES Atlassian, Heptio, Digital Ocean, Netflix, Pulimi, Twitch, Google, Microsoft, Reddit, Cloudflare, MongoDB, InfluxDB, Datadog, bookings.com, Rakuten, GitHub, GitLab, Freelancer, Fastly, Netlify, Pivotal, Couchbase, Lyft, Monzo, Uber, Source{d}, srcgraph, …
18. THE COMPANIES ……
19. THE PROJECTS Vitess, Docker, Traefic, Kubernetes, Istio, GitLab, Vault, Consol, Terraform, CockroachDB, CloudFoundry, Gobot, Beego, …
21. THE COMMUNITY
23. GO MEETUPS IN CHINA
24. GODOC.ORG, 800,000+ PACKAGES
25. THE CONFERENCES GOPHERCON DENVER DOTGO PARIS GOPHERCON SINGAPORE GOPHERCON EU GOPHERCON BRAZIL GOPHERCON UK
26. GO CONFERENCES IN CHINA
27. NEXT YEAR, GOPHERCHINA BEIJING
28. THE GOPHER The Go gopher was designed by Renee French.
 The design is licensed under the Creative Commons 3.0 Attributions license.
29. EGON ELBRE
32. TAKUYA UEDA
33. //LINUX.PICTURES
 IDGAF LICENSE
34. GITHUB.COM/GENGO/GOSHIP
39. ASHLEY MACNAMARA
40. THE GROWTH OF THE LANGUAGE “My best estimate is now between 0.8 and 1.6 million. It seems to me likely that we've crossed
 a million Go developers.”
 —Russ Cox, July 2018
41. THE FUTURE 2018–
42. THE BEGINNING OF GO 2 Gophercon 2017, Russ Cox announced it was time to start talking about Go 2 https://blog.golang.org/toward-go2 Go 2 would not be an opportunity to redesign the language from scratch. Instead, Go 2 would be an evolution of Go 1, designed to address pain points Go developers worldwide have felt for a decade.
43. THE BEGINNING OF GO 2 “Our goal for Go 2 is to fix the most significant ways Go fails to scale.” —Russ Cox, GopherCon 2017
44. HOW SHALL WE DISCOVER WHERE GO FAILED TO SCALE? In his presentation at Gophercon 2017 Russ discribed the methodology for how the large issues which caused Go to fail at scale will be identified. Specifically Russ called on the users of Go to write experience reports; gists, blog posts, issues, that demonstrated clearly the issues that developers were having using Go for increasingly larger and larger projects. https://github.com/golang/go/wiki/ExperienceReports Now it’s a year later, what did the Go team discover?
45. TOWARDS GO 2 Top three pain points for Go developers: •Dependency management – modules •Error handling – check, handle, and error values • Generics
46. DEPENDENCY MANAGEMENT GO MODULES
47. GO MODULES The first improvement is the addition of a new concept to the Go tool, a module. A module is a collection of packages. Just as we have .go source files grouped into a package, so too can a collection of packages with shared prefix be considered a module. Now, this probably looks pretty close to a concept that you aready know, a git repository. But there is an important difference, modules have an explicit understanding of versions.
48. WHY DO WE NEED GO MODULES? Prior to Go modules, go get only knew how to fetch whatever revision happened to be current in your repository at the time. If you already had a copy of a package in your $GOPATH then go get would skip it, so you might end up building against a really old version. If you used the go get -u flag to force it to download a fresh copy, you might find that you now had a much newer version of a package than the author.
49. GO GET DOES NOT PROVIDE REPRODUCIBLE BUILDS Put simply, go get doesn’t guarentee reproducible builds. We’ve had many people propose solutions, tools like: • godep • gopkg.in • govendor • gb Promoted the idea of a vendor/ directory, a self contained gopath that could be checked in with the code so that your program had a copy of each of the dependencies it needed.
50. THE PACKAGE MANAGEMENT WORKING GROUP In 2016 Peter Bourgon formed a working group to focus on solving the dependency management problem and called on the go team to join him in this effort. From that working group grew a tool we know as dep. dep drew much of its inspiration from the authors experience with their previous tools glide. dep encouraged the use of semver, semantic versioning, using tags on your git repos, to provide tools like dep with a way of managing the contents of your vendor/ directory.
51. THE GO TEAM INTRODUCE MODULES In early 2018 the Go team proposed their own tool, at the time given the working title vgo, now known as go modules. Go modules are integrated into the Go tool. The notion of modules is baked in as a first class citizen. This makes it possible for Go developers to build their code anywhere they want. Go modules don’t require a vendor/directory, and if you use modules you no longer need to use GOPATH to hold all your Go source code.
52. GO MODULES LIVE DEMO
53. YOU CAN USE GO MODULES TODAY Go 1.11, which shipped in August, includes full support for modules. It's opt-in at the moment, because we realise there is a large change, not just for package authors but for the ecosystem of tool authors Experiment with converting your projects to use go.mod and please give the Go team feedback via Github.
54. ERROR HANDLING CHECK, HANDLE, AND ERROR VALUES
55. ERROR HANDLING IN GO Unlike Java, Ruby, Python, or C#, Go does not use exceptions for control flow. Instead Go's error handling takes advantage of the language’s native support for multiple return values. func Open(path string) (*File, error) By convention, if a function returns an error value, then the caller should check if that error value to see if the operation succeeded or failed.
56. ERROR HANDLING IN GO By convention, if a function returns an error value, then the caller should check the error value to see if the operation succeeded or failed. f, err := os.Open("/etc/passwd")
 if err != nil {
 return err
 } Go developers believe that by being forced to think about failure case before the success case, leads to more robust programs. However, this form of error checking means it can feel repetitive to write this error checking code by hand.
57. func CopyFile(src, dst string) error { r, err := os.Open(src) if err != nil { return err } defer r.Close() w, err := os.Create(dst) if err != nil { return err } defer w.Close() if _, err := io.Copy(w, r); err != nil { return err } if err := w.Close(); err != nil { return err }
 return nil }
58. func CopyFile(src, dst string) error { r, err := os.Open(src) if err != nil { return err } defer r.Close() w, err := os.Create(dst) if err != nil { return err } defer w.Close() if _, err := io.Copy(w, r); err != nil { return err } if err := w.Close(); err != nil { return err }
 return nil }
59. func CopyFile(src, dst string) error { r, err := os.Open(src) if err != nil { return err } defer r.Close() w, err := os.Create(dst) if err != nil { return err } defer w.Close() if _, err := io.Copy(w, r); err != nil { return err } if err := w.Close(); err != nil { return err }
 return nil }
60. func CopyFile(src, dst string) error {
 r, err := os.Open(src)
 if err != nil {
 return err
 }
 defer r.Close()
 …
 } 
 func check(rc io.ReadCloser, err error) io.ReadCloser {
 if err == nil {
 return rc
 }
 panic(err) 
 }
61. func CopyFile(src, dst string) error {
 r := check(os.Open(src))
 defer r.Close()
 …
 check must return a value } 
 Two values go into check 
 
 
 func check(rc io.ReadCloser, err error) io.ReadCloser {
 if err == nil {
 return rc
 }
 panic(err) 
 One value comes out } Crashes the whole program ☹
62. func CopyFile(src, dst string) error {
 r := check(os.Open(src))
 defer r.Close()
 …
 } 
 
 
 
 func check(rc io.ReadCloser, err error) io.ReadCloser {
 if err == nil {
 return rc
 }
 return err
 } We want to return the error
 here
63. CHECK IS ADDED TO THE LANGUAGE Go programmers cannot write the own check functions today as we cannot return to the caller of the caller of check. So the Go team are adding a new check keyword to the language which does exactly this.
64. func CopyFile(src, dst string) error { r, err := os.Open(src) if err != nil { return err } defer r.Close() w, err := os.Create(dst) if err != nil { return err } defer w.Close() if _, err := io.Copy(w, r); err != nil { return err } if err := w.Close(); err != nil { return err }
 return nil }
65. func CopyFile(src, dst string) error { r := check os.Open(src) defer r.Close() w := check os.Create(dst) defer w.Close() check io.Copy(w, r) check w.Close()
 return nil }
66. func CopyFile(src, dst string) error { r, err := os.Open(src) if err != nil { return err } defer r.Close() w, err := os.Create(dst) if err != nil { return err } defer w.Close() if _, err := io.Copy(w, r); err != nil { return err } if err := w.Close(); err != nil { return err }
 return nil } Will say “couldn’t open file”, but why the file was being opened is lost Should cleanup failed copy destination on failure And remove copy if close fails
67. func CopyFile(src, dst string) error { r, err := os.Open(src) if err != nil { return fmt.Errorf("copy %s %s:'>s:'>s:'>s:'>s:'>s:'>s:'>s: %v", src, dst, err) } defer r.Close() w, err := os.Create(dst) if err != nil { return fmt.Errorf("copy %s %s:'>s:'>s:'>s:'>s:'>s:'>s:'>s: %v", src, dst, err) } if _, err := io.Copy(w, r); err != nil { w.Close() os.Remove(dst) return fmt.Errorf("copy %s %s:'>s:'>s:'>s:'>s:'>s:'>s:'>s: %v", src, dst, err) } Add context to the error so If wewueskencohwecwk thoatrefmaiolevde the
 if err != nil block, there
 will be nowhere to put the cleanup code if err := w.Close(); err != nil { os.Remove(dst) return fmt.Errorf("copy %s %s:'>s:'>s:'>s:'>s:'>s:'>s:'>s: %v", src, dst, err) } return nil }
68. CHECK AND HANDLE The solution the Go team are proposing a new statement called handle. You can think of handle as being similar to defer. Control will transfer to the handle block if err != nil. Just like defer, handle functions can appear anywhere during the function. If a check fails, it transfers control to the innermost handler, which transfers control to the next handler above it, and so on, until a handler executes a return statement.
69. func CopyFile(src, dst string) error { handle err { return fmt.Errorf("copy %s %s: %v", src, dst, err) } r := check os.Open(src) defer r.Close() w := check os.Create(dst) handle err { w.Close() os.Remove(dst) // (only if a check fails) } check io.Copy(w, r) check w.Close() return nil }
70. INSPECTING ERRORS Go programmers have two main techniques for providing information in errors. If the intent is only to describe a unique condition with no additional data, a variable of type error suffices var ErrUnexpectedEOF = errors.New("unexpected EOF") Programs can act on such sentinel errors by a simple comparison: if err == io.ErrUnexpectedEOF { ... }
71. INSPECTING ERRORS To provide more information, the programmer can define a new type that implements the error interface. For example, os.PathError is a struct that includes a pathname. Programs can extract information from these errors by using type assertions: if pe, ok := err.(*os.PathError); ok { ... pe.Path ... }
72. INSPECTING ERRORS We could instead create a new type to hold additional details along with the underlying error if err != nil {
 return &WriteError{Database: "users", Err: err}
 } However, this could break the caller as type of the error has changed to our WriteError type. Either way, wrapping breaks both equality checks and type assertions looking for the original error. This discourages wrapping, leading to less useful errors.
73. ERRORS.UNWRAP The first part of the design is to add a standard, optional interface implemented by errors that wrap other errors: package errors
 
 // A Wrapper is an error implementation
 // wrapping context around another error.
 type Wrapper interface {
 // Unwrap returns the next error in the error chain.
 // If there is no next error, Unwrap returns nil.
 Unwrap() error
 } Programs can inspect the chain of wrapped errors by using a type assertion to check for the Unwrap method and then calling it.
74. IS AND AS Wrapping errors breaks the two common patterns for acting on errors, equality comparison and type assertion. To reestablish those operations, the second part of the design adds two new functions: errors.Is, which searches the error chain for a specific error value. // instead of err == io.ErrUnexpectedEOF
 if errors.Is(err, io.ErrUnexpectedEOF) { ... } The errors.Is function is used instead of a direct equality check
75. IS AND AS The second helper is errors.As, which searches the chain for a specific type of error. The errors.As function is used instead of a type assertion: // instead of pe, ok := err.(*os.PathError)
 if pe, ok := errors.As(*os.PathError)(err); ok { 
 ... pe.Path ...
 
 }
76. ERROR HANDLING check and handle for cleaning up error handling boilerplate errors.Is and errors.As for error inspection
77. GENERICS ??????
78. WHY DO GO PROGRAMMERS WANT GENERICS? func Max(a, b int) int { if a > b { return a } return b } Only works with ints
80. GENERIC MAX IMPLEMENTATION func Max(a, b T) T {
 if a > b {
 return a
 }
 return b
 } func main() {
 var A, B uint8 = 50, 90
 result := Max(A, B)
 fmt.Println(result)
 }
81. GENERIC MAX IMPLEMENTATION func Max(a, b uint8) uint8 {
 if a > b {
 return a
 }
 return b
 } func main() {
 var A, B uint8 = 50, 90
 result := Max(A, B)
 fmt.Println(result) // 90
 }
82. THE PROBLEM WITH TEMPLATE SUBSTITUTION func Max(a, b T) T {
 if a > b {
 return a
 }
 return b
 } func main() {
 var A, B = "Hello", "QCon"
 result := Max(A, B)
 fmt.Println(result)
 }
83. THE PROBLEM WITH TEMPLATE SUBSTITUTION func Max(a, b string) string {
 if a > b {
 return a
 }
 return b
 } func main() {
 var A, B = "Hello", "QCon"
 result := Max(A, B)
 fmt.Println(result) // "QCon"
 }
84. THE PROBLEM WITH TEMPLATE SUBSTITUTION func Max(a, b T) T {
 if a > b {
 return a
 }
 return b
 } func main() {
 var A, B = []byte("Hello"), []byte("QCon")
 result := Max(A, B)
 }
85. THE PROBLEM WITH TEMPLATE SUBSTITUTION func Max(a, b []byte) []byte {
 if a > b {
 return a
 }
 return b
 Compiler complains here } func main() {
 But the bug is actually here var A, B = []byte("Hello"), []byte("QCon")
 result := Max(A, B)
 }
86. THE PROBLEM WITH TEMPLATE SUBSTITUTION func Max(a, b T) T {
 if a > b {
 return a
 }
 return b
 } func main() {
 var A, B float64 = 3.1417, math.NaN()
 result := Max(A, B)
 fmt.Println(result)
 }
87. THE PROBLEM WITH TEMPLATE SUBSTITUTION func Max(a, b float64) float64 {
 if a > b {
 return a
 }
 return b
 } func main() {
 var A, B float64 = 3.1417, math.NaN()
 result := Max(A, B)
 fmt.Println(result) // ????
 }
88. THE PROBLEM WITH TEMPLATE SUBSTITUTION We need a way of applying a constraint on which types can be substituted for T In other languages, like Java, this is called a type bound. public static T max(T a, T b) { ... } Go doesn't have type inheretence, and we don't want to add it, we see not having inheretence as a feature, not a bug.
89. CONTRACTS The suggestion the Go team have come up with is called a contract. A contract is a way to write down a list of requirements for a type implementing T contract comparable(t T) {
 t > t
 t << 1
 }
90. COMPARABLE CONTRACT contract comparable(t T) {
 t > t
 t << 1
 } T must be a type with a greater
 than operator. This excludes slices, maps channels, or structs. T must be a type that can be shifted, 
 this excludes float64.
91. HOW DO WE USE A CONTRACT? contract comparable(t T) { t>t t << 1 } Type parameter func Max(type T comparable)(a, b T) T { if a > b { return a } return b Return values } Formal parameters
92. THE GENERIC DILEMMA The generics debate in Go is not new. Years ago Russ Cox wrote a short post called the Generics Dilemma, on the three approaches to adding generics to any language 1. Don't do it. This is the approach C tool, and, until now, the approach Go chose. 2. Compile-time specialisation or template expansion. This is the C++ approach, It generates a lot of code, much of it redundant, and needs a good linker to eliminate duplicate copies. This slows down compliation 3. Box everything and insert casts at runtime. This is the Java approach.
93. GO GENERICS DON'T DICTATE HOW THE COMPILER WILL IMPLEMENT THEM The important thing to recognise in this proposal is the syntax I shown in the previous slides does not dictate how the feature will be implemented. Unlike the C++ implementation which is explicitly defined to rely on template text substitution, or the java solution which requires boxing every patameter into an object, this proposal does not specify how the compiler should implement this feature. The Go compiler may choose to specialise a generic function at compiletime or use run time boxing and casting. The decision becomes purely a compiler optimization, not one of semantic significance.
94. WOULD YOU LIKE TO KNOW MORE? If you'd like to know more, read the design documents, and importantly contribute your feedback on these proposals at this page https://blog.golang.org/go2draft Go modules implementation is much further along, as I mentioned, its available to try in Go 1.11 today, so feedback and experience reports are best directed to the issue tracker.
95. THERE WILL BE NO GO 2 AND THAT’S OK
96. STABILITY Go developers recognise that over the last 9 years the value Go has bought to you is not what has been added to go, but what has not changed. The value in Go is the huge base of software written in the language that was defined in 2012, and which we’ve been using productively since then.
97. BACKWARDS COMPATIBILITY The value of Go is in the commitment to backwards compatibility that the Go 1 contract bought us for the last nine years.
98. ADOPTION The value in language is all of you in this room today. Because ultimately a programming language is only successful if it has a large user base of people who are happy to continue to use it.
99. TOWARDS GO 2 In a few months it will be December, then January 2019. 2019 is a whole new year, distinct and separate from the previous 365 days of 2018. Yet, except for changing the year, January 1st 2019 will be in every other respect just a continuation of December 31st, 2018.
100. TOWARDS GO 2 For all of the Go users today, Go 2 is not a single release we're working towards. Just like one day following the next, the progress of small, frequent, releases will continue, adding these features that I discussed today,—and maybe a few other small tweaks—until one day we decide to call it Go 2.
103. THANK YOU! ENJOY QCON SHANGHAI 2018 EGON ELBRE