I/O BootCamp 2011: Real World Go


Uploaded by GoogleDevelopers on 10.05.2011

Transcript:
>> GERRAND: My name is Andrew Gerrand and I work at Google Sydney and on the Go Team,
the Go Programming Language. Just before I get started, who here has heard of Go before?
And keep your hand up if you've actually seen some Go code or if you've written some Go
code. My colleague there is feverishly waving his hand. Cool. And other languages that you
guys use, who's--who writes Java codes typically and Python? JavaScript? Anything else? Just
yell something out. >> Scala.
>> GERRAND: Scala. Cool. >> Common Lisp.
>> GERRAND: Common Lisp. We got one real nerd here. That's right. Sorry. So in this talk
today called Real World Go, I'm going to introduce Go, talk about some of Go's interesting language
features and also discuss some real world applications in which Go is being used outside
of Google. And we do use it increasingly extensively within Google. But there's a lot of interesting
projects happening out there in the world as well. There is a system called SpeakerMeter
which we're using at Boot Camp in I/O to get feedback from people. That's the QI code you
can scan now, but I'm going to take it off the screen probably before you get a chance
to do so. I'll show it again at the end. It's just a good way of getting feedback back to
me so I can improve my speaking skills. So I'll just start with some background as to
the origins of Go, the why and what. So, why Go? It's a question I get asked pretty often.
Why create a new programming language? We have so many. Surely there's no need for another
one. Well, this was born basically out of frustration with the existing languages, the
mainstream languages that we had at our disposal. The statically typed languages, the dominant
ones like C++ and Java tend to be very efficient when they compile and run and they give you
a lot of control. But they're typically very bureaucratic. They can be verbose in use but--and
also overly complex. It can be difficult to understand exactly how the code you've--that
you've written will behave when you've written it and sometimes they can be very, very picky.
But on the other hand, we have these dynamic languages and scripting languages that are
really easy to use. But because they're dynamically typed, they can be very error-prone. A lot
of programmer errors that would be compiler errors in a statically typed language become
runtime errors in a dynamic language. And this means that you don't notice until you've
deployed your program but some obscure corner case triggers a colossal bug. They can also
be inefficient and slow. And when you start writing code at scale and particularly at
a kind of Google scale with many tens of thousands of programmers, they really start to breakdown
in terms of their ability to componentize and abstract things. And finally, we live
in this concurrent world where we have many, many network machines and multi-core machines.
But the traditional approach to writing concurrent software is tricky. It's--involves threads
and locks and you have to be very precise in your reasoning about those programs to
write correct concurrent programs. So, generally, the landscape looks like you had speed reliability
or simplicity and you had to pick two. And sometimes we only got to pick one and we thought,
"Well, can't we do better than this?" So, Go is a modern general purpose language. It
compiles to native machine code on a variety of architectures. It's statically typed, so
you get the reliability and efficiency benefits of statically typed language, but it has a
lightweight syntax. Using type inference, we can infer a lot of the typed information,
so you remove that repetition from defining types and such. It has a simple type system.
It's not a classical OO kind of model and so it's very easy to understand what's going
on and understand what your code does. And finally, it has some novel concurrency primitives
that make reasoning and writing--reasoning about and writing concurrent code a lot more
straightforward. So when we designed Go, the tenets of that design were, first and foremost,
simplicity. Each language feature should be easy to understand in and of itself. So you
should be able to understand all the rules associated with a particular feature and make--easily
make valid decisions about how that should behave. And going hand in hand in that is
orthogonality. Each of Go's features should, when they interact with the other features,
should interact in a predictable and consistent way, a way that's easy to understand and reason
about. And finally, readability. It's very important when working in a collaborative
environment that when you look at a piece of code, you should be able to understand
what that code does without having to have a huge amount of external context in your
mind in order to make sense of it. And driving all of this was a consensus driven design
process. Rob said that nothing went into the Go language until Ken Thompson, Robert Griesemer,
and Rob all agreed that it was right and it was correct. And as a result, there were some
language features that didn't--that were in discussion for over a year before they actually
made it into the language proper. And each of those three has a very--has different aesthetics,
very different opinions about languages. And so, the--in the end, the compromise is something
that's really solid and very, very well thought through. So this is one of the simplest possible
Go programs is just the "Hello, world." It has a package statement saying which package
the program belongs to. Every Go program starts in package main, the function main. We have
an input statement. The font package is a string formatting package. And our main function
simply cause the print line function from the string for main package to print "Hello,
world." And that, I think those are the Chinese characters for "world." They're just--the--we
use those characters to underscore that all Go source files, UTF-8, Unicode files, so
you can use Unicode in string literals and you can also use them in identifiers. So,
if you brought a mathematical formula, for example, you can use like a sigma character
to signify some value if you like. And this is Hello, world 2.0. So, if you run this program,
it starts a web server listening on port 8080 and if you visited that URL, you would see
the string "Hello, world." The difference between this and the previous slide is we've
added the HTTP package to the imports. And now we have defined a second function, handler,
which is an HTTP handler that simply writes the string "Hello" followed by the path component
of the URL as the HTTP response. And this--and in the main function, we register that handler
to the webroot and start the web server. So this is just to give an idea of the sort of
succinctness of Go code, how straightforward it is to accomplish something that's actually
quite complex under the hood. So let's take a look at Go's type system. So, I mentioned
Go is a statically type language but the type inference system that we have saves a lot
of repetition. Now this is a bit of a contrived example for Java, but in Java or in C or C++,
you need to say which type your variable is going to be and then you assign something
of that type to the variable. And so in Java's case, you say, "Integer i = new Integer(1)"
or "foo = new foo." In C+--C or C++, you have to say "int i = 1." But it's obvious in the
code that most of the time you just want an integer. So in Go, we can just say "i := 1"
to declare a new i which is an integer equal to one. If we use a floating point initializer,
then it'll be a float64 type and if we use a string, it'll be a string. And in this final
example, I've actually created a function value, mul, which multiplies two integers
and returns an integer. And the type will be inferred to be a function type that takes
two integers and returns an integer. So, this gives you an idea of the kind of shorthand
that you start to develop running Go code. In Go, we have--we defined methods on types.
And methods can be defined on any user defined type. In this case, I've defined a type called
Point which is a struct containing two values, x and y, both floats. And then I can declare
this method apps on point and it returns to float64, and all that does is return the absolute
value of that point. And then to create a point value, I have to say "p := Point" with
some initial values. And then I can take the app--call apps on that P in the same way you
would in Java or other languages like that. So it's kind of familiar. But when I say they
can be defined on any type, I mean like any type. It doesn't have to be a stuct. A struct
kind of looks like an object but this kind of underscores here, I if have my float which
is just a float64, I can define an abs method on that type and it just returns the absolute
value of that floating point value. And then I can create my float in the say way I did
with point and call abs on that. So what I'm trying to show here is that Go objects are
just values. There's no sort of box. There's--it's not a--it doesn't have to be a class. You
just define methods on bits of data. So it's a nice way of associating logic with data
but without the sort of the way overhead of establishing a class and building that kind
of hierarchy. So, in order to generalize Go types, in order to make them interact nicely
with each other, we have Go's concept of interfaces. And interfaces simply specify the behaviors
of types. So, when you define an interface type; you define a set of methods and often,
it's just one or two methods. I think the largest go interface I have seen has maybe
four or five. And any type that implements those methods will implement that interface
implicitly. So if I have some function PrintAbs which types an Abser, which is any type that
implements Abs, I can pass in a value of type MyFloat or a point to that function. And at
no point did the--either of those types have to be aware of the Abser interface. They don't
have to declare that they implement the Abser interface. They just do, simply because they
declare the Abs method. And this--to give you a concrete example of this in the IO package
in the standard library, we declare a interface type called Writer. And writers are used to
write streams of binary data to things and they--it's just one method called Write which
takes a buffer or a slice of bytes or an array of bytes and returns the number of bytes written
and an error value. But there are many, many writers throughout the standard library and
in other Go code and then you can use those writers anywhere where a writer is expected.
And we've already seen an example of this in the Hello World 2.0 example. In our HTTP
handler, we have an Fprint statement and Fprint writes the string to W. W is a response writer,
it's our HTTP response. And the reason why this works is because Fprint expects an IO
writer and HTTP response writer implements the write method. Now, at no point does the
fmt package need to be aware of the HTTP package. It just works because that interface is implemented
implicitly and there's examples of this everywhere. I mean, you can just as easily, say, encode
an image to a writer or you can--internally in the HTTP handler, we have like, if you--if
you're writing GZIPed HTTP request, you can just chain these writers to write from this
response writer to a GZIP writer to the network connection itself that sends the response
to the user. So this becomes very, very powerful once you're coding at scale and it really
helps to decouple pieces of code and make them independent of each other and very easy
to mix and match. And now a bit about Go's concurrency features. Who is familiar with
UNIX environments? It's the world, isn't it? In UNIX we think about processes that are
connected by pipes. If I wanted to find all of the number of lines of test code in the
Go standard library, I could issue a find to find all the file names in the Go package
tree, grep them for file sending in test and then pipe that into a word count and get the
number of lines. Each of these tools is a simple tool designed to do one thing and to
do it well. And this is--this is the UNIX philosophy, right? And so we have standard
interface between each of those and then they can just be connected indiscriminately. The
analogue in Go is that you have goroutines that are connected by channels. So what's
a goroutine? A goroutine is like a thread. They share memory like a typical threading
environment, but they're much cheaper than threads. Goroutines have segmented stats which
means that they can be created in only a few kilobytes so they're very, very cheap to create
and destroy. And the go runtime typically schedules many of these goroutines across
a fewer number of operating system threads, often only a handful. It's possible to have
thousands or tens of thousands of goroutines running in a program that is essentially single-threaded.
So the syntax to launch a goroutine is using the Go keyword. If I had some function Sort
that takes a list and sorts it, I could choose a pivot i and then sort each part of that
list in separate goroutines by saying go sort which calls the sort function in a new goroutine.
The other part of go's concurrency model are channels. Channels are a typed conduit for
synchronization and communication. So, a channel can send or receive any go type. So unlike
UNIX pipes which are simply binary data, channels are typed. And the way you use a channel is
with the channel operator which is a "<-". It looks like an arrow and you use that to send
and receive values through a channel and the data moves in the direction of the arrow.
So in this compute function here, compute takes a channel of integers called CH and
then it will call the function some computation and send the result of that function to the
channel CH. And then in the main function, we can create a channel of integers using
the make function, store that in CH, launch a goroutine that calls compute. And so the
compute will go off and run this function, send the resulting value on CH. Meanwhile,
in my main function, in the main goroutine, I receive a value from that channel and store
it in result and then later, I can do something with that result. So to give a better example
of synchronization, let's look back at the sort example. I had these two goroutines that
have gone off and are sorting this list, each take a part of the list to sort. But then
how do I know when they are finished? I can use a channel to synchronize those goroutines
so that I can find out when they're both finished and therefore, when the list is sorted. So
in this example, I created channel done which is just a channel of Boolean values. It could
be a channel of any kind of values. What I'm interested in is the message that something
has happened, not the value itself. And then I create a doSort closure. So Go has closures,
it encloses the done channel. And doSort takes a slice, S, sorts that slice, and when it's
finished, it just sends the value true to that channel. It could be false, it doesn't
matter what the value actually is. And then back in the main goroutine, I choose the pivot
and actually launch two new goroutines that do that sort. And then after they're done,
I just receive two values from the done channel. After I've received both of those values,
I know that both the sort operations are completed and so I can continue on with the code. And
this works because unbuffered channel operations are synchronous and they only happen when
the sending side and the receiving side are both ready to make the operation happen. So,
slightly more concrete example of communication. In a typical sort of threading model, you
might have many workers that feed from a task pool and in a traditional sense you would
have worker threads contending over some lock for a pool of work. And so it doesn't matter
if you don't really understand what this code means precisely, but basically we have this
pool which has a Mutex in it and a list of tasks. And then if I have some worker function
and if many of those are running concurrently, if they want to get a new piece of work, they
have to take that lock, they have to pick the next task out of the pool, and then they
have to adjust the pools length, and then release the lock, and then they can process
the task. So already my function is--my worker function is more concerned with dealing with
the concurrency model than it is in actually doing the work which is--we think is the wrong
way to think about it. In Go, a more idiomatic way to do this in Go would be to have many
worker goroutines that just receive tasks from a channel and then they send the tasks
to another channel when they're done. So in this case, I have a worker function, many
of which will be running and set with their own goroutines, and then they just loop forever,
receiving work from an in channel and processing it and then sending work to an out channel.
And so in my main function, I create two channels: pending and done. And then I launch some goroutine
to create work somewhere and that would just send work on the pending channel. And then
I launch 10 workers to receive work from the pending channel, work on it and send it to
done. And then I've launched function consumeWork to just consume the work that's actually being
completed. And so in this sense, all we're looking at here is--the only code on the screen
is code that's actually concerned with doing what we want to do. We don't have to think
about locks, we don't have to think about contention or anything like that. It's simply
the code required to express the problem and that's the real elegance of the system. So
goroutines, they give you the efficiency of an asynchronous model of like an event-driven
model, except you can write code in asynchronous style. You just write goroutines to do their
specific jobs well, to think about their specific problem and then you connect them together
with channels. And in practice, this yields much, much simpler code and much more maintainable
code because it's a lot easier to reason about a single goroutine or a single function which
has a specific job to do. And so, Go encourage you to think--encourages you to think about
the concurrency--the concurrency issues that actually matter. And our sort of mantra is
don't communicate by sharing memory. Instead, you can share memory by communicating about
that memory. Another really nice thing about Go is it has quite a rich standard library
and it's very carefully constructed and consistent. And so we have more than 150 packages in the
standard library and it's constantly under development. It's practically improving everyday,
literally improving probably every couple of days with a huge amount of progress being
made in this regard, which is great. And beyond the standard library, we also have more than
200 packages listed on our package dashboard with like, MySQL, MongoDB, other database
drivers, SDL bindings for doing graphics and audio, protocol buffers for communicating
across networks, and OAuth libraries for interacting with foreign systems and APIs. Now, let's
quickly give you a glance at the Go center library. So this is the list of the standard
library about archivers, compression, Kryptos, a lot of Krypto actually, encodings, X11,
packages for reading Go code, HTPP, and so on and so on. And this is the package dashboard
which lists recent installs of packages, Go packages by third parties. And so you can
see there's a huge amount of activity going on there. So it's very much an ecosystem that's
thriving and alive and well. So now, for the sort of second part, what is Go actually good
for? Well, when we launched Go, we called it a "Systems language" which was probably
a bit misleading. We originally thought it would be ever--it would be a good replacement
language for the kind of things we were using C++ and Java for at Google. But it turned
out that there was a lot of interest from people in the dynamic languages camps. There
are a lot of people frustrated by the scripting languages that we're using and they were enticed
by an easy-to-use, reliable language that performs well. And so we've seen a lot of
diverse uses of Go from around the world in scientific computing, web applications, graphics,
network tools, and much more. More than I can enumerate here. And so now we just call
Go a "General-purpose language." So let's look at our real world examples. The first
example I want to look at is Heroku. Who's heard of Heroku, anyone? They are a cloud
hosting company for Ruby programmers. And two guys there, Keith and Blake, were designing
a "distributed init system" for their--for their cluster of virtual machines and they
needed it to manage processors across this speed fleet in a way that it could recover
gracefully from instance failures, network partitions and so on. And so they needed a
way to reliably synchronize and share information among those servers in a way that is consistent.
And so they wrote something called Doozer. So Doozer is a basis for building distributed
systems. It's a highly available consistent data store and what it does is it provides
a single fundamental synchronization primitive called compare-and-set which can be used as
the basis for building any kind of synchronization operation. And indeed, in Go's memory model,
we used compare-and-set internally to implement that. But this is compare-and-set over a network
and so, it can be used for a whole range of things. They say that Doozer is where you
put the family jewels and one typical example of a system like this is in database master
election. So imagine you have a master--database master and several slaves. If the master goes
away and just disappears, what do the slaves do? They can use Doozer to decide who gets
to be the next master or similarly, if you have, say, a cluster environment which is
high performance and needs to be readily available; you can use Doozer as a name service. You
could use DNS but then there's propagation delays and other issues associated with that.
Using Doozer instead, you can just push all of your name information to there and then
you know that every node in your network is seeing the same information at the same time
in a way that is available and consistent. And the same goes for configuration. They
push a lot of their configuration data into Doozer and they--and that means that all of
the servers know the state of the system simultaneously. They know what they're supposed to be doing
and it--they can rely on that to be true. So why did they choose Go to do this? Well,
first and foremost, Go's concurrency primitives suit the problem. Doozer uses a product called
Paxos to achieve the consensus between nodes. And Paxos is a very, very complicated distributed
algorithm that is described in terms of separate entities that communicate by sending messages
asynchronously. And it's very, very hard to get this right. There are a lot of implementations
out there and many of the example implementations used to educate people about Paxos are full
of errors. But they found that Goroutines and channels actually made it manageable or
even easy to implement Paxos. So that's probably too strong a word; it's still hard. But they
said that in--this is a quote from them on the Go blog that they write for us a couple
of weeks ago and they said that, "In the same way that garbage collectors improve upon malloc
and free, we found that goroutines and channels improve upon lock-based approach to concurrency.
These tools let us avoid complex bookkeeping and stay focused on the problem at hand. We
are still amazed at how few lines of code it took to achieve something renowned for
being so difficult." So that's quite a testimonial. They also found Go convenient. Through it's
standard library, they were able to implement a web-based administration console for Doozer
in literally a train ride. And so they said this is a real testament to how well Go mixes
systems and applications programming. And finally they said that Go has a mechanical
source formatter called gofnt, and which is used to make all Go code look the same and
settle any syntax disputes. And they found that they never argued over where to put a
curly-brace, tabs versus spaces, or if we should align assignments. Who's had an argument
with a colleague about syntax issues? Seriously. I know I have, but I haven't since I've started
running Go code. They just simply agreed that the buck stopped at the output of gofnt which
is great. My next example comes from New Zealand from a company called "MROffice." And one
man, Kees Varekamp, had a background in market research software but he found most of the
existing software in that space to be pretty lacking. So he launched his company MROffice
in 2010 to make better software for this industry. And the flagship product he designed is called
"Dialer." And what it does is, in a call center environment, you have many interviewers who
are called calling people to perform interviews and they have interview software that provides
scripts for those interviews and collects statistics. And they have a VoIP gateway for
actually making the telephony calls. But they needed some--Dialer solves the problem of
choosing numbers to call and calling them such that no interviewer is waiting for people
to pickup and such that no interviewee is being kept on hold before an interviewer arrives.
It's actually quite a difficult problem and one that he seems to have solved well. So
originally he wrote Dialer in Python. And he said, "I love Python," and uses it for
everything but he found that long-running server processes are not--it's not such a
good choice for those. There's a lot--he was getting lots of runtime errors that could
have been caught during compile time. And he said, "When Go came out, it would immediately
made sense to me, it was type safe, compiled, and feels like a scripting language." So he
ported his code base to Go and it worked for him because he found that the concurrency
model really suited the problem he was having. If you have a Go routine to handle each call,
each interviewer, and each interviewee, and goroutines to connect those together, you
can then they--and communicate together via channels. It greatly simplified the problem.
And he also found that the HTTP and websocket libraries made it really easy for him to just
throw together a management user interface. So, he has this beta product now running in
multiple core call centers around the world. And he's also working on a predictive Dialer
design using neural networks and pushing the features even further. And his conclusions
about Go is he found the tutorials and documentation were excellent. And he said, "I've been converted
to statistically typed languages," which I think is one of the nicest testimonials I've
heard about Go. And he says that, "Go is a good compromise for cooperation between type
purists and lazy scripters." And I think he was describing himself as a lazy scripter.
My next example is from a company called "Atlassian." Atlassian make development and collaboration
tools for the developers. They're as a worldwide company and they mostly develop in Java. But
they have this testing cluster of virtual machines which they use to test all their
software across and they run in a large number of this diskless hosts. And it has a provisioning
and monitoring system that's written in Go. And so that system consists of three parts;
there's an agent that runs on each virtual machine and it monitors the state of the virtual
machine; broadcasting that stayed across the land. A manager process that listens to those
agents broadcasts and then takes some action if the virtual machine fails to report. And
a command line tool for issuing commands to the manager process. So the agent itself is
trivial. It just sits there looping endlessly reading its state from the proc virtual file
system, encoding that state in a protocol buffer, and broadcasting it out across the
network. And then the manager process, when it starts up it reads a configuration file,
launches the goroutine. One goroutine for each Virtual Machine in the cluster and each
of those goroutine's just listens for those announcements from the agent. And if it fails
to check in, it will issue instructions usually via shell commands to keep that machine in
the correct state. And so this is a kind of diagram of how that works. We have physical
machines which each have VMs which each have Agents. And each of those Agents corresponds
to a goroutine running in a single manager process. So he--Dave Cheney who wrote this
found it really easy to deploy and ship binaries using Go because Go binaries are all statically
linked and have no dependencies. And so, he just was able to push out these binaries to
these diskless hosts and he found it much easier compared to shipping a JVM or a Python
runtime. And he also found that the one goroutine per Virtual Machine made the problem really
easy to approach. And he said it was trivial in Go but really painful in other languages
that he tried. So my next example and final example is a system called Camlistore which
is written by Brad Fitzpatrick and he wanted to store his data across all of his devices
and to share that data with his friends and the public, and it really is that general.
He wanted to make a system for storing all data and sharing it with anyone. And so, at
its core, Camlistore is a content-addressable data store which means that all content in
the system is identified by a hash of its content. It's a synchronization and access-control
mechanism for that data across data stores. It's an application programming interface
for people that want to interact with the system. It has a user interface. It is considered
your 'home directory for the web' and finally, it's programming language-agnostic. It's not
Go specific, except the largest parts of it are written in Go. So use cases with Camlistore,
say, personal backups which you can automatically synchronize to various cloud files service--file
hosting services or other systems in other places as--or a drop box style file synchronization
mechanism for synchronizing your working data across machines. You an use it for photo management
and sharing. There's an Android app so that if you take a photo, it can automatically
get pushed out to your Camlistore and shared with anybody who has access rights to your
photos. And you can also use it for website content management. So if you want to push
objects into there and have them served out over HTTP; that will work as well. So the
Go parts of Camlistore are the Camlistore daemon which is the blobserver in itself.
The thing that stores all the data and HTTP server for interacting with Camlistore clients
if I have a Camlistore API; a user interface for users and administrators; and also some
command-line tools. Camput and camget for interacting with the data store, camsync for
synchronizing data stores, and probably the most interesting example is cammount which
is a FUSE file system like user line filesystem which you can use to access data directly
from a Camlistore blob server. It also includes about two dozen as sort of libraries which
he wrote in the process of building Camlistore. And each of those libraries is not just something
that's tied inherently through Camlistore proper. It's something that--they're all little
pieces that you can pull out and use in other pieces of software and--which he has done
and others have done. And so, why did he choose to write it in Go? Well, this is a kind of--this
is the nicest Go testimonial I've seen. He said, "I've been running Go for over a year
now and it makes me giddy about programming again. Annoying things that aren't annoying,
trade-offs that I normally worry about I no longer worry about. I bust out lots of fast,
correct, maintainable testable code in very small amounts of time," and he hasn't been
this excited about a language in ages. I asked him how long it took him to write Cammount,
the FUSE file system thing and he just said, "Oh, two or three beers." Like literally,
it's that productive a language. And we also asked, you know, "Why didn't you write Camlistore
before?" He said, "Well, I have the idea for a very long time but it wasn't until I got
familiar with Go that I felt that it was actually possible. It just always had seemed too painful
before then." So in this presentation, I've shown four examples of Go being used in very
different ways. We have this rock-solid systems programming language in Doozer. We have Go
being used for simple and reliable applications programming in Dialer. We've seen just simple
utility programming, utilizing Go's concurrency support at Atlassian. And with Camlistore,
we've seen a "full stack" programming happening from data store to user interface, Go has
been more than capable of all of these things. So one thing I haven't mentioned so far is
that Go is Open Source. It began at Google in 2007 as a 20% project and was --but in
November 2009, we released it under the BSD license, so it's totally free. Since its release,
more than 130 non-Google contributors have submitted over 1,000 changes to the Go core.
And so there's a huge community involvement in developing Go. About 10 Go employees work--Google
employees work on Go full-time. And we have two non-Google committers, those are people
who can commit straight to the Go core and dozens of regular contributors, people who
write code for us every week. So all of Go development takes place on public mailing
lists. All that code reviews, and all that prices is fully visible to the outside world.
And I invite you now, if this kind of thing interests you, to get involved. We're very
open to new contributors. We have a lot of documentation for getting started working
with the Go core and we welcome anybody who wants to contribute to our project. So, I've
only really scratched the surface about what Go is about here. There is a lot more to it
still and you can learn a lot more about Go at I/O today, and tomorrow, and the next day.
This afternoon, I'm taking a workshop called "Get Started with Go" which will be a hands-on--getting
started with the Go language and I'm doing that twice. There's two sessions, one and
a repeat. And tomorrow, Rob Pike and I will be giving a talk called "Writing web apps
in Go." I strongly encourage you to come along to that. There'll be surprises, there will
be course schwag. And at office hours from 12:00 to 3:00 at I/O on both days, you can
meet with some of the Go team and have all of your questions answered. And if you're
interested in pursuing this further now, I strongly encourage you to visit our website
or our official blog. There's a huge wealth of information there and a lot of articles
and a lot of informative stuff to get you started. So, does anybody have any questions?
>> Where is Go being used inside Google? >> GERRAND: The question was where is Go being
used inside Google. Unfortunately, I can't answer that question, but I can say that it
is being used in a lot of places for a variety of purposes. But I can say that one place
where it has seen a lot of adoption is in the operations kind of tasks where you have
people who administer large systems who typically write--would write scripts to do things across
a vast number of machines. They can now do this in Go and they find it a lot more of--a
much more efficient language than what they have been using before. Anything else? Yeah.
>> Is anyone using Go for embedded programming and what's the state of the arm compiler?
>> GERRAND: The question was "Is anybody using Go for embedded programming and what's the
state of the arm compiler?" I'm not--I'm not aware of anybody using it for embedded proper.
I know a while ago somebody was--the guy who started the arm port over a year ago did so
because he wanted to run it on a small embedded device to drive one of those 3D milling machines.
So, I know that's happened but I haven't heard much about that since. But we've been--the
Go compiler is mature and it is stable and we've tracked the build status of it, and
we run builders on the Nexus One phones. So, it runs on where Android will run. And it--you
know, I can imagine it will be able to power Android applications at some point, but it's
a matter of doing the heavy lifting involved in building the interfaces to do that. But
we're very, very committed to arm as a platform. It's certainly not a second class citizen.
We've invested a huge amount of time in making our arm compiler really mature and the code
generation really efficient. Yup. >> Why is there a--what's the use of the distinction
between the new and make keywords? >> GERRAND: The question was what's the distinction
between the new and make keywords? I don't think I showed new in this talk. But I may
have. >> You made channels.
>> GERRAND: Yeah, so, make is for initializing internal Go data structures like maps or slices
or channels, and new is for initializing instances of user defined types or built-in types. New
just initialize--it allocates the memory and returns to the point of that memory and that's
all it does. But make actually does something more than just allocating. Yeah.
>> Is there common pitfalls that you see with the people trying Go, starting from C++ or
Java? >> GERRAND: The question is, "Are there common
pitfalls to people starting from C++ or Java who'd get in to Go?" The most common pitfall
is people tend to bring with them a whole lot of patents that they inherit from these
sort of traditional object oriented languages. And as I mentioned, Go doesn't have classes.
It doesn't encourage you to use subtype inheritance and there is something that's like inheritance
but it's much less far reaching. And really, I think the biggest hurdle is that people
have to say--people often come to our mailing list and say, you know, "How do I setup this
particular type hierarchy?" And the answer is, "Well, don't do that." But the more polite
answer is, well, what is the problem you're actually trying to solve? Like, maybe if you--and
so once we find that once people sort of described the bigger picture of what they're trying
to do, there tends to be a more elegant and idiomatic way of doing that in Go. So I think,
you know, as with learning all new things, there's always a process of unlearning involved
as well. And I think that's actually one of the things I've enjoyed the most about learning
Go has been reevaluating a lot of the things that I had considered a given about programming.
A lot of that stuff has actually turned out to be not very important at all. Yeah.
>> [INDISTINCT]. >> GERRAND: Uh-hmm.
>> When we talk about the new [INDISTINCT]. >> GERRAND: So, the questions was I showed
some locks in my code and when would I choose to use explicit locking versus using channels.
So, basically you just use whichever is easiest, whichever is clearest. Sometimes using a lock
is the most elegant way to express a particular thing. The classical example in Go is when
you have some shared data structure that you want to protect from synchronous access from--sorry,
from concurrent access. Like--and in that case, you could setup a Go routine that manages
that structure and send it instructions via channels to update or retrieve values from
that--from that data structure. But often, it's actually easier to just create a lock
for that data structure and do it in a typical way. But Go sort of gives you the freedom
to either use channels where they're appropriate or use locks where they're appropriate. There's
no sort of prescriptiveness there in the language. Yeah.
>> You could send the channels via channels. What's the practical application?
>> GERRAND: So the question was you can send channels via channels and what's the practical
application of this. So, a common application of this is you--if you--it's a pattern where
you have some kind of multiplexer that, say, receives messages on a channel and then wants
to send it out over a variety of channels or a range of channels to various goroutines.
And in--in that situation, if a goroutine wants to be included in that multiplexer,
it will actually send the channel to the multiplexer and the multiplexer will add it to its list
of channels it should be sending things to. So in that way, you can kind of register with
some goroutine and then be associated with it. And another one is you can create a data
structure that includes a function value and a channel, send it to some other Goroutine
which executes the function and then sends the result of that function call back down
the channel to the caller. So it's kind of--I always kind of envision it as like, you sort
of coil up a rope and like throw the other end to somebody actually down a channel and
then they'd pass things back to you that way. So, there's some really cool things that you
can do once you sort of start getting into the details of it. It's a good question. Anybody
else? No. Yeah. >> [INDISTINCT].
>> GERRAND: The question was what's the preferred text data for writing Go. The answer is that
we have decidedly agnostic on this front. I use Vim. I know some of the other guys on
the team use some more esoteric editors. We have eMax users. There are people who use
the clips, people who use Xcode. In the Go distribution, there is a misc folder which
has editor support for a variety of editors. And we're always keen to have people submit
support for other editors as well. I know for Eclipse there is actually a project called
Go Eclipse which extends their support for writing Go in Eclipse further. But I'm not
an Eclipse user so I don't know a hell of a lot about that but.
>> [INDISTINCT]. >> GERRAND: So the statement was doesn't that
make that hard for debugging things if you can't step through things? But we don't--we
don't have really a solid IDE integration in terms of debugging. But in the last few
months we've really improved our support for GDB, like a new debugger. And if you have
an editor that's GDB aware, then that should be able to interact pretty well with--that
should be able to debug Go programs pretty well. But this is definitely something that
we are looking to improve even further. And sort of on the roadmap is a dedicated Go debugger
that we would endeavor to integrate with as many environments as we could. Yeah.
>> What was your background prior to that? >> GERRAND: My background was in applications
programming and systems programming. I used to work for a web startup before I started
at Google, in which I wrote a lot of--a variety of code from front-end to back-end, to--we
did a large data mining system. And before that, I worked for internet providers, building
applications for them. Anybody else? No? Who's coming to my workshop this afternoon? Hey,
victory. Great. I'll see you all there. Thank you.