SlideShare ist ein Scribd-Unternehmen logo
1 von 249
Downloaden Sie, um offline zu lesen
Building  
your  first  
Go  App
1
Go mascot designed by Renée French and copyrighted under the Creative Commons Attribution 3.0 license.
@spf13
•Author of Hugo, Cobra, Viper
& More
•Chief Developer Advocate for
MongoDB
•Gopher 2
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
hugo.spf13.com
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
Plan
•Introduce Go Language
•Introduce Tools & Libraries
•Build our application
•Tell the world how awesome we are 8
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
http://
spf13.com/
presentation/
first-go-app/
10
Installing  Go
•You should already have Go installed
•If you don’t, do it NOW
•Installation Guide
11
Installing  MongoDB
•You should already have MongoDB installed
•If you don’t, do it NOW
•Installation Guide
12
Git  &  Mercurial
•Lastly we need Git & Mercurial
•http://git-scm.com/downloads
•http://mercurial.selenic.com/wiki/Download
13
Introduction    
to  Go
14
Why  Another  Language?
• Software is slow
• Sofware is hard to write
• Software doesn’t scale well
15
Go  is  Fast
• Go execution speed is close to C
• Go compile time rivals dynamic
interpretation
16
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
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
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, ...
— 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
— Rob Pike
“Why  would  you  have  
a  language  that  is  
not  theoretically  
exciting?  Because  it’s  
very  useful.”
21
package main
!
import "fmt"
!
func main() {
fmt.Println(“Hello, 世界")
}
Hello  World
22
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, 世界")
}
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, 世界")
}
“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, 世界")
}
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, 世界")
}
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, 世界")
}
{ }
•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, 世界")
}
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, 世界")
}
 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, 世界")
}
“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, 世界")
}
Rob  Pike  did  it  better
http://confreaks.com/videos/3419-
gophercon2014-opening-day-keynote
32
Tons  more…
•types
•constants
•methods
•interfaces
•pointers
•control flow
•conditionals
•tools
•packages
•concurrency 33
Effective  Go
34
Lets  write  
some  code  
!
Introduce  the    
go  tools 35
package main
!
import "fmt"
!
func main() {
fmt.Println("Hello,World")
}
Hello  World
36
hello.go
❯ go run hello.go



Hello,World
Go  Run
37
❯ 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
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
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
package main
!
import "testing"
!
func TestOne(t *testing.T) {
one := false
if !one {
t.Errorf(“Test Failed”)
}
}
Hello  Test
41
hello_test.go
❯ 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
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.
Why  Planet?
•CLI application
•Web application
•Good
introduction
•Right sized
•Database
(MongoDB)
•Concurrency 45
Steps
0. Env Setup
1. Commands
2. Configuration
3. Working with Feeds
4. DB as Storage
5-6. Web Server
7-8. DB -> Templates
9. & 10. Add Polish 46
Step  0  


Setting  up  our  
environment
47
Go  PAth  
!
$GOPATH
48
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
❯ mkdir $HOME/go

!
❯ export 

