This is a creation in Article, where the information may have evolved or changed.
Francesc (@francesc) is a member of the Go core team and is a developer of the Google Cloud platform. He is a programming language enthusiast, Google's technical guidance guru, one of the creators of the Go tour. This discussion is inspired by another Raquel Vélez in jsconf. Slides discussion, this discussion has been sent here.
Sourcegraph is the next generation of programming collaboration tools for searching, exploring, and reviewing code. We participate in Gophercon India to share how we use Go and learn how others use it, and we are honored to cooperate with liveblog in this discussion.
As one of the developers of the Go team, Francesc probably has more go language programmers than anyone else in the world. Because of this favourable condition, he divides the learning process of the go language into 5 stages.
These stages are also established for the learning of other languages. Understanding what stage you are in can help you find the most effective ways to improve yourself, and avoid common pitfalls in each stage of your learning process.
Editor's note: This article gives an interactive code snippet for each learning phase. By clicking on the function name you can jump to a specific function definition, allowing for in-depth research. Please see below.
Here are the five evolutionary stages of GO programmers:
The first stage (vegetable forcing): just learned the language. Some tutorials or workshops have been used to understand the basic syntax and can write short snippets of code.
Second Stage (explorer): Can write a complete program, but do not understand some of the more advanced language features, such as "channels". You haven't used go to write a big project.
The third stage (Big hand): You can skillfully use go, can use go to solve, production environment in a specific and complete problem. Has formed a set of its own idioms and common code base. Go is a very useful tool in your coding scheme.
Fourth stage (great God): It is absolutely impossible to understand the design choices and motivations behind the go language. A concise and composable philosophy that can be understood.
preacher : Actively share with others about go language knowledge and your understanding of the go language. In a variety of suitable places to send their own voice, participate in mailing lists, set up QQ Group, do special reports. Being a preacher is not necessarily a completely independent phase, and this role can be in any one of these stages.
First stage: Vegetable forcing
Rookie at this stage use go to create some small projects or toy projects. They should take advantage of the Go tour, go playground/wide, go docs, and mailing lists (golang-nuts).
func main() { fmt.Println(stringutil.Reverse("!selpmaxe oG ,olleH"))}
View Context
Func Main in Golang/example on✱sourcegraph
This is a simple example of the go language, and this snippet is from the hello.go in the Golang/example code base . Click to view full code.
An important skill, the newcomer should try to learn how to ask questions correctly. Many new people in the mailing list say, "Hey, this is an error," which does not provide enough information to allow others to understand and help them solve the problem. What others see is a post with hundreds of lines of code pasted, and no effort is devoted to highlighting the problem.
Therefore, you should try to avoid pasting the code directly into the forum. Instead, use the "Share" button in the Go playground that can be edited and run directly in the browser to link to the code snippet. (Note: Playground is wall, can use wide)
Second Stage (seeker)
Explorers can already use go to write small software, but sometimes they are still confused. They may not fully understand how to use the advanced features of go, such as channels. Although they have a lot of things to learn, but have mastered enough to do something useful! They start to feel about the potential of go and are excited about what they can do with go.
There are usually two steps to be experienced during the exploratory phase. First, the inflated expectations reach the top, and you think you can do all the things with go, but you can't understand or comprehend the true meaning of go. You'll probably write the go code in familiar language patterns and idioms, but there's no strong sense of what it's like to go. You start trying to do things like "Migrating architecture x, from Y to go".
After reaching the vertex of the expected swelling, you will encounter the valley of ideal disillusionment. You start to miss the character X of language y, and you don't have a complete grasp of the go. You're still writing the Go Language program in other programming languages, and you're even starting to feel frustrated. You may be using both reflect and unsafe packages, but this is not a typical go. The true go does not use the same magical things.
A good example of the project generated during this exploratory phase is the Martini Web framework. Martini is an early web framework for the Go language, which absorbs a lot of ideas (such as dependency injection) from the Ruby Web framework. Initially, the framework had a strong response in the community, but it was increasingly criticized for performance and usability. Jeremy Saenz, author of the Martini Framework, responds positively to these feedback from the go community and writes a library that is more compliant with the Go Language Specification Negroni
func (m *Martini) RunOnAddr(addr string) { // TODO: Should probably be implemented using a new instance of http.Server in place of // calling http.ListenAndServer directly, so that it could be stored in the martini struct for later use. // This would also allow to improve testing when a custom host and port are passed. logger := m.Injector.Get(reflect.TypeOf(m.logger)).Interface().(*log.Logger) logger.Printf("listening on %s (%s)\n", addr, Env) logger.Fatalln(http.ListenAndServe(addr, m))}
View Context
(*martini). Runonaddr in Go-martini/martini on✱sourcegraph
An interactive code snippet from the Martini Framework, which is an example of an unusual go. Note Dependency injection implemented with reflection packets
func TestNegroniServeHTTP(t *testing.T) { result := "" response := httptest.NewRecorder() n := New() n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "foo" next(rw, r) result += "ban" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bar" next(rw, r) result += "baz" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bat" rw.WriteHeader(http.StatusBadRequest) })) n.ServeHTTP(response, (*http.Request)(nil)) expect(t, result, "foobarbatbazban") expect(t, response.Code, http.StatusBadRequest)}
View Context
Func testnegroniservehttp in Codegangsta/negroni on * sourcegraph
An interactive code snippet from the Negroni library, which is an example of an authentic go
Other languages often rely on third-party libraries when it comes to providing some core functionality, such as HTTP processing. But the go language is very different at this point, and its standard library is very powerful. If you think the Go standard library is not strong to do what you want to do, then I say you are wrong. The Go Language standard library is incredibly powerful, and it's worth taking the time to read its code and learn the patterns it implements.
func (srv *Server) ListenAndServe() error { addr := srv.Addr if addr == "" { addr = ":http" } ln, err := net.Listen("tcp", addr) if err != nil { return err } return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})}
View in context
(*server). Listenandserve in Golang/go on* sourcegraph
The Listenandserve function fragment in the Go standard library. If you have written a go program, you may have called this function many times, but have you ever taken the time to see its implementation? Click on the code snippet above.
Disillusionment in the depths of disillusionment comes from the fact that you are still thinking in other language patterns, and you have not fully explored what go can offer you. Here are some fun things you can do to break down the dilemma and further explore the fun things in this language.
Go generate
Now look at go generate. Go generate is a command that you can use to automatically generate the Go code. You can combine meta-programming such as jsonenums (a class library that automatically generates JSON marshalling boilerplate code for enumeration types) to quickly automate the writing of repetitive tedious code using go generate. There are already a large number of interfaces that can be used to parse the AST in the Go Standard class library, and AST makes it easier and easier to write meta-programming tools. At the meeting, there were two other discussions (meta-programming practices in the go language and embracing the standard class library).
Func main () {flag. Parse () If Len (*typenames) = = 0 {log. Fatalf ("The Flag-type must be set")} Types: = Strings. Split (*typenames, ",")//Only one directory at a time can processed, and the default is ".". Dir: = "." If args: = flag. Args (); Len (args) = = 1 {dir = args[0]} else if Len (args) > 1 {log. Fatalf ("Only one directory at a Time")} pkg, err: = parser. Parsepackage (dir, *outputsuffix+ ". Go") if err! = Nil {log. Fatalf ("Parsing package:%v", err)} var analysis = struct {Command string packagename str ing typesandvalues map[string][]string} {command:strings. Join (OS. Args[1:], ""), packagename:pkg. Name, Typesandvalues:make (map[string][]string),}//Run generate for each type. For _, TypeName: = range Types {values, err: = pkg. Valuesoftype (typeName) if err! = Nil {log. Fatalf ("Finding values for type%v:%v ", TypeName, Err)} analysis. Typesandvalues[typename] = values var buf bytes. Buffer If Err: = Generatedtmpl.execute (&buf, analysis); Err! = Nil {log. Fatalf ("Generating Code:%V", err)} src, err: = format. Source (BUF. Bytes ()) if err! = Nil {//should never happen, but can arise when developing this code. The user can compile the output to see the error. Log. Printf ("Warning:internal error:invalid Go generated:%s", err) log. Printf ("Warning:compile the package to analyze the error") src = buf. Bytes ()} Output: = Strings. ToLower (typeName + *outputsuffix + ". Go") OutputPath: = FilePath. Join (dir, Output) if err: = Ioutil. WriteFile (OutputPath, SRC, 0644); Err! = Nil {log. Fatalf ("Writing output:%s", Err)}}}
View Context
The main function in Campoy/jsonenums on the ✱sourcegraph site
An interactive fragment demonstrates how to write the jsonenums command.
Opengl
Many people use go as a Web service, but do you know that you can also write cool graphics apps with go? Check out the bundle of go in OpenGL.
func main() { glfw.SetErrorCallback(errorCallback) if !glfw.Init() { panic("Can't init glfw!") } defer glfw.Terminate() window, err := glfw.CreateWindow(Width, Height, Title, nil, nil) if err != nil { panic(err) } window.MakeContextCurrent() glfw.SwapInterval(1) gl.Init() if err := initScene(); err != nil { fmt.Fprintf(os.Stderr, "init: %s\n", err) return } defer destroyScene() for !window.ShouldClose() { drawScene() window.SwapBuffers() glfw.PollEvents() }}
View in text
The function inside the go-gl/examples in ✱sourcegraph main
The interactive fragment is a description of the OpenGL bundle of go to make Gopher cube. Click on the function or method name to explore.
Hacking Marathon and challenges
You can also watch the challenges and Hackathon Marathon, similar to Gopher Gala and go challenge. In the past, programmers from all over the world have been working together to challenge some real cool projects where you can get inspiration from them.
Stage Three: Veteran
As an old hand, this means you can solve many of the issues you care about in the go language. The new problems that need to be solved will bring new questions, and after trial and error, you have learned what can and cannot be done in this language. At this point, you have a solid understanding of the language's habits and patterns. You can work very efficiently, write readable, well-documented, maintainable code.
A good way to be a veteran is to work on a big project. If you have an idea for a project yourself, start doing it (and, of course, make sure it doesn't already exist). Most people may not have the idea of a big project, so they can contribute to a project that already exists. The go language already has many large projects, and they are being used extensively, such as Docker, Kubernetes and go itself. Take a look at this list of items
func (cli *DockerCli) CmdRestart(args ...string) error { cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container", true) nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing the container.") cmd.Require(flag.Min, 1) utils.ParseFlags(cmd, args, true) v := url.Values{} v.Set("t", strconv.Itoa(*nSeconds)) var encounteredError error for _, name := range cmd.Args() { _, _, err := readBody(cli.call("POST", "/containers/"+name+"/restart?"+v.Encode(), nil, false)) if err != nil { fmt.Fprintf(cli.err, "%s\n", err) encounteredError = fmt.Errorf("Error: failed to restart one or more containers") } else { fmt.Fprintf(cli.out, "%s\n", name) } } return encounteredError}
View in context
(*DOCKERCLI). cmdrestart in Docker/docker on * sourcegraph
The interactive code snippet for the Docker project. Click on the function name to begin the journey of discovery.
Veteran should have a strong grasp of the tools of the go ecosystem, as these tools really improve productivity. You should understand go Generate,go vet,go test-race, and Gofmt/goimports/goreturns. You should use Go FMT because it will automatically format your code according to the style standard of the go community. Goimports can do the same thing, and it will add the lost imports. Goretures not only did what was said before, but also added the missing error in the return expression, which everyone hated.
At the veteran stage, you must start code review. The meaning of code review is not to modify or find errors (that's what testers do). Code review can help maintain a unified programming style, improve the overall quality of your software, and improve your own programming skills in other people's feedback. Almost all large open source projects do code review for each commit.
Here's an example of learning from human feedback: Google's go team used to declare command-line tags outside of the main function. At last year's Gophercon meeting, Francesc met the SoundCloud company's Peter Bourgon (@peterbourgon). Peter Bourgon says in SoundCloud, they all declare tags inside the main function so they don't mistakenly use tags externally. Francesc now thinks this is a best practice.
Stage four: Experts
As an expert, you have a good understanding of the philosophical thinking of language. For the Go language feature, you know when to use and when not to use. For example, Jeremy Saenz in the Dotgo storm discussion about when to use an interface.
func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call { call := new(Call) call.ServiceMethod = serviceMethod call.Args = args call.Reply = reply if done == nil { done = make(chan *Call, 10) // buffered. } else { // If caller passes done != nil, it must arrange that // done has enough buffer for the number of simultaneous // RPCs that will be using that channel. If the channel // is totally unbuffered, it's best not to run at all. if cap(done) == 0 { log.Panic("rpc: done channel is unbuffered") } } call.Done = done client.send(call) return call}
View Context
✱sourcegraph (*client) in Golang/go on the site. Go
A small piece of interactive code fragments from the standard class library use the channel. Understanding the decision behind the model in the standard class library is the only way to become an expert.
But don't be an expert in a single language. Like any other language, go is just a tool. You should also explore other languages and learn about their patterns and styles. Francesc from his experience of using go to find the inspiration to write JavaScript. He also likes to focus on immutability and the Haskell language, which is committed to avoiding variability, and gets inspiration for how to write go code.
Preacher
As a preacher, you share your knowledge, impart what you learn and best practices that you put forward. You can share the places you like or dislike about go. Go meetings all over the world to find the closest to you.
You can be a preacher at any stage, and don't wait until you become an expert in this field to make your own voice. At any stage of your learning go, ask questions, combine your experience to give feedback, and don't be shy about making places you don't like. Your feedback can help the community improve the way it does things, and it may change your own view of programming.
Func Main () {httpaddr: = flag. String ("http", "127.0.0.1:3999", "HTTP service address (e.g., ' 127.0.0.1:3999 ')") OriginHost: = flag. String ("Orighost", "", "host component of the Web Origin URL (e.g., ' localhost ')") flag. Stringvar (&basepath, "base", "", "Base path for slide template and static resources") flag. Boolvar (&present. Playenabled, "Play", true, "Enable playground (permit execution of arbitrary user Code)") Nativeclient: = flag. Bool ("NaCl", False, "use Native Client environment Playground (prevents non-go code execution)") flag. Parse () if BasePath = = "" {p, err: = Build. Default.import (Basepkg, "", build. FINDONLY) If err! = Nil {fmt. fprintf (OS. Stderr, "couldn ' t find gopresent files:%v\n", err) fmt. fprintf (OS. Stderr, Basepathmessage, basepkg) os. Exit (1)} BasePath = P.dir} err: = Inittemplates (basepath) if err! = Nil {log. Fatalf ("Failed to parse Templates:%v", err)} ln, ERR: = Net. Listen ("TCP", *HTTPADDR) if err! = Nil {log. Fatal (ERR)} defer ln. Close () _, port, err: = Net. Splithostport (Ln. Addr (). String ()) if err! = Nil {log. Fatal (Err)} origin: = &url. Url{scheme: "http"} if *originhost! = "" {origin. Host = net. Joinhostport (*originhost, Port)} else if Ln. Addr (). (*net. TCPADDR). Ip. Isunspecified () {name, _: = OS. Hostname () origin. Host = net. Joinhostport (name, port)} else {reqhost, reqport, err: = Net. Splithostport (*HTTPADDR) if err! = Nil {log. Fatal (ERR)} if Reqport = = "0" {origin. Host = net. Joinhostport (Reqhost, Port)} else {origin. Host = *httpaddr}} if present. playenabled {if *nativeclient {socket. Runscripts = False socket. Environ = func () []string {if runtime. Goarch = = "AMD64" {return environ ("Goos=nacl", "Goarch=amd64p32 ")} return Environ (" Goos=nacl ")}} playscript (BasePath," Sock Ettransport ") http. Handle ("/socket", socket. Newhandler (Origin))} http. Handle ("/static/", http. Fileserver (http. Dir (BasePath))) if!ln. Addr (). (*net. TCPADDR). Ip. Isloopback () && present. playenabled &&!*nativeclient {log. Print (localhostwarning)} log. Printf ("Open your Web browser and visit%s", Origin. String ()) log. Fatal (http. Serve (ln, nil))}
View in context
Func Main in Golang/tools on✱sourcegraph
The main function of the popular present command is that many go users use it to make slideshows. Many of the speakers modified the module to suit their needs.
Q&a
Q: In the Go language, one of the features I miss is a good debugger.
A: We're doing, not just the debugger, but we'll also provide a better overall monitoring tool that will give you a better insight into what the program is doing when it runs (showing the state of all running goroutine). Explore it in Go 1.5.