Text file talks/2012/chat.slide

     1  Go: code that grows with grace
     2  
     3  Andrew Gerrand
     4  Google Sydney
     5  http://andrewgerrand.com
     6  @enneff
     7  https://go.dev
     8  
     9  * Video
    10  
    11  A video of this talk was recorded at Øredev in Malmö, Sweden in November 2012.
    12  
    13  .link http://vimeo.com/53221560 Watch the talk on Vimeo
    14  
    15  * Go
    16  
    17  You may have heard of Go.
    18  
    19  It's my favorite language. I think you'll like it, too.
    20  
    21  * What is Go?
    22  
    23  An open source (BSD licensed) project:
    24  
    25  - Language specification,
    26  - Small runtime (garbage collector, scheduler, etc),
    27  - Two compilers (`gc` and `gccgo`),
    28  - 'Batteries included' standard library,
    29  - Tools (build, fetch, test, document, profile, format),
    30  - Documentation.
    31  
    32  As of September 2012 we have more than 300 contributors.
    33  
    34  * Go is about composition
    35  
    36  Go is Object Oriented, but not in the usual way.
    37  
    38  - no classes (methods may be declared on any type)
    39  - no subtype inheritance
    40  - interfaces are satisfied implicitly (structural typing)
    41  
    42  The result: simple pieces connected by small interfaces.
    43  
    44  * Go is about concurrency
    45  
    46  Go provides CSP-like concurrency primitives.
    47  
    48  - lightweight threads (goroutines)
    49  - typed thread-safe communication and synchronization (channels)
    50  
    51  The result: comprehensible concurrent code.
    52  
    53  * Go is about gophers
    54  
    55  .image chat/gophers.jpg
    56  
    57  * Core values
    58  
    59  Go is about composition, concurrency, and gophers.
    60  
    61  Keep that in mind.
    62  
    63  * Hello, go
    64  
    65  .play chat/support/hello.go
    66  
    67  * Hello, net
    68  
    69  .play chat/support/hello-net.go
    70  
    71  * Interfaces
    72  
    73  Hey neato! We just used `Fprintln` to write to a net connection.
    74  
    75  That's because a `Fprintln` writes to an `io.Writer`, and `net.Conn` is an `io.Writer`.
    76  
    77  .code chat/support/hello-net.go /Fprintln/
    78  .code chat/support/defs.go /Fprintln/
    79  .code chat/support/defs.go /type.Writer/,/^}/
    80  .code chat/support/defs.go /type.Conn/,/^}/
    81  
    82  * An echo server
    83  
    84  .play chat/support/echo-no-concurrency.go
    85  
    86  * A closer look at io.Copy
    87  
    88  .code chat/support/echo-no-concurrency.go /Copy/
    89  .code chat/support/defs.go /Copy/,/func/
    90  .code chat/support/defs.go /type.Conn/,/^}/
    91  .code chat/support/defs.go /type.Writer/,/^}/
    92  .code chat/support/defs.go /type.Reader/,/^}/
    93  
    94  * Goroutines
    95  
    96  Goroutines are lightweight threads that are managed by the Go runtime. To run a function in a new goroutine, just put `"go"` before the function call.
    97  
    98  .play chat/support/goroutines.go
    99  
   100  * A concurrent echo server
   101  
   102  .play chat/support/echo.go
   103  
   104  * "Chat roulette"
   105  
   106  In this talk we'll look at a simple program, based on the popular "chat roulette" site.
   107  
   108  In short:
   109  
   110  - a user connects,
   111  - another user connects,
   112  - everything one user types is sent to the other.
   113  
   114  * Design
   115  
   116  The chat program is similar to the echo program. With echo, we copy a connection's incoming data back to the same connection.
   117  
   118  For chat, we must copy the incoming data from one user's connection to another's.
   119  
   120  Copying the data is easy. As in real life, the hard part is matching one partner with another.
   121  
   122  * Design diagram
   123  
   124  .image chat/diagrams.png
   125  
   126  * Channels
   127  
   128  Goroutines communicate via channels. A channel is a typed conduit that may be synchronous (unbuffered) or asynchronous (buffered).
   129  
   130  .play chat/support/chan.go
   131  
   132  * Select
   133  
   134  A select statement is like a switch, but it selects over channel operations (and chooses exactly one of them).
   135  
   136  .play chat/support/select.go
   137  
   138  * Modifying echo to create chat
   139  
   140  In the accept loop, we replace the call to `io.Copy`:
   141  
   142  .code chat/support/echo.go /for {/,/\n	}/
   143  
   144  with a call to a new function, `match`:
   145  
   146  .code chat/tcp-simple/chat.go /for {/,/\n	}/
   147  
   148  * The matcher
   149  
   150  The `match` function simultaneously tries to send and receive a connection on a channel.
   151  
   152  - If the send succeeds, the connection has been handed off to another goroutine, so the function exits and the goroutine shuts down.
   153  - If the receive succeeds, a connection has been received from another goroutine. The current goroutine then has two connections, so it starts a chat session between them.
   154  
   155  .code chat/tcp-simple/chat.go /var.partner/,/^}/
   156  
   157  * The conversation
   158  
   159  The chat function sends a greeting to each connection and then copies data from one to the other, and vice versa.
   160  
   161  Notice that it launches another goroutine so that the copy operations may happen concurrently.
   162  
   163  .code chat/tcp-simple/chat.go /func.chat/,/^}/
   164  
   165  * Demo
   166  
   167  * Error handling
   168  
   169  It's important to clean up when the conversation is over. To do this we send the error value from each `io.Copy` call to a channel, log any non-nil errors, and close both connections.
   170  
   171  .code chat/tcp/chat.go /func.chat/,/^}/
   172  .code chat/tcp/chat.go /func.cp/,/^}/
   173  
   174  * Demo
   175  
   176  * Taking it to the web
   177  
   178  "Cute program," you say, "But who wants to chat over a raw TCP connection?"
   179  
   180  Good point. Let's modernize it by turning it a web application.
   181  
   182  Instead of TCP sockets, we'll use websockets.
   183  
   184  We'll serve the user interface with Go's standard `net/http` package, and websocket support is provided by the `websocket` package from the `go.net` sub-repository,
   185  
   186  * Hello, web
   187  
   188  .play chat/support/hello-web.go
   189  
   190  * Hello, WebSocket
   191  
   192  .code chat/support/websocket.js
   193  .play chat/support/websocket.go
   194  
   195  * Using the http and websocket packages
   196  
   197  .code chat/http/chat.go /package/,/^}/
   198  
   199  * Serving the HTML and JavaScript
   200  
   201  .code chat/http/html.go /import/
   202  .code chat/http/html.go /func/,/<script>/
   203  .code chat/http/html.go /websocket.=/,/onClose/
   204  .code chat/http/html.go /<\/html>/,$
   205  
   206  * Adding a socket type
   207  
   208  We can't just use a `websocket.Conn` instead of the `net.Conn`, because a `websocket.Conn` is held open by its handler function. Here we use a channel to keep the handler running until the socket's `Close` method is called.
   209  
   210  .code chat/http-noembed/chat.go /type.socket/,/END/
   211  
   212  * Struct embedding
   213  
   214  Go supports a kind of "mix-in" functionality with a feature known as "struct embedding". The embedding struct delegates calls to the embedded type's methods.
   215  
   216  .play chat/support/embed.go /type/,$
   217  
   218  * Embedding the websocket connection
   219  
   220  By embedding the `*websocket.Conn` as an `io.ReadWriter`, we can drop the explicit `socket` `Read` and `Write` methods.
   221  
   222  .code chat/http/chat.go /type.socket/,/END/
   223  
   224  * Demo
   225  
   226  * Relieving loneliness
   227  
   228  What if you connect, but there's noone there?
   229  
   230  Wouldn't it be nice if we could synthesize a chat partner?
   231  
   232  Let's do it.
   233  
   234  * Generating text with markov chains
   235  
   236  .code chat/support/markov.txt
   237  
   238  * Generating text with markov chains
   239  
   240  Fortunately, the Go docs include a markov chain implementation:
   241  
   242  .link /doc/codewalk/markov go.dev/doc/codewalk/markov
   243  
   244  We'll use a version that has been modified to be safe for concurrent use.
   245  
   246  .code chat/markov/markov.go /Chain/,/{/
   247  .code chat/markov/markov.go /Write/,/{/
   248  .code chat/markov/markov.go /Generate/,/{/
   249  
   250  * Feeding the chain
   251  
   252  We will use all text that enters the system to build the markov chains.
   253  To do this we split the socket's `ReadWriter` into a `Reader` and a `Writer`,
   254  and feed all incoming data to the `Chain` instance.
   255  
   256  .code chat/markov/chat.go /type.socket/,/^}/
   257  .code chat/markov/chat.go /var.chain/,/^}/
   258  
   259  * The markov bot
   260  
   261  .code chat/markov/chat.go /\/\/.Bot/,/^}/
   262  .code chat/markov/chat.go /type.bot/,/^}/
   263  .code chat/markov/chat.go /func.+bot.+Write/,/^}/
   264  .code chat/markov/chat.go /func.+bot.+speak/,/^}/
   265  
   266  * Integrating the markov bot
   267  
   268  The bot should jump in if a real partner doesn't join.
   269  To do this, we add a case to the select that triggers after 5 seconds, starting a chat between the user's socket and a bot.
   270  
   271  .code chat/markov/chat.go /func.match/,/^}/
   272  
   273  The `chat` function remains untouched.
   274  
   275  * Demo
   276  
   277  * One more thing
   278  
   279  * TCP and HTTP at the same time
   280  
   281  .code chat/both/chat.go /func main/,/^}/
   282  .code chat/both/chat.go /func netListen/,/^}/
   283  
   284  * Demo
   285  
   286  * Discussion
   287  
   288  * Further reading
   289  
   290  All about Go:
   291  
   292  .link / go.dev
   293  
   294  The slides for this talk:
   295  
   296  .link /talks/2012/chat.slide go.dev/talks/2012/chat.slide
   297  
   298  "Go Concurrency Patterns" by Rob Pike:
   299  
   300  .link /s/concurrency-patterns go.dev/s/concurrency-patterns
   301  

View as plain text