GOPATH=$HOME/go
Setting  up
50
export GOPATH=$USER/go
export GOROOT=`go env GOROOT`
PATH=$PATH:$GOPATH/bin
Linux  &  Mac
51
Add this to your ~/.bashrc (or equivalent)
Windows
•Control panel > System
52
Go  PAth
•/home/user/gocode/ ($GOPATH)
• src/ (put your source code here)
• bin/ (binaries installed here)
• pkg/ (installed package objects)
53
Creating  our  
project
54
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
package main
!
import "fmt"
!
func main() {
fmt.Println(“My Project")
}
main.go
56
❯ go run main.go



My Project
Run  it
57
58
I’m on the #gopath with @spf13 at #OSCON

http://j.mp/onGoPath
Tweet  Break
Step  1  


Creating  the  
Command(s)
59
Defining  

our  first  
command
60
Structs
•Short for structure
•Objectish … blend of data & methods, but no
inheritance
•Really cheap. Struct{} is free (0 bytes).
61
Functions
•Can have multiple return values
•No overloading
•No optional parameters (but variadic)
62
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
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
cobra
•A CLI Commander
•Easy management of commands &
flags
•Used by bitbucket, openshift & lots
more
65
http://fav.me/d5gkby7
go get -u 

github.com/spf13/cobra
Getting  Cobra
66
❯ mkdir $wd/commands
Commands  Dir
67
// Copyright © 2014 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
!
package commands
!
import (
"fmt"
"os"
!
"github.com/spf13/cobra"
)
planet.go  (1)
68
Path  =  Url
go get uses it to install
69
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
executing  
cobra’s  
command
71
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
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
(  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
func Execute() {
err := RootCmd.Execute()
if err != nil {
fmt.Println(err)
os.Exit(-1)
}
}
planet.go  (3)
75
// Copyright © 2014 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
!
package main
!
import "github.com/spf13/firstGoApp-Planet/commands"
!
func main() {
commands.Execute()
}
main.go
76
Make sure to use your path
❯ go run main.go

Dagobah runs
!
❯ go run main.go help
Running  it
77
Getting  Help
•https://godoc.org/github.com/spf13/cobra
•https://github.com/spf13/firstGoApp-Planet/
tree/step1
78
Creating #CobraCommands with @spf13 at #OSCON
http://j.mp/cobracmd
Tweet  Break
Step  2  


Easy  Configuration
80
Handing  
Config  files
81
Package  Identifiers
•Export with Capital name
•No automatic getters & setters
•var field … func Field() … func SetField() 

are appropriate names
82
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
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
package main
!
import (
"errors"
"fmt"
)
!
var Foo int
!
func Zero() (int, error) {
return 0, errors.New("yo")
}
!
!
func main() {
!
Foo = 10
!
fmt.Println("outer:", Foo) // 10
!
if Foo, err := Zero(); err != nil {
fmt.Println("inner:", Foo) // 0
}
!
fmt.Println("outer again:", Foo) // still 10
}
:=  Trap
85http://play.golang.org/p/i4L9Ao1P65
Viper
•A configuration manager
•Easy loading of config files
•Registry for application settings
•Designed to work well with (or without) Cobra
86
go get -u 

github.com/spf13/viper
Getting  Viper
87
// Copyright © 2014 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
!
package commands
!
import (
"fmt"
"os"
!
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
planet.go  (1)
88
var CfgFile string
!
func init() {
cobra.OnInitialize(initConfig)

RootCmd.PersistentFlags().StringVar(&CfgFile, "config", "", "config file (default is
$HOME/dagobah/config.yaml)")
}
!
func initConfig() {
if CfgFile != "" {
viper.SetConfigFile(CfgFile)
}
viper.SetConfigName("config")
viper.AddConfigPath("/etc/dagobah/")
viper.AddConfigPath("$HOME/.dagobah/")
viper.ReadInConfig()
}
planet.go  (2)
89
Creating  our  
config  file
90
appname: "Dagobah"
feeds:
- "http://spf13.com/index.xml"
- "http://dave.cheney.net/feed"
- "http://www.goinggo.net/feeds/posts/default"
- "http://blog.labix.org/feed"
- "http://blog.golang.org/feed.atom"
!
$HOME/.dagobah/config.yaml
91
trying  it  out
92
var RootCmd = &cobra.Command{
Use: "...",
Short: `...`,
Long: `...`,
Run: rootRun,
}
!
func rootRun(cmd *cobra.Command, args []string) {
fmt.Println(viper.Get("feeds"))
fmt.Println(viper.GetString("appname"))
}
planet.go  (3)
93
❯ go run main.go

[http://spf13.com/index.xml http://
dave.cheney.net/feed http://
www.goinggo.net/feeds/posts/default
http://blog.labix.org/feed http://
blog.golang.org/feed.atom]



Dagobah
Running  it
94
I got bit by the #goviper at #OSCON 

http://j.mp/go-viper
Tweet  Break
https://
github.com/spf13/
firstGoApp-
Planet/tree/
step2
96
Step  3  


Working  with  Feeds
97
Finding  
Libraries
98
Go-Search.org
99
Go  wiki
100
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
go get -u 

github.com/jteeuwen/go-
pkg-rss
Getting  Go-PKG-RSS
102
boilerplate  

stuff
103
import (
"time"
...
)
!
func addCommands() {
RootCmd.AddCommand(fetchCmd)
}
!
func Execute() {
addCommands()
...
}
planet.go
104
// Copyright © 2014 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
!
package commands
!
import (
"fmt"
"os"
"time"
!
rss "github.com/jteeuwen/go-pkg-rss"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
Fetch.Go  (1)
105
Creating  our  
own  type
106
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
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
type Config struct {
Feeds []string
Port int
}
Fetch.Go  (2)
109
Defining  the  
fetch  
command
110
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
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
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
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
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
Fetching  in  a  
goroutine
116
GoRoutines
•A function executing concurrently with
other goroutines in the same address space
•Lightweight
•Not threads, coroutines, or processes
117
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
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
func fetchRun(cmd *cobra.Command, args []string) {


Fetcher()
!
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt)
<-sigChan
}
Fetch.go  (4)
120
func Fetcher() {
var config Config
if err := viper.Marshal(&config); err != nil {
fmt.Println(err)
}
!
for _, feed := range config.Feeds {
go PollFeed(feed.Url)
}
}
Fetch.go  (5)
121
Building  our  
fetcher
122
Learning  about  go-pkg-rss
•How do we learn how to use the package?
123
Learning  about  go-pkg-rss
•github.com/jteeuwen/go-pkg-rss
•Readme is pretty lacking
•godoc.org/github.com/jteeuwen/go-pkg-rss
124
godoc.org/github.com/jteeuwen/go-pkg-rss
125
Go  Search
126
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
func PollFeed(uri string) {
timeout := viper.GetInt("RSSTimeout")
if timeout < 1 {
timeout = 1
}
feed := rss.New(timeout, true, chanHandler, itemHandler)
!
for {
if err := feed.Fetch(uri, nil); err != nil {
fmt.Fprintf(os.Stderr, "[e] %s: %s", uri, err)
return
}
!
fmt.Printf("Sleeping for %d seconds on %sn", feed.SecondsTillUpdate(), uri)
time.Sleep(time.Duration(feed.SecondsTillUpdate() * 1e9))
}
}
Fetch.GO  (6)
128
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
❯ 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
Tweet  Break
I wrote my first goroutine at #OSCON with @spf13
https://
github.com/spf13/
firstGoApp-
Planet/tree/
step3
132
Step  4  


Storing  in  

the  Database
133
Pretty
•github.com/kr/pretty
•pretty.Println(X,Y,Z)
134
MongoDB
•Open Source
•Document Database
•Document == Struct or Document == Map
•Works seamlessly with Go (and other languages)
135
MongoDB
•Fast & Scalable
•Used by Disney, IBM, Metlife, eBay,
Forbes, Craigslist, Cisco, Stripe
136
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
go get -u gopkg.in/mgo.v2
Getting  mgo
138
boilerplate

stuff
139
// Copyright © 2014 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
!
package commands
!
import (
"fmt"
"os"
!
"github.com/spf13/viper"
"gopkg.in/mgo.v2"
)
!
var mongodbSession *mgo.Session
!
func init() {
RootCmd.PersistentFlags().String("mongodb_uri", "localhost", "host where mongoDB is")
viper.BindPFlag("mongodb_uri", RootCmd.PersistentFlags().Lookup(“mongodb_uri"))
CreateUniqueIndexes()
}
MongoDB.go  (1)
140
Setting  up  a  
DB  session
141
func DBSession() *mgo.Session {
if mongodbSession == nil {
uri := os.Getenv("MONGODB_URI")
if uri == "" {
uri = viper.GetString("mongodb_uri")
!
if uri == "" {
log.Fatalln("No connection uri for MongoDB provided")
}
}
!
var err error
mongodbSession, err = mgo.Dial(uri)
if mongodbSession == nil || err != nil {
log.Fatalf("Can't connect to mongo, go error %vn", err)
}
!
mongodbSession.SetSafe(&mgo.Safe{})
}
return mongodbSession
}
MongoDB.go  (2)
142
setting  up  
some  
shortcuts
143
!
func DB() *mgo.Database {
return DBSession().DB(viper.GetString("dbname"))
}
!
func Items() *mgo.Collection {
return DB().C("items")
}
!
func Channels() *mgo.Collection {
return DB().C("channels")
}
MongoDB.go  (3)
144
Setting  up  
indexes
145
func CreateUniqueIndexes() {
idx := mgo.Index{
Key: []string{"key"},
Unique: true,
DropDups: true,
Background: true,
Sparse: true,
}
!
if err := Items().EnsureIndex(idx); err != nil {
fmt.Println(err)
}
!
if err := Channels().EnsureIndex(idx); err != nil {
fmt.Println(err)
}
}
MongoDB.go  (4)
146
Preparing  
the  data
147
Data  Prep
•Feeds are dirty
•Go doesn’t allow “patching” of structs (not
how structs work)
•MongoDB works with native types & named
types 148
Tags  (Annotations)
•String literal following a field declaration
•Provides additional information during
reflection
•Used by JSON, BSON, YAML, etc
149
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
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
type Itm struct {
Date time.Time
Key string
ChannelKey string
Title string
FullContent string
Links []*rss.Link
Description string
Author rss.Author
Categories []*rss.Category
Comments string
Enclosures []*rss.Enclosure
Guid *string `bson:",omitempty"`
Source *rss.Source
PubDate string
Id string `bson:",omitempty"`
Generator *rss.Generator
Contributors []string
Content *rss.Content
Extensions map[string]map[string][]rss.Extension
}
fetch.go
152
func itmify(o *rss.Item, ch *rss.Channel) Itm {
var x Itm
x.Title = o.Title
x.Links = o.Links
x.ChannelKey = ch.Key()
x.Description = o.Description
x.Author = o.Author
x.Categories = o.Categories
x.Comments = o.Comments
x.Enclosures = o.Enclosures
x.Guid = o.Guid
x.PubDate = o.PubDate
x.Id = o.Id
x.Key = o.Key()
x.Generator = o.Generator
x.Contributors = o.Contributors
x.Content = o.Content
x.Extensions = o.Extensions
x.Date, _ = o.ParsedPubDate()
!
if o.Content != nil && o.Content.Text != "" {
x.FullContent = o.Content.Text
} else {
x.FullContent = o.Description
}
!
return x
}
fetch.go
153
type Chnl struct {
Key string
Title string
Links []rss.Link
Description string
Language string
Copyright string
ManagingEditor string
WebMaster string
PubDate string
LastBuildDate string
Docs string
Categories []*rss.Category
Generator rss.Generator
TTL int
Rating string
SkipHours []int
SkipDays []int
Image rss.Image
ItemKeys []string
Cloud rss.Cloud
TextInput rss.Input
Extensions map[string]map[string]
[]rss.Extension
Id string
Rights string
Author rss.Author
SubTitle rss.SubTitle
}
fetch.go
154
func chnlify(o *rss.Channel) Chnl {
var x Chnl
x.Key = o.Key()
x.Title = o.Title
x.Links = o.Links
x.Description = o.Description
x.Language = o.Language
x.Copyright = o.Copyright
x.ManagingEditor = o.ManagingEditor
x.WebMaster = o.WebMaster
x.PubDate = o.PubDate
x.LastBuildDate = o.LastBuildDate
x.Docs = o.Docs
x.Categories = o.Categories
x.Generator = o.Generator
x.TTL = o.TTL
x.Rating = o.Rating
x.SkipHours = o.SkipHours
x.SkipDays = o.SkipDays
x.Image = o.Image
x.Cloud = o.Cloud
x.TextInput = o.TextInput
x.Extensions = o.Extensions
x.Id = o.Id
x.Rights = o.Rights
x.Author = o.Author
x.SubTitle = o.SubTitle
!
...
!
return x
}
fetch.go
155
...
!
!
var keys []string
for _, y := range o.Items {
keys = append(keys, y.Key())
}
x.ItemKeys = keys
!
...
fetch.go
156
Storing  
Feeds  &  
Items
157
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
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
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
Running  
MongoDB
161
❯ mongod



MongoDB starting : pid=51054
port=27017 dbpath=/data/db
Running  MongoDB
162
❯ mongo







Mongo  Shell
163
❯ 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
> 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
_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
Tweet  Break
Feeding mgo at #OSCON with @spf13
http://j.mp/mongomgo
https://
github.com/spf13/
firstGoApp-
Planet/tree/
step4
168
Step  5  


Building  a  

web  Server
169
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
Gin
•Compatible with net/http
•Uses Httprouter (really fast)
•Familiar/Friendly Interface
•Works well with JSON
•Had to pick something 171
go get -u

github.com/gin-gonic/gin
Getting  Gin
172
boilerplate  

stuff
173
// Copyright © 2014 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
!
package commands
!
import (
"github.com/gin-gonic/gin"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
Server.Go  (1)
174
Defining  the  
Server  
command
175
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
func addCommands() {
RootCmd.AddCommand(fetchCmd)
RootCmd.AddCommand(serverCmd)
}
planet.go
177
Defining  our  
first  route
178
func serverRun(cmd *cobra.Command, args []string) {
r := gin.Default()
!
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
!
port := viper.GetString("port")
fmt.Println("Running on port:", port)
r.Run(":" + port)
}
server.go  (3)
179
❯ go run dagobah.go server
Running  it
180
Check  it  out
http://localhost:1138 181
Tweet  Break
I wrote a webserver in go using Gin 

with @spf13 at #OSCON http://j.mp/gin-go
https://
github.com/spf13/
firstGoApp-
Planet/tree/
step5
183
Step  6  


Building  a  

Dynamic  Server
184
Binary  Problem?
•Go ships as a single binary
•Need to load files from within the binary
•Don’t want to embed by hand
185
go.rice
•Nicely allows local loads in dev, and embedded
loads when executing binary
•Stable, but not very mature yet
•Best option I know of
186
go get -u 

github.com/GeertJohan/
go.rice
Getting  Go.Rice
187
Serving  
Static  Files
188
Get  your  
static  &  
templates  on
c.spf13.com/OSCON/step6-static.zip
189
import (
"fmt"
"html/template"
"log"
"net/http"
!
"github.com/GeertJohan/go.rice"
"github.com/gin-gonic/gin"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
server.go
190
func serverRun(cmd *cobra.Command, args []string) {
...

r.GET("/static/*filepath", staticServe)
!
port := viper.GetString("port")
fmt.Println("Running on port:", port)
r.Run(":" + port)
}
server.go
191
func staticServe(c *gin.Context) {
static, err := rice.FindBox("static")
if err != nil {
log.Fatal(err)
}
!
original := c.Request.URL.Path
c.Request.URL.Path = c.Params.ByName("filepath")
fmt.Println(c.Params.ByName("filepath"))
http.FileServer(static.HTTPBox()).ServeHTTP(c.Writer, c.Request)
c.Request.URL.Path = original
}
server.go
192
Loading  &  
Serving    
Templates
193
func loadTemplates(list ...string) *template.Template {
templateBox, err := rice.FindBox("templates")
if err != nil {
log.Fatal(err)
}
templates := template.New("")
!
for _, x := range list {
templateString, err := templateBox.String(x)
if err != nil {
log.Fatal(err)
}
!
// get file contents as string
_, err = templates.New(x).Parse(templateString)
if err != nil {
log.Fatal(err)
}
}
return templates
}
server.go
194
func serverRun(cmd *cobra.Command, args []string) {
r := gin.Default()
templates := loadTemplates("full.html")
r.SetHTMLTemplate(templates)
!
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
!
r.GET("/", homeRoute)
r.GET("/static/*filepath", staticServe)

!
port := viper.GetString("port")
fmt.Println("Running on port:", port)
r.Run(":" + port)
}
server.go
195
func homeRoute(c *gin.Context) {
obj := gin.H{"title": "Go Rules"}
c.HTML(200, “full.html", obj)
}
server.go
196
❯ go run dagobah.go server
Running  it
197
Check  it  out
http://localhost:1138 198
Tweet  Break
No more mr rice guy 

with @spf13 at #OSCON http://j.mp/go-rice
https://
github.com/spf13/
firstGoApp-
Planet/tree/
step6
200
Step  7  


Connecting  the  Data  
to  The  templates
201
Go  Templates
•Really nice to work with
•Very simple, yet very powerful
•Safe
•Go Template Primer
202
Understanding  

the  data
203
> db.items.find().sort({ "date" : -1 }).limit(1).pretty()
{
"_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  Schema
204
Listing  POsts
205
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
func homeRoute(c *gin.Context) {
var posts []Itm
results := Items().Find(bson.M{}).Sort("-date").Limit(20)
results.All(&posts)
!
obj := gin.H{"title": "Go Rules", "posts": posts}
c.HTML(200, "full.html", obj)
}
server.go
207
...
<section id="latest-list" class="ui divided inbox selection list active tab" data-tab="recent">
{{ range $item := .posts }}
{{ if $item.WorthShowing }}
<a class="item" href=“#{{$item.Key | urlquery }}">
<div class="description">{{ $item.Title }}</div>
<div class="right floated ui label small">{{ $item.Date.Format "Jan 2, 2006" }}</div>
</a>
{{ end }}
{{ end }}
</section>
...
Full.html
208
Adding  Helpers  

to  itm
209
func (i Itm) FirstLink() (link rss.Link) {
if len(i.Links) == 0 || i.Links[0] == nil {
return
}
return *i.Links[0]
}
!
func (i Itm) WorthShowing() bool {
if len(i.FullContent) > 100 {
return true
}
return false
}
fetch.go
210
displaying  POsts
211
...
<main>
{{ with .message}}!
<h1 class="ui header large"> {{.}} </h1>!
{{ end }}!
!
{{ range $item := .posts }}!
{{ if $item.WorthShowing }}!
<article data-key="{{$item.Key}}">!
<header>!
<a name="{{$item.Key}}">!
<h1 class="ui header">{{$item.Title}}</h1>!
<section class="meta-tags">!
<a class="ui label large blue author" href="/channel/{{$item.ChannelKey}}">{{$item.Author.Name}}</a>!
<span class="large ui label date">{{ $item.Date.Format "Jan 2, 2006" }}</span>!
</section>!
</header>!
<section class="main-content">!
{{$item.FullContent | html }}!
</section>!
<footer>!
{{with $item.FirstLink}}!
<a class="ui basic button" href="{{.Href}}">Source</a>!
{{end}}!
<div class="ui divider"></div>!
</footer>!
</article>!
{{ end }}!
{{ else }}!
No Articles!
{{ end }}!
</main>
...
full.html
212
Adding  Template  
Functions
213
func loadTemplates(list ...string) *template.Template {
templateBox, err := rice.FindBox("templates")
if err != nil {
log.Fatal(err)
}
!
templates := template.New("")
!
for _, x := range list {
templateString, err := templateBox.String(x)
if err != nil {
log.Fatal(err)
}
!
// get file contents as string
_, err = templates.New(x).Parse(templateString)
if err != nil {
log.Fatal(err)
}
}
!
funcMap := template.FuncMap{
"html": ProperHtml,
"title": func(a string) string { return strings.Title(a) },
}
!
templates.Funcs(funcMap)
!
return templates
}
server.go
214
func ProperHtml(text string) template.HTML {
if strings.Contains(text, "content:encoded>") || strings.Contains(text, "content/:encoded>") {
text = html.UnescapeString(text)
}
return template.HTML(html.UnescapeString(template.HTMLEscapeString(text)))
}
server.go
215
Looking  Good
http://localhost:1138 216
Tweet  Break
Conquering Go Templates 

with @spf13 at #OSCON
https://
github.com/spf13/
firstGoApp-
Planet/tree/
step7
218
Step  8  


More  Routes
219
Adding  Helpers
220
func (c Chnl) HomePage() string {
if len(c.Links) == 0 {
return ""
}
!
url, err := url.Parse(c.Links[0].Href)
if err != nil {
log.Println(err)
}
return url.Scheme + "://" + url.Host
}
fetch.go
221
!
func four04(c *gin.Context, message string) {
c.HTML(404, "full.html", gin.H{"message": message, "title": message})
}
server.go
222
func AllChannels() []Chnl {
var channels []Chnl
r := Channels().Find(bson.M{}).Sort("-lastbuilddate")
r.All(&channels)
return channels
}
MongoDB.go
223
Listing  channels
224
func homeRoute(c *gin.Context) {
var posts []Itm
results := Items().Find(bson.M{}).Sort("-date").Limit(20)
results.All(&posts)
!
obj := gin.H{"title": "Go Rules", 

"posts": posts, "channels": AllChannels()}
c.HTML(200, "full.html", obj)
}
server.go
225
...
<section id="channel-list" 

class="ui large inverted vertical menu tab" data-tab=“channels">
<a class="item js-navigate" href="/" >!
<i class="external home icon"></i>!
<span class="ui name" href=""> All </span>!
</a>!
{{ range $channel := .channels }}!
<div class="item js-navigate-channel" data-href="/channel/{{$channel.Key}}" 

data-key="{{$channel.Key}}" style="cursor:pointer;">!
<a href="{{$channel.HomePage}}" class="ui float right"><i class="external url sign icon"></i></a>!
<span class="ui name" href=""> {{$channel.Title}} </span>!
<span class="ui label">{{ len $channel.Links }}</span>!
</div>!
{{end}}!
</section>
...
full.html
226
displaying  
channels
227
func serverRun(cmd *cobra.Command, args []string) {
...
r.GET("/channel/*key", channelRoute)
r.Run(":" + port)
}
server.go
228
func channelRoute(c *gin.Context) {
key := c.Params.ByName("key")
if len(key) < 2 {
four04(c, "Channel Not Found")
return
}
!
key = key[1:]
!
fmt.Println(key)
!
var posts []Itm
results := Items().Find(bson.M{"channelkey": key}).Sort("-date").Limit(20)
results.All(&posts)
!
if len(posts) == 0 {
four04(c, "No Articles")
return
}
...
server.go  -  pt  1
229
...

var currentChannel Chnl
err := Channels().Find(bson.M{"key": key}).One(&currentChannel)
if err != nil {
if string(err.Error()) == "not found" {
four04(c, "Channel not found")
return
} else {
fmt.Println(err)
}
}
!
obj := gin.H{"title": currentChannel.Title,
"header": currentChannel.Title, "posts": posts, "channels": AllChannels()}
!
c.HTML(200, "full.html", obj)
}
server.go  -  pt  2
230
displaying  

A  post
231
func serverRun(cmd *cobra.Command, args []string) {
...
r.GET("/post/*key", channelRoute)
r.Run(":" + port)
}
server.go
232
func postRoute(c *gin.Context) {
key := c.Params.ByName("key")
!
if len(key) < 2 {
four04(c, "Invalid Post")
return
}
!
key = key[1:]
!
var ps []Itm
r := Items().Find(bson.M{"key": key}).Sort("-date").Limit(1)
r.All(&ps)
!
if len(ps) == 0 {
four04(c, "Post not found")
return
}
...
server.go  -  Pt  1
233
...

!
var posts []Itm
results := Items().Find(bson.M{"date": bson.M{"$lte": ps[0].Date}}).Sort("-date").Limit(20)
results.All(&posts)
!
obj := gin.H{"title": ps[0].Title, "posts": posts, "channels": AllChannels()}
!
c.HTML(200, "full.html", obj)
}
server.go  -  Pt  2
234
Looking  Good
http://localhost:1138 235
Tweet  Break
Making my own planet in #go with @spf13

at #OSCON http://j.mp/go-planet
https://
github.com/spf13/
firstGoApp-
Planet/tree/
step8
237
Step  9  


Advanced  Routes
238
Congrats
•You’ve made it really far
•Now the training wheels are off
•Let’s try to add pagination & search
240
Hints
•You will need a new index
•We’re talking full text here
•You will also need a new route
241
...
r.GET("/", homeRoute)
r.GET("/post/*key", postRoute)
r.GET("/search/*query", searchRoute)
r.GET("/static/*filepath", staticServe)
r.GET("/channel/*key", channelRoute)
...
server.go
242
Step  10  
!
Add  Polish
243
What’s  next  ?
•Add ‘truncate’ command to remove old posts
and channels
•Change root command to run fetcher &
server
•Add infinite scroll capabilities 244
What’s  next  ?
•Make it so users can provide their own
static files & templates
•Documentation
•Blog posts
245
In  Conclusion
246
Go mascot designed by Renée French and copyrighted under the Creative Commons Attribution 3.0 license.
Thank  yOU 247
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
@spf13
•Author of Hugo, Cobra, Viper
& More
•Chief Developer Advocate for
MongoDB
•Gopher 249

Weitere ähnliche Inhalte

Was ist angesagt?

Happy Go Programming
Happy Go ProgrammingHappy Go Programming
Happy Go ProgrammingLin Yo-An
 
Monitoring and Debugging your Live Applications
Monitoring and Debugging your Live ApplicationsMonitoring and Debugging your Live Applications
Monitoring and Debugging your Live ApplicationsRobert Coup
 
Go for SysAdmins - LISA 2015
Go for SysAdmins - LISA 2015Go for SysAdmins - LISA 2015
Go for SysAdmins - LISA 2015Chris McEniry
 
OSCON2014 : Quick Introduction to System Tools Programming with Go
OSCON2014 : Quick Introduction to System Tools Programming with GoOSCON2014 : Quick Introduction to System Tools Programming with Go
OSCON2014 : Quick Introduction to System Tools Programming with GoChris McEniry
 
Vim Script Programming
Vim Script ProgrammingVim Script Programming
Vim Script ProgrammingLin Yo-An
 
Learning Python from Data
Learning Python from DataLearning Python from Data
Learning Python from DataMosky Liu
 
Introduction to Google's Go programming language
Introduction to Google's Go programming languageIntroduction to Google's Go programming language
Introduction to Google's Go programming languageMario Castro Contreras
 
Elegant concurrency
Elegant concurrencyElegant concurrency
Elegant concurrencyMosky Liu
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring ClojurescriptLuke Donnet
 
Fighting API Compatibility On Fluentd Using "Black Magic"
Fighting API Compatibility On Fluentd Using "Black Magic"Fighting API Compatibility On Fluentd Using "Black Magic"
Fighting API Compatibility On Fluentd Using "Black Magic"SATOSHI TAGOMORI
 
An Introduction to Go
An Introduction to GoAn Introduction to Go
An Introduction to GoCloudflare
 
Laying Pipe with Transmogrifier
Laying Pipe with TransmogrifierLaying Pipe with Transmogrifier
Laying Pipe with TransmogrifierClayton Parker
 
Redesigning Common Lisp
Redesigning Common LispRedesigning Common Lisp
Redesigning Common Lispfukamachi
 
XPath for web scraping
XPath for web scrapingXPath for web scraping
XPath for web scrapingScrapinghub
 
10 reasons to be excited about go
10 reasons to be excited about go10 reasons to be excited about go
10 reasons to be excited about goDvir Volk
 
Cookpad Hackarade #04: Create Your Own Interpreter
Cookpad Hackarade #04: Create Your Own InterpreterCookpad Hackarade #04: Create Your Own Interpreter
Cookpad Hackarade #04: Create Your Own Interpretermametter
 

Was ist angesagt? (20)

Happy Go Programming
Happy Go ProgrammingHappy Go Programming
Happy Go Programming
 
Monitoring and Debugging your Live Applications
Monitoring and Debugging your Live ApplicationsMonitoring and Debugging your Live Applications
Monitoring and Debugging your Live Applications
 
Go for SysAdmins - LISA 2015
Go for SysAdmins - LISA 2015Go for SysAdmins - LISA 2015
Go for SysAdmins - LISA 2015
 
OSCON2014 : Quick Introduction to System Tools Programming with Go
OSCON2014 : Quick Introduction to System Tools Programming with GoOSCON2014 : Quick Introduction to System Tools Programming with Go
OSCON2014 : Quick Introduction to System Tools Programming with Go
 
Golang
GolangGolang
Golang
 
Vim Script Programming
Vim Script ProgrammingVim Script Programming
Vim Script Programming
 
Learning Python from Data
Learning Python from DataLearning Python from Data
Learning Python from Data
 
Introduction to Google's Go programming language
Introduction to Google's Go programming languageIntroduction to Google's Go programming language
Introduction to Google's Go programming language
 
Lua and its Ecosystem
Lua and its EcosystemLua and its Ecosystem
Lua and its Ecosystem
 
Elegant concurrency
Elegant concurrencyElegant concurrency
Elegant concurrency
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring Clojurescript
 
Fighting API Compatibility On Fluentd Using "Black Magic"
Fighting API Compatibility On Fluentd Using "Black Magic"Fighting API Compatibility On Fluentd Using "Black Magic"
Fighting API Compatibility On Fluentd Using "Black Magic"
 
An Introduction to Go
An Introduction to GoAn Introduction to Go
An Introduction to Go
 
Laying Pipe with Transmogrifier
Laying Pipe with TransmogrifierLaying Pipe with Transmogrifier
Laying Pipe with Transmogrifier
 
Redesigning Common Lisp
Redesigning Common LispRedesigning Common Lisp
Redesigning Common Lisp
 
XPath for web scraping
XPath for web scrapingXPath for web scraping
XPath for web scraping
 
LuaJIT
LuaJITLuaJIT
LuaJIT
 
10 reasons to be excited about go
10 reasons to be excited about go10 reasons to be excited about go
10 reasons to be excited about go
 
IJTC%202009%20JRuby
IJTC%202009%20JRubyIJTC%202009%20JRuby
IJTC%202009%20JRuby
 
Cookpad Hackarade #04: Create Your Own Interpreter
Cookpad Hackarade #04: Create Your Own InterpreterCookpad Hackarade #04: Create Your Own Interpreter
Cookpad Hackarade #04: Create Your Own Interpreter
 

Ähnlich wie Getting Started with Go

Untangling fall2017 week2
Untangling fall2017 week2Untangling fall2017 week2
Untangling fall2017 week2Derek Jacoby
 
Untangling fall2017 week2_try2
Untangling fall2017 week2_try2Untangling fall2017 week2_try2
Untangling fall2017 week2_try2Derek Jacoby
 
これからのPerlプロダクトのかたち(YAPC::Asia 2013)
これからのPerlプロダクトのかたち(YAPC::Asia 2013)これからのPerlプロダクトのかたち(YAPC::Asia 2013)
これからのPerlプロダクトのかたち(YAPC::Asia 2013)goccy
 
Why my Go program is slow?
Why my Go program is slow?Why my Go program is slow?
Why my Go program is slow?Inada Naoki
 
Open Source Tools for Leveling Up Operations FOSSET 2014
Open Source Tools for Leveling Up Operations FOSSET 2014Open Source Tools for Leveling Up Operations FOSSET 2014
Open Source Tools for Leveling Up Operations FOSSET 2014Mandi Walls
 
Cape Cod Web Technology Meetup - 3
Cape Cod Web Technology Meetup - 3Cape Cod Web Technology Meetup - 3
Cape Cod Web Technology Meetup - 3Asher Martin
 
Package manages and Puppet - PuppetConf 2015
Package manages and Puppet - PuppetConf 2015Package manages and Puppet - PuppetConf 2015
Package manages and Puppet - PuppetConf 2015ice799
 
Packaging perl (LPW2010)
Packaging perl (LPW2010)Packaging perl (LPW2010)
Packaging perl (LPW2010)p3castro
 
Golang - Overview of Go (golang) Language
Golang - Overview of Go (golang) LanguageGolang - Overview of Go (golang) Language
Golang - Overview of Go (golang) LanguageAniruddha Chakrabarti
 
Geecon 2019 - Taming Code Quality in the Worst Language I Know: Bash
Geecon 2019 - Taming Code Quality  in the Worst Language I Know: BashGeecon 2019 - Taming Code Quality  in the Worst Language I Know: Bash
Geecon 2019 - Taming Code Quality in the Worst Language I Know: BashMichał Kordas
 
Write microservice in golang
Write microservice in golangWrite microservice in golang
Write microservice in golangBo-Yi Wu
 
MobileConf 2021 Slides: Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides:  Let's build macOS CLI Utilities using SwiftMobileConf 2021 Slides:  Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides: Let's build macOS CLI Utilities using SwiftDiego Freniche Brito
 
Programming in Linux Environment
Programming in Linux EnvironmentProgramming in Linux Environment
Programming in Linux EnvironmentDongho Kang
 
Burp plugin development for java n00bs (44 con)
Burp plugin development for java n00bs (44 con)Burp plugin development for java n00bs (44 con)
Burp plugin development for java n00bs (44 con)Marc Wickenden
 
Dependencies Managers in C/C++. Using stdcpp 2014
Dependencies Managers in C/C++. Using stdcpp 2014Dependencies Managers in C/C++. Using stdcpp 2014
Dependencies Managers in C/C++. Using stdcpp 2014biicode
 
plackdo, plack-like web interface on perl6
plackdo, plack-like web interface on perl6plackdo, plack-like web interface on perl6
plackdo, plack-like web interface on perl6Nobuo Danjou
 
Composer JSON kills make files
Composer JSON kills make filesComposer JSON kills make files
Composer JSON kills make filesropsu
 
Burp Plugin Development for Java n00bs - 44CON 2012
Burp Plugin Development for Java n00bs - 44CON 2012Burp Plugin Development for Java n00bs - 44CON 2012
Burp Plugin Development for Java n00bs - 44CON 201244CON
 
Dependent things dependency management for apple sw - slideshare
Dependent things   dependency management for apple sw - slideshareDependent things   dependency management for apple sw - slideshare
Dependent things dependency management for apple sw - slideshareCavelle Benjamin
 

Ähnlich wie Getting Started with Go (20)

Untangling fall2017 week2
Untangling fall2017 week2Untangling fall2017 week2
Untangling fall2017 week2
 
Untangling fall2017 week2_try2
Untangling fall2017 week2_try2Untangling fall2017 week2_try2
Untangling fall2017 week2_try2
 
これからのPerlプロダクトのかたち(YAPC::Asia 2013)
これからのPerlプロダクトのかたち(YAPC::Asia 2013)これからのPerlプロダクトのかたち(YAPC::Asia 2013)
これからのPerlプロダクトのかたち(YAPC::Asia 2013)
 
Why my Go program is slow?
Why my Go program is slow?Why my Go program is slow?
Why my Go program is slow?
 
Open Source Tools for Leveling Up Operations FOSSET 2014
Open Source Tools for Leveling Up Operations FOSSET 2014Open Source Tools for Leveling Up Operations FOSSET 2014
Open Source Tools for Leveling Up Operations FOSSET 2014
 
Cape Cod Web Technology Meetup - 3
Cape Cod Web Technology Meetup - 3Cape Cod Web Technology Meetup - 3
Cape Cod Web Technology Meetup - 3
 
Package manages and Puppet - PuppetConf 2015
Package manages and Puppet - PuppetConf 2015Package manages and Puppet - PuppetConf 2015
Package manages and Puppet - PuppetConf 2015
 
Packaging perl (LPW2010)
Packaging perl (LPW2010)Packaging perl (LPW2010)
Packaging perl (LPW2010)
 
Golang - Overview of Go (golang) Language
Golang - Overview of Go (golang) LanguageGolang - Overview of Go (golang) Language
Golang - Overview of Go (golang) Language
 
Geecon 2019 - Taming Code Quality in the Worst Language I Know: Bash
Geecon 2019 - Taming Code Quality  in the Worst Language I Know: BashGeecon 2019 - Taming Code Quality  in the Worst Language I Know: Bash
Geecon 2019 - Taming Code Quality in the Worst Language I Know: Bash
 
Go. why it goes v2
Go. why it goes v2Go. why it goes v2
Go. why it goes v2
 
Write microservice in golang
Write microservice in golangWrite microservice in golang
Write microservice in golang
 
MobileConf 2021 Slides: Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides:  Let's build macOS CLI Utilities using SwiftMobileConf 2021 Slides:  Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides: Let's build macOS CLI Utilities using Swift
 
Programming in Linux Environment
Programming in Linux EnvironmentProgramming in Linux Environment
Programming in Linux Environment
 
Burp plugin development for java n00bs (44 con)
Burp plugin development for java n00bs (44 con)Burp plugin development for java n00bs (44 con)
Burp plugin development for java n00bs (44 con)
 
Dependencies Managers in C/C++. Using stdcpp 2014
Dependencies Managers in C/C++. Using stdcpp 2014Dependencies Managers in C/C++. Using stdcpp 2014
Dependencies Managers in C/C++. Using stdcpp 2014
 
plackdo, plack-like web interface on perl6
plackdo, plack-like web interface on perl6plackdo, plack-like web interface on perl6
plackdo, plack-like web interface on perl6
 
Composer JSON kills make files
Composer JSON kills make filesComposer JSON kills make files
Composer JSON kills make files
 
Burp Plugin Development for Java n00bs - 44CON 2012
Burp Plugin Development for Java n00bs - 44CON 2012Burp Plugin Development for Java n00bs - 44CON 2012
Burp Plugin Development for Java n00bs - 44CON 2012
 
Dependent things dependency management for apple sw - slideshare
Dependent things   dependency management for apple sw - slideshareDependent things   dependency management for apple sw - slideshare
Dependent things dependency management for apple sw - slideshare
 

Mehr von Steven Francia

State of the Gopher Nation - Golang - August 2017
State of the Gopher Nation - Golang - August 2017State of the Gopher Nation - Golang - August 2017
State of the Gopher Nation - Golang - August 2017Steven Francia
 
The Future of the Operating System - Keynote LinuxCon 2015
The Future of the Operating System -  Keynote LinuxCon 2015The Future of the Operating System -  Keynote LinuxCon 2015
The Future of the Operating System - Keynote LinuxCon 2015Steven Francia
 
What every successful open source project needs
What every successful open source project needsWhat every successful open source project needs
What every successful open source project needsSteven Francia
 
Build your first MongoDB App in Ruby @ StrangeLoop 2013
Build your first MongoDB App in Ruby @ StrangeLoop 2013Build your first MongoDB App in Ruby @ StrangeLoop 2013
Build your first MongoDB App in Ruby @ StrangeLoop 2013Steven Francia
 
Modern Database Systems (for Genealogy)
Modern Database Systems (for Genealogy)Modern Database Systems (for Genealogy)
Modern Database Systems (for Genealogy)Steven Francia
 
Introduction to MongoDB and Hadoop
Introduction to MongoDB and HadoopIntroduction to MongoDB and Hadoop
Introduction to MongoDB and HadoopSteven Francia
 
MongoDB, Hadoop and humongous data - MongoSV 2012
MongoDB, Hadoop and humongous data - MongoSV 2012MongoDB, Hadoop and humongous data - MongoSV 2012
MongoDB, Hadoop and humongous data - MongoSV 2012Steven Francia
 
Big data for the rest of us
Big data for the rest of usBig data for the rest of us
Big data for the rest of usSteven Francia
 
OSCON 2012 MongoDB Tutorial
OSCON 2012 MongoDB TutorialOSCON 2012 MongoDB Tutorial
OSCON 2012 MongoDB TutorialSteven Francia
 
Replication, Durability, and Disaster Recovery
Replication, Durability, and Disaster RecoveryReplication, Durability, and Disaster Recovery
Replication, Durability, and Disaster RecoverySteven Francia
 
Multi Data Center Strategies
Multi Data Center StrategiesMulti Data Center Strategies
Multi Data Center StrategiesSteven Francia
 
NoSQL databases and managing big data
NoSQL databases and managing big dataNoSQL databases and managing big data
NoSQL databases and managing big dataSteven Francia
 
MongoDB, Hadoop and Humongous Data
MongoDB, Hadoop and Humongous DataMongoDB, Hadoop and Humongous Data
MongoDB, Hadoop and Humongous DataSteven Francia
 
Hybrid MongoDB and RDBMS Applications
Hybrid MongoDB and RDBMS ApplicationsHybrid MongoDB and RDBMS Applications
Hybrid MongoDB and RDBMS ApplicationsSteven Francia
 
Building your first application w/mongoDB MongoSV2011
Building your first application w/mongoDB MongoSV2011Building your first application w/mongoDB MongoSV2011
Building your first application w/mongoDB MongoSV2011Steven Francia
 
MongoDB, E-commerce and Transactions
MongoDB, E-commerce and TransactionsMongoDB, E-commerce and Transactions
MongoDB, E-commerce and TransactionsSteven Francia
 
MongoDB, PHP and the cloud - php cloud summit 2011
MongoDB, PHP and the cloud - php cloud summit 2011MongoDB, PHP and the cloud - php cloud summit 2011
MongoDB, PHP and the cloud - php cloud summit 2011Steven Francia
 

Mehr von Steven Francia (20)

State of the Gopher Nation - Golang - August 2017
State of the Gopher Nation - Golang - August 2017State of the Gopher Nation - Golang - August 2017
State of the Gopher Nation - Golang - August 2017
 
The Future of the Operating System - Keynote LinuxCon 2015
The Future of the Operating System -  Keynote LinuxCon 2015The Future of the Operating System -  Keynote LinuxCon 2015
The Future of the Operating System - Keynote LinuxCon 2015
 
What every successful open source project needs
What every successful open source project needsWhat every successful open source project needs
What every successful open source project needs
 
Build your first MongoDB App in Ruby @ StrangeLoop 2013
Build your first MongoDB App in Ruby @ StrangeLoop 2013Build your first MongoDB App in Ruby @ StrangeLoop 2013
Build your first MongoDB App in Ruby @ StrangeLoop 2013
 
Modern Database Systems (for Genealogy)
Modern Database Systems (for Genealogy)Modern Database Systems (for Genealogy)
Modern Database Systems (for Genealogy)
 
Introduction to MongoDB and Hadoop
Introduction to MongoDB and HadoopIntroduction to MongoDB and Hadoop
Introduction to MongoDB and Hadoop
 
Future of data
Future of dataFuture of data
Future of data
 
MongoDB, Hadoop and humongous data - MongoSV 2012
MongoDB, Hadoop and humongous data - MongoSV 2012MongoDB, Hadoop and humongous data - MongoSV 2012
MongoDB, Hadoop and humongous data - MongoSV 2012
 
Big data for the rest of us
Big data for the rest of usBig data for the rest of us
Big data for the rest of us
 
OSCON 2012 MongoDB Tutorial
OSCON 2012 MongoDB TutorialOSCON 2012 MongoDB Tutorial
OSCON 2012 MongoDB Tutorial
 
Replication, Durability, and Disaster Recovery
Replication, Durability, and Disaster RecoveryReplication, Durability, and Disaster Recovery
Replication, Durability, and Disaster Recovery
 
Multi Data Center Strategies
Multi Data Center StrategiesMulti Data Center Strategies
Multi Data Center Strategies
 
NoSQL databases and managing big data
NoSQL databases and managing big dataNoSQL databases and managing big data
NoSQL databases and managing big data
 
MongoDB, Hadoop and Humongous Data
MongoDB, Hadoop and Humongous DataMongoDB, Hadoop and Humongous Data
MongoDB, Hadoop and Humongous Data
 
MongoDB and hadoop
MongoDB and hadoopMongoDB and hadoop
MongoDB and hadoop
 
MongoDB for Genealogy
MongoDB for GenealogyMongoDB for Genealogy
MongoDB for Genealogy
 
Hybrid MongoDB and RDBMS Applications
Hybrid MongoDB and RDBMS ApplicationsHybrid MongoDB and RDBMS Applications
Hybrid MongoDB and RDBMS Applications
 
Building your first application w/mongoDB MongoSV2011
Building your first application w/mongoDB MongoSV2011Building your first application w/mongoDB MongoSV2011
Building your first application w/mongoDB MongoSV2011
 
MongoDB, E-commerce and Transactions
MongoDB, E-commerce and TransactionsMongoDB, E-commerce and Transactions
MongoDB, E-commerce and Transactions
 
MongoDB, PHP and the cloud - php cloud summit 2011
MongoDB, PHP and the cloud - php cloud summit 2011MongoDB, PHP and the cloud - php cloud summit 2011
MongoDB, PHP and the cloud - php cloud summit 2011
 

Getting Started with Go

  • 1. Building   your  first   Go  App 1 Go mascot designed by Renée French and copyrighted under the Creative Commons Attribution 3.0 license.
  • 2. @spf13 •Author of Hugo, Cobra, Viper & More •Chief Developer Advocate for MongoDB •Gopher 2
  • 3.
  • 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
  • 7.
  • 8. Plan •Introduce Go Language •Introduce Tools & Libraries •Build our application •Tell the world how awesome we are 8
  • 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
  • 11. Installing  Go •You should already have Go installed •If you don’t, do it NOW •Installation Guide 11
  • 12. Installing  MongoDB •You should already have MongoDB installed •If you don’t, do it NOW •Installation Guide 12
  • 13. Git  &  Mercurial •Lastly we need Git & Mercurial •http://git-scm.com/downloads •http://mercurial.selenic.com/wiki/Download 13
  • 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
  • 22. package main ! import "fmt" ! func main() { fmt.Println(“Hello, 世界") } Hello  World 22
  • 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
  • 35. Lets  write   some  code   ! Introduce  the     go  tools 35
  • 36. package main ! import "fmt" ! func main() { fmt.Println("Hello,World") } Hello  World 36 hello.go
  • 37. ❯ go run hello.go
 
 Hello,World Go  Run 37
  • 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
  • 41. package main ! import "testing" ! func TestOne(t *testing.T) { one := false if !one { t.Errorf(“Test Failed”) } } Hello  Test 41 hello_test.go
  • 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.
  • 44.
  • 45. Why  Planet? •CLI application •Web application •Good introduction •Right sized •Database (MongoDB) •Concurrency 45
  • 46. Steps 0. Env Setup 1. Commands 2. Configuration 3. Working with Feeds 4. DB as Storage 5-6. Web Server 7-8. DB -> Templates 9. & 10. Add Polish 46
  • 47. Step  0   
 Setting  up  our   environment 47
  • 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
  • 50. ❯ mkdir $HOME/go
 ! ❯ export 
 GOPATH=$HOME/go Setting  up 50
  • 51. export GOPATH=$USER/go export GOROOT=`go env GOROOT` PATH=$PATH:$GOPATH/bin Linux  &  Mac 51 Add this to your ~/.bashrc (or equivalent)
  • 53. Go  PAth •/home/user/gocode/ ($GOPATH) • src/ (put your source code here) • bin/ (binaries installed here) • pkg/ (installed package objects) 53
  • 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
  • 56. package main ! import "fmt" ! func main() { fmt.Println(“My Project") } main.go 56
  • 57. ❯ go run main.go
 
 My Project Run  it 57
  • 58. 58 I’m on the #gopath with @spf13 at #OSCON
 http://j.mp/onGoPath Tweet  Break
  • 59. Step  1   
 Creating  the   Command(s) 59
  • 60. Defining  
 our  first   command 60
  • 61. Structs •Short for structure •Objectish … blend of data & methods, but no inheritance •Really cheap. Struct{} is free (0 bytes). 61
  • 62. Functions •Can have multiple return values •No overloading •No optional parameters (but variadic) 62
  • 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
  • 68. // Copyright © 2014 Steve Francia <spf@spf13.com>. // // Use of this source code is governed by an Apache2 // license that can be found in the LICENSE file. ! package commands ! import ( "fmt" "os" ! "github.com/spf13/cobra" ) planet.go  (1) 68
  • 69. Path  =  Url go get uses it to install 69
  • 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
  • 75. func Execute() { err := RootCmd.Execute() if err != nil { fmt.Println(err) os.Exit(-1) } } planet.go  (3) 75
  • 76. // Copyright © 2014 Steve Francia <spf@spf13.com>. // // Use of this source code is governed by an Apache2 // license that can be found in the LICENSE file. ! package main ! import "github.com/spf13/firstGoApp-Planet/commands" ! func main() { commands.Execute() } main.go 76 Make sure to use your path
  • 77. ❯ go run main.go
 Dagobah runs ! ❯ go run main.go help Running  it 77
  • 79. Creating #CobraCommands with @spf13 at #OSCON http://j.mp/cobracmd Tweet  Break
  • 80. Step  2   
 Easy  Configuration 80
  • 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
  • 85. package main ! import ( "errors" "fmt" ) ! var Foo int ! func Zero() (int, error) { return 0, errors.New("yo") } ! ! func main() { ! Foo = 10 ! fmt.Println("outer:", Foo) // 10 ! if Foo, err := Zero(); err != nil { fmt.Println("inner:", Foo) // 0 } ! fmt.Println("outer again:", Foo) // still 10 } :=  Trap 85http://play.golang.org/p/i4L9Ao1P65
  • 86. Viper •A configuration manager •Easy loading of config files •Registry for application settings •Designed to work well with (or without) Cobra 86
  • 87. go get -u 
 github.com/spf13/viper Getting  Viper 87
  • 88. // Copyright © 2014 Steve Francia <spf@spf13.com>. // // Use of this source code is governed by an Apache2 // license that can be found in the LICENSE file. ! package commands ! import ( "fmt" "os" ! "github.com/spf13/cobra" "github.com/spf13/viper" ) planet.go  (1) 88
  • 89. var CfgFile string ! func init() { cobra.OnInitialize(initConfig)
 RootCmd.PersistentFlags().StringVar(&CfgFile, "config", "", "config file (default is $HOME/dagobah/config.yaml)") } ! func initConfig() { if CfgFile != "" { viper.SetConfigFile(CfgFile) } viper.SetConfigName("config") viper.AddConfigPath("/etc/dagobah/") viper.AddConfigPath("$HOME/.dagobah/") viper.ReadInConfig() } planet.go  (2) 89
  • 91. appname: "Dagobah" feeds: - "http://spf13.com/index.xml" - "http://dave.cheney.net/feed" - "http://www.goinggo.net/feeds/posts/default" - "http://blog.labix.org/feed" - "http://blog.golang.org/feed.atom" ! $HOME/.dagobah/config.yaml 91
  • 93. var RootCmd = &cobra.Command{ Use: "...", Short: `...`, Long: `...`, Run: rootRun, } ! func rootRun(cmd *cobra.Command, args []string) { fmt.Println(viper.Get("feeds")) fmt.Println(viper.GetString("appname")) } planet.go  (3) 93
  • 94. ❯ go run main.go
 [http://spf13.com/index.xml http:// dave.cheney.net/feed http:// www.goinggo.net/feeds/posts/default http://blog.labix.org/feed http:// blog.golang.org/feed.atom]
 
 Dagobah Running  it 94
  • 95. I got bit by the #goviper at #OSCON 
 http://j.mp/go-viper Tweet  Break
  • 97. Step  3   
 Working  with  Feeds 97
  • 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
  • 104. import ( "time" ... ) ! func addCommands() { RootCmd.AddCommand(fetchCmd) } ! func Execute() { addCommands() ... } planet.go 104
  • 105. // Copyright © 2014 Steve Francia <spf@spf13.com>. // // Use of this source code is governed by an Apache2 // license that can be found in the LICENSE file. ! package commands ! import ( "fmt" "os" "time" ! rss "github.com/jteeuwen/go-pkg-rss" "github.com/spf13/cobra" "github.com/spf13/viper" ) Fetch.Go  (1) 105
  • 106. Creating  our   own  type 106
  • 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
  • 109. type Config struct { Feeds []string Port int } Fetch.Go  (2) 109
  • 110. Defining  the   fetch   command 110
  • 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
  • 116. Fetching  in  a   goroutine 116
  • 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
  • 120. func fetchRun(cmd *cobra.Command, args []string) { 
 Fetcher() ! sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt) <-sigChan } Fetch.go  (4) 120
  • 121. func Fetcher() { var config Config if err := viper.Marshal(&config); err != nil { fmt.Println(err) } ! for _, feed := range config.Feeds { go PollFeed(feed.Url) } } Fetch.go  (5) 121
  • 123. Learning  about  go-pkg-rss •How do we learn how to use the package? 123
  • 124. Learning  about  go-pkg-rss •github.com/jteeuwen/go-pkg-rss •Readme is pretty lacking •godoc.org/github.com/jteeuwen/go-pkg-rss 124
  • 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
  • 128. func PollFeed(uri string) { timeout := viper.GetInt("RSSTimeout") if timeout < 1 { timeout = 1 } feed := rss.New(timeout, true, chanHandler, itemHandler) ! for { if err := feed.Fetch(uri, nil); err != nil { fmt.Fprintf(os.Stderr, "[e] %s: %s", uri, err) return } ! fmt.Printf("Sleeping for %d seconds on %sn", feed.SecondsTillUpdate(), uri) time.Sleep(time.Duration(feed.SecondsTillUpdate() * 1e9)) } } Fetch.GO  (6) 128
  • 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
  • 131. Tweet  Break I wrote my first goroutine at #OSCON with @spf13
  • 133. Step  4   
 Storing  in  
 the  Database 133
  • 135. MongoDB •Open Source •Document Database •Document == Struct or Document == Map •Works seamlessly with Go (and other languages) 135
  • 136. MongoDB •Fast & Scalable •Used by Disney, IBM, Metlife, eBay, Forbes, Craigslist, Cisco, Stripe 136
  • 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
  • 138. go get -u gopkg.in/mgo.v2 Getting  mgo 138
  • 140. // Copyright © 2014 Steve Francia <spf@spf13.com>. // // Use of this source code is governed by an Apache2 // license that can be found in the LICENSE file. ! package commands ! import ( "fmt" "os" ! "github.com/spf13/viper" "gopkg.in/mgo.v2" ) ! var mongodbSession *mgo.Session ! func init() { RootCmd.PersistentFlags().String("mongodb_uri", "localhost", "host where mongoDB is") viper.BindPFlag("mongodb_uri", RootCmd.PersistentFlags().Lookup(“mongodb_uri")) CreateUniqueIndexes() } MongoDB.go  (1) 140
  • 141. Setting  up  a   DB  session 141
  • 142. func DBSession() *mgo.Session { if mongodbSession == nil { uri := os.Getenv("MONGODB_URI") if uri == "" { uri = viper.GetString("mongodb_uri") ! if uri == "" { log.Fatalln("No connection uri for MongoDB provided") } } ! var err error mongodbSession, err = mgo.Dial(uri) if mongodbSession == nil || err != nil { log.Fatalf("Can't connect to mongo, go error %vn", err) } ! mongodbSession.SetSafe(&mgo.Safe{}) } return mongodbSession } MongoDB.go  (2) 142
  • 143. setting  up   some   shortcuts 143
  • 144. ! func DB() *mgo.Database { return DBSession().DB(viper.GetString("dbname")) } ! func Items() *mgo.Collection { return DB().C("items") } ! func Channels() *mgo.Collection { return DB().C("channels") } MongoDB.go  (3) 144
  • 146. func CreateUniqueIndexes() { idx := mgo.Index{ Key: []string{"key"}, Unique: true, DropDups: true, Background: true, Sparse: true, } ! if err := Items().EnsureIndex(idx); err != nil { fmt.Println(err) } ! if err := Channels().EnsureIndex(idx); err != nil { fmt.Println(err) } } MongoDB.go  (4) 146
  • 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
  • 152. type Itm struct { Date time.Time Key string ChannelKey string Title string FullContent string Links []*rss.Link Description string Author rss.Author Categories []*rss.Category Comments string Enclosures []*rss.Enclosure Guid *string `bson:",omitempty"` Source *rss.Source PubDate string Id string `bson:",omitempty"` Generator *rss.Generator Contributors []string Content *rss.Content Extensions map[string]map[string][]rss.Extension } fetch.go 152
  • 153. func itmify(o *rss.Item, ch *rss.Channel) Itm { var x Itm x.Title = o.Title x.Links = o.Links x.ChannelKey = ch.Key() x.Description = o.Description x.Author = o.Author x.Categories = o.Categories x.Comments = o.Comments x.Enclosures = o.Enclosures x.Guid = o.Guid x.PubDate = o.PubDate x.Id = o.Id x.Key = o.Key() x.Generator = o.Generator x.Contributors = o.Contributors x.Content = o.Content x.Extensions = o.Extensions x.Date, _ = o.ParsedPubDate() ! if o.Content != nil && o.Content.Text != "" { x.FullContent = o.Content.Text } else { x.FullContent = o.Description } ! return x } fetch.go 153
  • 154. type Chnl struct { Key string Title string Links []rss.Link Description string Language string Copyright string ManagingEditor string WebMaster string PubDate string LastBuildDate string Docs string Categories []*rss.Category Generator rss.Generator TTL int Rating string SkipHours []int SkipDays []int Image rss.Image ItemKeys []string Cloud rss.Cloud TextInput rss.Input Extensions map[string]map[string] []rss.Extension Id string Rights string Author rss.Author SubTitle rss.SubTitle } fetch.go 154
  • 155. func chnlify(o *rss.Channel) Chnl { var x Chnl x.Key = o.Key() x.Title = o.Title x.Links = o.Links x.Description = o.Description x.Language = o.Language x.Copyright = o.Copyright x.ManagingEditor = o.ManagingEditor x.WebMaster = o.WebMaster x.PubDate = o.PubDate x.LastBuildDate = o.LastBuildDate x.Docs = o.Docs x.Categories = o.Categories x.Generator = o.Generator x.TTL = o.TTL x.Rating = o.Rating x.SkipHours = o.SkipHours x.SkipDays = o.SkipDays x.Image = o.Image x.Cloud = o.Cloud x.TextInput = o.TextInput x.Extensions = o.Extensions x.Id = o.Id x.Rights = o.Rights x.Author = o.Author x.SubTitle = o.SubTitle ! ... ! return x } fetch.go 155
  • 156. ... ! ! var keys []string for _, y := range o.Items { keys = append(keys, y.Key()) } x.ItemKeys = keys ! ... fetch.go 156
  • 157. Storing   Feeds  &   Items 157
  • 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
  • 162. ❯ mongod
 
 MongoDB starting : pid=51054 port=27017 dbpath=/data/db Running  MongoDB 162
  • 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
  • 167. Tweet  Break Feeding mgo at #OSCON with @spf13 http://j.mp/mongomgo
  • 169. Step  5   
 Building  a  
 web  Server 169
  • 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
  • 171. Gin •Compatible with net/http •Uses Httprouter (really fast) •Familiar/Friendly Interface •Works well with JSON •Had to pick something 171
  • 174. // Copyright © 2014 Steve Francia <spf@spf13.com>. // // Use of this source code is governed by an Apache2 // license that can be found in the LICENSE file. ! package commands ! import ( "github.com/gin-gonic/gin" "github.com/spf13/cobra" "github.com/spf13/viper" ) Server.Go  (1) 174
  • 175. Defining  the   Server   command 175
  • 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
  • 178. Defining  our   first  route 178
  • 179. func serverRun(cmd *cobra.Command, args []string) { r := gin.Default() ! r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) ! port := viper.GetString("port") fmt.Println("Running on port:", port) r.Run(":" + port) } server.go  (3) 179
  • 180. ❯ go run dagobah.go server Running  it 180
  • 182. Tweet  Break I wrote a webserver in go using Gin 
 with @spf13 at #OSCON http://j.mp/gin-go
  • 184. Step  6   
 Building  a  
 Dynamic  Server 184
  • 185. Binary  Problem? •Go ships as a single binary •Need to load files from within the binary •Don’t want to embed by hand 185
  • 186. go.rice •Nicely allows local loads in dev, and embedded loads when executing binary •Stable, but not very mature yet •Best option I know of 186
  • 187. go get -u 
 github.com/GeertJohan/ go.rice Getting  Go.Rice 187
  • 189. Get  your   static  &   templates  on c.spf13.com/OSCON/step6-static.zip 189
  • 191. func serverRun(cmd *cobra.Command, args []string) { ...
 r.GET("/static/*filepath", staticServe) ! port := viper.GetString("port") fmt.Println("Running on port:", port) r.Run(":" + port) } server.go 191
  • 192. func staticServe(c *gin.Context) { static, err := rice.FindBox("static") if err != nil { log.Fatal(err) } ! original := c.Request.URL.Path c.Request.URL.Path = c.Params.ByName("filepath") fmt.Println(c.Params.ByName("filepath")) http.FileServer(static.HTTPBox()).ServeHTTP(c.Writer, c.Request) c.Request.URL.Path = original } server.go 192
  • 193. Loading  &   Serving     Templates 193
  • 194. func loadTemplates(list ...string) *template.Template { templateBox, err := rice.FindBox("templates") if err != nil { log.Fatal(err) } templates := template.New("") ! for _, x := range list { templateString, err := templateBox.String(x) if err != nil { log.Fatal(err) } ! // get file contents as string _, err = templates.New(x).Parse(templateString) if err != nil { log.Fatal(err) } } return templates } server.go 194
  • 195. func serverRun(cmd *cobra.Command, args []string) { r := gin.Default() templates := loadTemplates("full.html") r.SetHTMLTemplate(templates) ! r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) ! r.GET("/", homeRoute) r.GET("/static/*filepath", staticServe)
 ! port := viper.GetString("port") fmt.Println("Running on port:", port) r.Run(":" + port) } server.go 195
  • 196. func homeRoute(c *gin.Context) { obj := gin.H{"title": "Go Rules"} c.HTML(200, “full.html", obj) } server.go 196
  • 197. ❯ go run dagobah.go server Running  it 197
  • 199. Tweet  Break No more mr rice guy 
 with @spf13 at #OSCON http://j.mp/go-rice
  • 201. Step  7   
 Connecting  the  Data   to  The  templates 201
  • 202. Go  Templates •Really nice to work with •Very simple, yet very powerful •Safe •Go Template Primer 202
  • 204. > db.items.find().sort({ "date" : -1 }).limit(1).pretty() { "_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  Schema 204
  • 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
  • 207. func homeRoute(c *gin.Context) { var posts []Itm results := Items().Find(bson.M{}).Sort("-date").Limit(20) results.All(&posts) ! obj := gin.H{"title": "Go Rules", "posts": posts} c.HTML(200, "full.html", obj) } server.go 207
  • 208. ... <section id="latest-list" class="ui divided inbox selection list active tab" data-tab="recent"> {{ range $item := .posts }} {{ if $item.WorthShowing }} <a class="item" href=“#{{$item.Key | urlquery }}"> <div class="description">{{ $item.Title }}</div> <div class="right floated ui label small">{{ $item.Date.Format "Jan 2, 2006" }}</div> </a> {{ end }} {{ end }} </section> ... Full.html 208
  • 210. func (i Itm) FirstLink() (link rss.Link) { if len(i.Links) == 0 || i.Links[0] == nil { return } return *i.Links[0] } ! func (i Itm) WorthShowing() bool { if len(i.FullContent) > 100 { return true } return false } fetch.go 210
  • 212. ... <main> {{ with .message}}! <h1 class="ui header large"> {{.}} </h1>! {{ end }}! ! {{ range $item := .posts }}! {{ if $item.WorthShowing }}! <article data-key="{{$item.Key}}">! <header>! <a name="{{$item.Key}}">! <h1 class="ui header">{{$item.Title}}</h1>! <section class="meta-tags">! <a class="ui label large blue author" href="/channel/{{$item.ChannelKey}}">{{$item.Author.Name}}</a>! <span class="large ui label date">{{ $item.Date.Format "Jan 2, 2006" }}</span>! </section>! </header>! <section class="main-content">! {{$item.FullContent | html }}! </section>! <footer>! {{with $item.FirstLink}}! <a class="ui basic button" href="{{.Href}}">Source</a>! {{end}}! <div class="ui divider"></div>! </footer>! </article>! {{ end }}! {{ else }}! No Articles! {{ end }}! </main> ... full.html 212
  • 214. func loadTemplates(list ...string) *template.Template { templateBox, err := rice.FindBox("templates") if err != nil { log.Fatal(err) } ! templates := template.New("") ! for _, x := range list { templateString, err := templateBox.String(x) if err != nil { log.Fatal(err) } ! // get file contents as string _, err = templates.New(x).Parse(templateString) if err != nil { log.Fatal(err) } } ! funcMap := template.FuncMap{ "html": ProperHtml, "title": func(a string) string { return strings.Title(a) }, } ! templates.Funcs(funcMap) ! return templates } server.go 214
  • 215. func ProperHtml(text string) template.HTML { if strings.Contains(text, "content:encoded>") || strings.Contains(text, "content/:encoded>") { text = html.UnescapeString(text) } return template.HTML(html.UnescapeString(template.HTMLEscapeString(text))) } server.go 215
  • 217. Tweet  Break Conquering Go Templates 
 with @spf13 at #OSCON
  • 219. Step  8   
 More  Routes 219
  • 221. func (c Chnl) HomePage() string { if len(c.Links) == 0 { return "" } ! url, err := url.Parse(c.Links[0].Href) if err != nil { log.Println(err) } return url.Scheme + "://" + url.Host } fetch.go 221
  • 222. ! func four04(c *gin.Context, message string) { c.HTML(404, "full.html", gin.H{"message": message, "title": message}) } server.go 222
  • 223. func AllChannels() []Chnl { var channels []Chnl r := Channels().Find(bson.M{}).Sort("-lastbuilddate") r.All(&channels) return channels } MongoDB.go 223
  • 225. func homeRoute(c *gin.Context) { var posts []Itm results := Items().Find(bson.M{}).Sort("-date").Limit(20) results.All(&posts) ! obj := gin.H{"title": "Go Rules", 
 "posts": posts, "channels": AllChannels()} c.HTML(200, "full.html", obj) } server.go 225
  • 226. ... <section id="channel-list" 
 class="ui large inverted vertical menu tab" data-tab=“channels"> <a class="item js-navigate" href="/" >! <i class="external home icon"></i>! <span class="ui name" href=""> All </span>! </a>! {{ range $channel := .channels }}! <div class="item js-navigate-channel" data-href="/channel/{{$channel.Key}}" 
 data-key="{{$channel.Key}}" style="cursor:pointer;">! <a href="{{$channel.HomePage}}" class="ui float right"><i class="external url sign icon"></i></a>! <span class="ui name" href=""> {{$channel.Title}} </span>! <span class="ui label">{{ len $channel.Links }}</span>! </div>! {{end}}! </section> ... full.html 226
  • 228. func serverRun(cmd *cobra.Command, args []string) { ... r.GET("/channel/*key", channelRoute) r.Run(":" + port) } server.go 228
  • 229. func channelRoute(c *gin.Context) { key := c.Params.ByName("key") if len(key) < 2 { four04(c, "Channel Not Found") return } ! key = key[1:] ! fmt.Println(key) ! var posts []Itm results := Items().Find(bson.M{"channelkey": key}).Sort("-date").Limit(20) results.All(&posts) ! if len(posts) == 0 { four04(c, "No Articles") return } ... server.go  -  pt  1 229
  • 230. ...
 var currentChannel Chnl err := Channels().Find(bson.M{"key": key}).One(&currentChannel) if err != nil { if string(err.Error()) == "not found" { four04(c, "Channel not found") return } else { fmt.Println(err) } } ! obj := gin.H{"title": currentChannel.Title, "header": currentChannel.Title, "posts": posts, "channels": AllChannels()} ! c.HTML(200, "full.html", obj) } server.go  -  pt  2 230
  • 232. func serverRun(cmd *cobra.Command, args []string) { ... r.GET("/post/*key", channelRoute) r.Run(":" + port) } server.go 232
  • 233. func postRoute(c *gin.Context) { key := c.Params.ByName("key") ! if len(key) < 2 { four04(c, "Invalid Post") return } ! key = key[1:] ! var ps []Itm r := Items().Find(bson.M{"key": key}).Sort("-date").Limit(1) r.All(&ps) ! if len(ps) == 0 { four04(c, "Post not found") return } ... server.go  -  Pt  1 233
  • 234. ...
 ! var posts []Itm results := Items().Find(bson.M{"date": bson.M{"$lte": ps[0].Date}}).Sort("-date").Limit(20) results.All(&posts) ! obj := gin.H{"title": ps[0].Title, "posts": posts, "channels": AllChannels()} ! c.HTML(200, "full.html", obj) } server.go  -  Pt  2 234
  • 236. Tweet  Break Making my own planet in #go with @spf13
 at #OSCON http://j.mp/go-planet
  • 238. Step  9   
 Advanced  Routes 238
  • 239.
  • 240. Congrats •You’ve made it really far •Now the training wheels are off •Let’s try to add pagination & search 240
  • 241. Hints •You will need a new index •We’re talking full text here •You will also need a new route 241
  • 242. ... r.GET("/", homeRoute) r.GET("/post/*key", postRoute) r.GET("/search/*query", searchRoute) r.GET("/static/*filepath", staticServe) r.GET("/channel/*key", channelRoute) ... server.go 242
  • 243. Step  10   ! Add  Polish 243
  • 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