This presentation was given as a Workshop at OSCON 2014.
New to Go? This tutorial will give developers an introduction and practical
experience in building applications with the Go language. Gopher Steve Francia,
Author of [Hugo](http://hugo.spf13.com),
[Cobra](http://github.com/spf13/cobra), and many other popular Go packages
breaks it down step by step as you build your own full featured Go application.
Starting with an introduction to the Go language. He then reviews the fantastic
go tools available. With our environment ready we will learn by doing. The
remainder of the time will be dedicated to building a working go web and cli
application. Through our application development experience we will introduce
key features, libraries and best practices of using Go.
This tutorial is designed with developers in mind. Prior experience with any of the
following languages: ruby, perl, java, c#, javascript, php, node.js, or python
is preferred. We will be using the MongoDB database as a backend for our
application.
We will be using/learning a variety of libraries including:
* bytes and strings
* templates
* net/http
* io, fmt, errors
* cobra
* mgo
* Gin
* Go.Rice
* Cobra
* Viper
4. My Go Story
•I write a medium size blog
•Frustrated with Wordpress performance & maintenance
•Existing Static Site Generators had complicated installations &
were very slow
•Began writing a S.S.G. in Go called Hugo 1.5 years ago
4
6. Hugo
•Hugo is 2nd fastest growing Static Site Generator
(40-50 * a week on github)
•Hugo is one of the fastest Static Site Generators.
1000x faster than Jekyll
•Easiest Installation of any SSG. Download and run
•2nd most contributors of any Go project (Docker 1st)6
9. Ground Rules
•Workshops are hard, everyone works at a
different pace
•We will move on when about 50% are ready
•Slides are online, feel free to work ahead or
catch up 9
15. Why Another Language?
• Software is slow
• Sofware is hard to write
• Software doesn’t scale well
15
16. Go is Fast
• Go execution speed is close to C
• Go compile time rivals dynamic
interpretation
16
17. Go is Friendly
• Feels like a dynamic language in many ways
• Very small core language, easy to remember all of
it
• Single binary installation, no dependencies
• Extensive Tooling & StdLib 17
18. Go is Concurrent
• Concurrency is part of the language
• Any function can become a goroutine
• Goroutines run concurrently, communicate through
channels
• Select waits for communication on any of a set of
channels 18
19. Go’s Inspiration
•C: statement and expression syntax
•Pascal: declaration syntax
•Modula 2, Oberon 2: packages
•CSP, Occam, Newsqueak, Limbo, Alef: concurrency
•BCPL: the semicolon rule
•Smalltalk: methods
•Newsqueak: <-, :=
•APL: iota
19
… AND lessons good and bad from all those plus:
C++, C#, Java, JavaScript, LISP, Python, Scala, ...
20. — txxxxd
“Most of the appeal
for me is not the
features that Go has,
but rather the
features that have
been intentionally left
out.”
20
21. — Rob Pike
“Why would you have
a language that is
not theoretically
exciting? Because it’s
very useful.”
21
23. Package
•Not classes or objects
•No subpackages
•Fundamental building block in Go
•Visibility is package-level, not type-level
•Programs run “main” package 23
package main
!
import "fmt"
!
func main() {
fmt.Println("Hello, 世界")
}
24. import
•Provides access to a package
•Package consists of types, functions, etc…
•No circular dependencies
24
package main
!
import "fmt"
!
func main() {
fmt.Println("Hello, 世界")
}
25. “fmt"
•Package path is just
a string
•Standard library sits at the root (no path)
•Core language is very small
•Most functionality is in Stdlibs
25
package main
!
import "fmt"
!
func main() {
fmt.Println("Hello, 世界")
}
26. func
•Declaring a function
•Same syntax for methods, anonymous functions
& closures
•main.main() is the function run when the
program is executed
26
package main
!
import "fmt"
!
func main() {
fmt.Println("Hello, 世界")
}
27. Main
•No void
•No return value
•No function args
(command line is in os package)
27
package main
!
import "fmt"
!
func main() {
fmt.Println("Hello, 世界")
}
28. { }
•Braces not spaces
•Feels like C ( & most languages )
•Newline must be after brace
(semicolons are inserted during compiliation)
28
package main
!
import "fmt"
!
func main() {
fmt.Println("Hello, 世界")
}
29. fmt
•Accessing the package
imported above
•Everything visible in the package will be
accessible through the name (or alias if
provided)
29
package main
!
import "fmt"
!
func main() {
fmt.Println("Hello, 世界")
}
30. Println
• Println, not println
• Println, not print_ln
•Capital for export
•Variadic function using reflection
30
package main
!
import "fmt"
!
func main() {
fmt.Println("Hello, 世界")
}
31. “Hello, 世界”
•UTF-8 input source
•Strings are immutable
•Strings are UTF-8 encoded
•String is a built-in type
31
package main
!
import "fmt"
!
func main() {
fmt.Println("Hello, 世界")
}
32. Rob Pike did it better
http://confreaks.com/videos/3419-
gophercon2014-opening-day-keynote
32
38. ❯ go build hello.go
!
❯ls -lh
1.7M Jun 17 22:44 hello
72B Jun 17 22:43 hello.go
!
❯ ./hello
Hello, World
Go Build
38
39. Go Fmt
•Automatically formats Go source code
•Ends stylistic debates
•Integration with editors (vim, emacs, others)
•Can also refactor code
(see http://spf13.com/post/go-fmt ) 39
40. go Test
•Enables easy testing of application
•Integrates with the testing package
•Supports benchmark, functional & unit style
testing
•Combine with ‘looper’ to have realtime feedback 40
42. ❯ go test ./...
--- FAIL: TestOne (0.00 seconds)
hello_test.go:8: Test failed
FAIL
FAIL_/Code/firstApp0.012s
!
!
❯ go test ./...
ok _/Code/firstApp0.012s
Go Test
42
43. Go
Planet
43The planet logo is based on the Go mascot designed by
Renée French and copyrighted under the Creative Commons Attribution 3.0 license.
49. Go path
•The GOPATH environment variable specifies
the location of your workspace (and
dependencies)
•It must not be the same path as your Go
installation
49
55. Project Dir
•Make a directory inside of $GOPATH/src
•I like mine to be in
$GOPATH/src/github.com/spf13/PROJECTNAME
•It can not be a symlink
•We will call this our working directory or $wd 55
63. First class Functions
•Function literals are anonymous functions in Go
•Can assign to a variable or field
•Can use as function parameters or return
values
•Can be created as a goroutine 63
64. pointers
•Function calls copy arguments into the function
•Pointers reference a location in memory where a value is
stored rather than the value itself
•In Go a pointer is represented using the *
•The & operator gives us the address of a variable
•Go automatically dereferences pointers when using “.” 64
65. cobra
•A CLI Commander
•Easy management of commands &
flags
•Used by bitbucket, openshift & lots
more
65
http://fav.me/d5gkby7
66. go get -u
github.com/spf13/cobra
Getting Cobra
66
70. var RootCmd = &cobra.Command{
Use: "dagobah",
Short: `Dagobah is an awesome planet style RSS
aggregator`,
Long: `Dagobah provides planet style RSS aggregation. It
is inspired by python planet. It has a simple YAML
configuration and provides it's own webserver.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Dagobah runs")
},
}
planet.go (2)
70
72. Variable Assignment
•‘:=‘ is the short variable declaration operator
Declares, creates & assigns simultaneously
while infering type
•Assignment via ‘=‘ requires prior declaration
•var foo int = 10 is the same as foo := 10 72
73. Error Handling
•Errors are not exceptional. Should be part of the language
•Typically one of the return values
•No exceptions in Go
fd, err := os.Open("test.go")
if err != nil {
log.Fatal(err)
} 73
74. ( Don’t) Panic
•Should rarely be used if ever
•Performs a full stack trace dump for end users
•Use only in the most dire circumstances (like
package can’t find FileSystem)
•Can use ‘recover’, but only inside deferred functions
74
82. Package Identifiers
•Export with Capital name
•No automatic getters & setters
•var field … func Field() … func SetField()
are appropriate names
82
83. init()
•Each source file can have one (or multiple)
•Niladic function to setup state
(function without return value)
•Called after all variable declarations in the
package 83
84. Scoping
•Very granular scoping.
•Variables declared inside { } only survive in that cotrol
structure (for, if, etc)
•The := trap
if := is used to declare x and x already exists in an
outer scope a new variable x will be created (shadowing)
84
101. go-pkg-rss
•Fetch Rss and Atom feeds from the internet
•Supports RSS .92, 1.0, 2.0 & Atom 1.0
•Respects TTL, SkipDays, CacheTimeout, etc
in the feeds
101
102. go get -u
github.com/jteeuwen/go-
pkg-rss
Getting Go-PKG-RSS
102
107. Named Types
•Can be any known type (struct, string, int,
slice, a new type you’ve declared, etc)
•Can have methods declared on it
•Not an alias. Explicit type.
107
108. Slices & arrays
•Array is fixed in length
•Slice can be viewed as a dynamic array (can grow)
•Slice is a view of an array
•Slice is the core data structure in Go for lists
of data 108
111. New( )
•new(T) Does 2 things at once:
•Allocates new zeroed value of type T
•Returns a pointer to the new value ( *T)
•Used for all non-reference types
111
112. Make( )
•Creates slices, maps, and channels only
•These types are special “reference” types
•Makes a initialized (not zeroed) value of type T
•Does not return a pointer
112
113. Composite Literals
•An expression that creates a new value each time it is
evaluated
•We’ve already used these quite a bit
•Can also be create values of arrays, slices, and maps
•Pseudo Constructor
•eg File{fd: fd, name: name}
113
114. Constructors
•Not built into Go
•Use Composite Literals when possible
•If initialization is needed use a factory
•Convention is to use New___()
•… or New() when only one type is exported in the package
114
115. var fetchCmd = &cobra.Command{
Use: "fetch",
Short: "Fetch feeds",
Long: `Dagobah will fetch all feeds listed in the config file.`,
Run: fetchRun
}
!
func init() {
fetchCmd.Flags().Int("rsstimeout", 5, "Timeout (in min) for RSS retrival")
viper.BindPFlag("rsstimeout", fetchCmd.Flags().Lookup("rsstimeout"))
}
Fetch.go (3)
115
117. GoRoutines
•A function executing concurrently with
other goroutines in the same address space
•Lightweight
•Not threads, coroutines, or processes
117
118. Channels
•Channels are lightweight
•Synchronize goroutines by communication rather than locking shared
memory
•Channel <- Sender —- Writes block when channel is full
•<- Channel —- Reads blocks waiting for something to be read
•Great talk on channels given at GopherCon
http://confreaks.com/videos/3422-gophercon2014-a-channel-compendium
118
119. Marshaling into
•We can’t return a T (no generics)
•We can reflect on any value of any type
•Marshal accepts the address of the value so
it can manipulate the value directly
119
127. For
•For, Foreach & While are all spelled ‘for’ in Go
for init; condition; post { }
// Like a C for
for condition { }
// Like a C while
for { }
// Like a C for(;;)
127
129. func chanHandler(feed *rss.Feed, newchannels []*rss.Channel) {
fmt.Printf("%d new channel(s) in %sn", len(newchannels), feed.Url)
}
!
func itemHandler(feed *rss.Feed, ch *rss.Channel, newitems []*rss.Item) {
fmt.Printf("%d new item(s) in %sn", len(newitems), feed.Url)
}
Fetch.go (7)
129
130. ❯ go run dagobah.go fetch --rsstimeout=1
15 new item(s) in http://spf13.com/index.xml
1 new channel(s) in http://spf13.com/index.xml
Sleeping for 300 seconds on http://spf13.com/index.xml
25 new item(s) in http://www.goinggo.net/feeds/posts/default
1 new channel(s) in http://www.goinggo.net/feeds/posts/default
Sleeping for 300 seconds on http://www.goinggo.net/feeds/posts/
default
10 new item(s) in http://dave.cheney.net/feed
1 new channel(s) in http://dave.cheney.net/feed
Sleeping for 299 seconds on http://dave.cheney.net/feed
Running it
130
137. Mgo
•Developed by the open source community
•Heavily used throughout Go community
•"mgo is the best database driver I've ever used."
— Patrick Crosby, Founder of StatHat
•"mgo and Go are a pair made in heaven.
— Brian Ketelsen, Author of GopherTimes.com137
148. Data Prep
•Feeds are dirty
•Go doesn’t allow “patching” of structs (not
how structs work)
•MongoDB works with native types & named
types 148
149. Tags (Annotations)
•String literal following a field declaration
•Provides additional information during
reflection
•Used by JSON, BSON, YAML, etc
149
150. for x,y := range
•Provides a way to iterate over an array, slice,
string, map, or channel.
•Like Foreach or Each in other languages
•x is key, y is value… can ignore by setting
to _ 150
151. Append
•Append is really awesome, feels like push, but
does a lot more.
•Append will grow a slice (both length &
capacity)
•… and copy the underlying array if needed 151
158. The Blank Identifier ‘_’
•Used to ignore return values from a
function
•Used with imports as an alias
• Allows import of unused packages so init
functions can be executed 158
159. func chanHandler(feed *rss.Feed, newchannels []*rss.Channel) {
fmt.Printf("%d new channel(s) in %sn", len(newchannels), feed.Url)
for _, ch := range newchannels {
chnl := chnlify(ch)
if err := Channels().Insert(chnl); err != nil {
if !strings.Contains(err.Error(), "E11000") {
fmt.Printf("Database error. Err: %v", err)
}
}
}
}
fetch.go
159
160. func itemHandler(feed *rss.Feed, ch *rss.Channel, newitems []*rss.Item) {
fmt.Printf("%d new item(s) in %sn", len(newitems), feed.Url)
for _, item := range newitems {
itm := itmify(item, ch)
if err := Items().Insert(itm); err != nil {
if !strings.Contains(err.Error(), "E11000") {
fmt.Printf("Database error. Err: %v", err)
}
}
}
}
fetch.go
160
164. ❯ go run dagobah.go fetch --rsstimeout=1
15 new item(s) in http://spf13.com/index.xml
1 new channel(s) in http://spf13.com/index.xml
Sleeping for 300 seconds on http://spf13.com/index.xml
25 new item(s) in http://www.goinggo.net/feeds/posts/default
1 new channel(s) in http://www.goinggo.net/feeds/posts/default
Sleeping for 300 seconds on http://www.goinggo.net/feeds/posts/
default
10 new item(s) in http://dave.cheney.net/feed
1 new channel(s) in http://dave.cheney.net/feed
Sleeping for 299 seconds on http://dave.cheney.net/feed
Running planet
164
165. > use dagobah
> db.items.findOne()
{
"_id" : ObjectId("53b4c08bddbc460a933cf3ed"),
"date" : ISODate("2014-07-01T00:00:00Z"),
"key" : "http://spf13.com/post/go-pointers-vs-references",
"channelkey" : "Recent Content on Hacking Management",
"title" : "Pointers vs References",
"links" : [
{
"href" : "http://spf13.com/post/go-pointers-vs-references",
"rel" : "",
"type" : "",
"hreflang" : ""
Looking at the Data
165
166. _ID
•MongoDB’s primary key
•Default is to use an “object_id”
•Object_id guaranteed to be unique across your
entire cluster
•MongoDB will create it for you on insert 166
170. Lots of choices
•Beego
High-performance web
framework
•Gin
Martini like with better
performance
•Goji
A minimalistic web framework
•Gorilla
A web toolkit
•httprouter
A high performance router
•Mango
modular web-app framework
like Rack
•Martini
modular web apps & services
•net/http
Standard library web package
•pat
Sinatra style, by the author of
Sinatra.
•Revel
A high-productivity web
framework
•tigertonic
framework for JSON web
services
•traffic
Sinatra inspired web framework
for Go
•web.go
A simple framework to write
webapps in Go.
170
176. var serverCmd = &cobra.Command{
Use: "server",
Short: "Server for feeds",
Long: `Dagobah will serve all feeds listed in the config file.`,
Run: serverRun,
}
!
func init() {
serverCmd.Flags().Int("port", 1138, "Port to run Dagobah server on")
viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
}
server.go (2)
176
206. passing data
into the template
•Go’s templates accept a variety of data types
•Gin’s default is ‘H’ : map[string]interface{}
•Feels natural
•All (exported) methods bound to values in the
map are accessible inside the template 206
244. What’s next ?
•Add ‘truncate’ command to remove old posts
and channels
•Change root command to run fetcher &
server
•Add infinite scroll capabilities 244
245. What’s next ?
•Make it so users can provide their own
static files & templates
•Documentation
•Blog posts
245
246. In Conclusion
246
Go mascot designed by Renée French and copyrighted under the Creative Commons Attribution 3.0 license.
248. What have we done ?
•Written our first lines of Go
•Written our first Go package
•Written our own web server
•Written our first Go application
•Learned a lot & had fun doing it 248
249. @spf13
•Author of Hugo, Cobra, Viper
& More
•Chief Developer Advocate for
MongoDB
•Gopher 249