SlideShare a Scribd company logo
BUILDING AN
AWESOME CLI
APP IN GO 1
2
ASHLEY MAC
•Dev Advocate at Rackspace
•Go newbie
•Slightly sarcastic
3
–Ashley Mac
“I have no idea what
i’m doing”
4
SPF13
•Willfully Unemployed
•Builds Cool Things With Go AKA
Gopher
•Irritatingly Specific
5
–Steve
“I Kinda Know What I'm
Doing”
6
MAKE SURE YOU
HAVE GO INSTALLED
AND WORKING +
AN EDITOR
7
UX OF
CLI 8
HUMAN
INTERFACE
GUIDELINES
FOR CLIS 9
UNIx
PHILOSOPHY
10
KEN'S "UNIx
PHILOSOPHY"11
UNIx PHILOSOPHY
•Simple
•Clear
•Composable

•Extensible
•Modular
•Small
12
– Rob Pike
“Many UNIX programs do quite
trivial things in isolation,
but, combined with other
programs, become general and
useful tools.”
13
– Doug McIlroy
“The manual page, which
really used to be a manual
page, is now a small volume,
with a thousand options”
14
POSIx +
GNU 15
COMMANDS
16
WHAT ARE
COMMANDS
? 17
› ls
c:dir
COMMANDS
18
› ls
› cp
› cat
› cd
list
copy
concatenate
change directory
ABBREVIATED
19
› ls
› cp
› cat
› cd
SHORT
20
Short
Clear
&
› ls
CONTExT
21
operates in current
Directory
THE
LANGUAGE OF
COMMANDS 22
› ls
HAS A LANGUAGE
23
List the contents

of the directory I'm in
› ls
› rm
› zip
› find
COMMANDS
24
Verbs
c:dir
COMMANDS
25
Noun?
ARGS
26
WHAT ARE
ARGS?
27
› rm [file]
› cp [file] [newfile]
c:copy [file] [newfile]
INPUT
28


> rm [file] ... [fileN]
MANY INPUTS
29
Arg0 Argn


> cp [file] [newfile]
ORDER MATTERS
30
From To


> cp [file] [newfile]
SEPARATED
31
Space separates
THE
LANGUAGE
OF ARGS 32


> cp [file] [newfile]
DIRECT OBJECT
33
Verb Noun Noun


> cp [file] [newfile]
IS PROUNCABLE
34
Copy this file to here
OPTIONS
35
FLAGS
36
› rm [options] [file]
c:del [options] [file]
MODIFY ACTIONS
37


› rm -f badfile.txt
SEPARATORS
38
Space separates


› rm --force
PREFIxED
39
prefix


› rm -f
PREFIxED
40
prefix


c: del /F
PREFIxED
41
prefix


-f == --force
SHORT VS LONG
42
Common Options
shortened


› rm -r -f rm -rf
STACKABLE
43
Short options stack
THE
LANGUAGE
OF FLAGS 44


› rm --force [file]
ADVERB
45
Verb Adverb Noun


› rm --force [file]
PRONOUNCEABLE
46
Forcefully remove

this file


› rm --force [file]
PRONOUNCEABLE
47
remove this file
with Force


› ls --color /home/spf13
FLAG INPUT
48
Verb Adverb Noun


› ls --color /home/spf13
PRONOUNCEABLE
49
Colorfully list my
home directory
› ls -a
MODIFY BEHAVIOR
50
› ls -a
MODIFY BEHAVIOR
51
List all the things
ALL ISN'T
AN ADVERB
52
ADVERBS ExPRESS
•manner
•place
•time
•frequency
•degree
•level of
certainty
•etc.
53
ADVERBS ANSWER
•How?
•In what way?
•When?
•Where?
•To what
extent?
54
› ls -a
MODIFY BEHAVIOR
55
List completely
to what extent?


› ls --width=40
IMPUTABLE
56
Input
to what extent?


› ls --width 40
IMPUTABLE
57
Input
to what extent?


› ls --width 40
PREPOSITION
58
Verb Preposition Obj


› ls --width 40
PRONOUNCEABLE
59
list the directory with
a width of 40 cols
PREP PHRASE = ADVERB
•consists of a preposition and its
object
•acts as an adverb
•"Speaking at OSCON"
60
BAD FLAG
DESIGN
61
FLAGS AS
ACTIONS62


› tar -xcvf
FLAG = ACTION
63
› tar
First option must be a mode
specifier:
-c Create -r Add/Replace 

-t List -u Update -x Extract
FLAG = ACTION
64
› zip
› unzip
BETTER
65
FLAGS WITH
FLAGS
66
Extract: tar -x [options]
-k Keep existing files
-m Don't restore mod times
FLAGS HAVING SUB FLAGS
67
Create: tar -c [options]
-z, -j, -J, --lzma
Compress archive with gzip/
bzip2/xz/lzma
FLAGS HAVING SUB FLAGS
68
INCOMPATIBLE
FLAGS
69
ls [options]
-S sort by file size
-t sort by modification time
-U do not sort
...
INCOMPATIBLE FLAGS
70
ls -StU
INCOMPATIBLE FLAGS
71
What should this do?
> ls
--sort=[size,modtime,none]
BETTER
72
DOUBLE
FLAGS 73
› git pull --stat --no-stat
FLAG --NO-FLAG
74
› git pull --stat
› git pull --stat=false
BETTER
75
CLI APPS
76
› httpd
› vi
› emacs
› git
CLI APPS
77
Noun
APPS
•Launch something
•Do more than one thing
•Collection of commands
78
SUB
COMMANDS
79
› svn add
› brew install
› npm search
› apt-get upgrade
› git clone
SUB COMMANDS
80
SUB COMMANDS
•CLI apps do multiple things
•Apps are groups of commands
•(sub) Commands have flags & args
•All rules still apply
81


› brew fetch -v hugo
ExPANDED RESOURCES
82
Cmd ArgApp Flag


› brew install hugo
NOUN
83
Verb ObjectNoun


› brew install hugo
PRONOUNCABLE
84
Brew, install hugo


› brew fetch -v hugo
PRONOUNCABLE
85
Verb Object
Noun adVerb


› brew fetch -v hugo
PRONOUNCABLE
86
Brew, verbosely 

fetch hugo
GO
INTRODUCTION
87
MY
ExPERIENCE
88
GOPATH AND SETUP
•You WILL store your code in a GitHub
user folder (example: $GOPATH/src/
github.com/username/helloworld)
•This was a pain in the ass
•I was comfortable with /code /dev/
or /projects 89
GOPATH AND SETUP
•By Storing code on github, I was
able to share my many problems
•Going from “I’m working on this”
to “let’s collaborate”
90
GOPATH
•The Go toolset uses an environment variable
called GOPATH to find Go source code.
•You can set GOPATH to anything you want,
but things will be easier if it’s set in your
home directory.
91
Windows:
c: setx GOPATH %USERPROFILE%


OS X:
❯ echo 'export GOPATH=$HOMEn' >> ~/.bash_profile
Close the terminal, reopen it, and type the following:
❯ echo $GOPATH
GO PATH
92
GOPATH AND SETUP
•Typing go get github.com/user/
project will download and build a
project.
93
EDITORS
•No IDE needed - any text editor will do.
•helpful features like autocomplete and
format & import on-save
•If you’re not sure what to use, I
recommend Atom — It’s free, cross-
platform, and easy to install. 94
PLUGINS
•Atom: https://github.com/joefitzgerald/go-plus
•Vim: https://github.com/fatih/vim-go
•included in http://vim.spf13.com/
•IntelliJ: 

https://plugins.jetbrains.com/plugin/?id=5047
•Full list: 

https://github.com/golang/go/wiki/
IDEsAndTextEditorPlugins 95
YOU DON’T NEED A
FRAMEWORK!
•The standard library has tons!
•Web server
•Templates
•Database
•etc.. 96
YOU DON’T NEED A
FRAMEWORK!
•Many Packages work
well together
•Very modular &
Composable 97
STANDARD LIBRARY
Let’s be honest, you don’t want to write everything from scratch so
most programming depends on your ability to interface with existing
libraries. i.e. packages. Here are a few core packages you should
know about;
•Strings
•Input/Output (io/ioutil)
•Errors
•fmt
98
• Containers and Sort
• path/filepath
• HTTP (net/http)
• math/rand
GO
99
STATICALLY

TYPED
100
STRONGLY

TYPED
101
COMPILED
102
MEMORY
MANAGED
103
POWERFUL
CONCURRENCY

BAKED IN
104
OPEN
SOURCE105
CROSS
PLATFORM
106
LANGUAGE
DESIGN
107
108
•Ken Thompson (B,C, Unix, UTF-8)
•Rob Pike (Unix, UTF-8)
•Robert Griesmier (Hotspot, JVM, V8)
MAJOR INFLUENCES
•C & derivatives
•Pascal & derivatives
•CSP
109
IDEALS
•Expressibility
•Edibility
•Powerful
•Simple
•Scalable
110
SPEC
•Java Spec : 670 pages
•YAML Spec : 84 pages
•Go Spec : 82 pages
111
KEYWORDS
•break
•default
•func
•interface
•select
•case
•defer
•go 112
•map
•struct
•chan
•else
•goto
•package
•switch
•const
•fallthrough
•if
•range
•type
•continue
•for
•import
•return
•var
BRACES
113
Fail
BRACES
Compile Eror
114
Compile Error
/tmp/sandbox826898458/main.go:6: syntax error: unexpected
semicolon or newline before {
BRACES
What works
115
Works
VARIABLES
116
Fail
VARIABLES
117
Error
/tmp/sandbox473116179/main.go:6: one declared and not used /tmp/
sandbox473116179/main.go:7: two declared and not used /tmp/
sandbox473116179/main.go:8: three declared and not used
WHAT GO
DOESN’T
HAVE 118
CLASSES 

( * SHOCKED
EXPRESSION *)119
OBJECTS
120
COMPLExITY
121
TYPES
122
SINGLE
VALUE
TYPES 123
NUMBERS
•Integers 

(numbers without a decimal)
•Floating-Point Numbers 

(numbers that contain a decimal)
• int, int8-64, uint, uint8-64, float32,64
124
STRINGS
•A string is a sequence of
characters
•Go strings are immutable
•Go strings are made up of
individual bytes (Usually one for each character)
125
MULTI VALUE
TYPES
126
type person struct {

name string

age int

}
STRUCT
127
ARRAY
•An array is an ordered sequence
of elements of a single type
•Fixed length
•Arrays are indexed starting from 0
128
SLICE
•Segment of an array
•Dynamic length
•Can be used without thinking
about array underneath
129
MAP
•Unordered collection of key-value
pairs
•Similar to associative arrays, hash
tables, and dictionaries
•Dynamic Length 130
SOME 

OTHER
TYPES 131
FUNCTION
•Function is a type
•First class citizen in Go
•Can have multiple input values
•Can have multiple return values
132
POINTERS
•Reference a location in memory
where a value is stored
•Represented using '*'
•Memory location referenced using '&'
133
DEFINE YOUR OWN TYPES
•Composed of other types
•Not aliases
134
METHOD
•Function defined on a type
135
TOOLING
136
GO HELP
The Go toolset has many different commands and
subcommands. You can pull up a list by typing:
go help
You now have everything you need to get started
137
GO FMT
•Formats your go code for you
•Awesome to do "on save"
•End of all stylistic debates
138
GO TEST
Writing code isn’t easy and humans make
mistakes so testing is really important, luckily, Go
includes a program that makes writing tests easier:
go test
Fun Fact: The Go compiler knows to ignore code
in files ending with _test.go
139
CLOSING
THOUGHTS
140
I THINK GO
IS AWESOME
141
IT HAS
STRONG
OPINIONS 142
COMPILATION IS
VERY FAST
(USUALLY A
SECOND OR TWO)143
AWESOME
COMMUNITY
144
RESOURCES
•Getting Started, official golang page — https://golang.org/doc/
•Parse’s move from Ruby to Golang — http://blog.parse.com/
learn/how-we-moved-our-api-from-ruby-to-go-and-saved-our-sanity/
•Tutorial — Creating a Wiki — https://golang.org/doc/articles/
wiki/ (this was the first big tutorial that got me to build something
useful, take this one slow to get a grasps on its concepts)
•Golang — Concurrency is not Parallelism (Rob Pike), this video I
found super informative about go’s concurency and got me excited
to keep coding in Golang — https://youtu.be/cN_DpYBzKso
145
LET'S BUILD
AN APP
146
147
HTTP://
WWW.SLIDESH
ARE.NET/SPF13
148
HTTPS://
GITHUB.COM
/SPF13/TRI 149
1. DESIGNING
OUR APP
150
WHAT'S IN
A NAME?
151
SHOCKING
AMOUNT OF
TODO APPS 152
LET'S MAKE A
BUNCH MORE
153
I'M CALLING
MINE "TRI"
154
FEATURES
155
FEATURES
•Add Todo
•List Todos
•Mark "done"
•Search/Filter
•Priorities
•Archive
•Edit
•Create Dates
•Due Dates
•Tags
•Projects
156
INTERFACE
DESIGN
157
ADDING
158
› tri add "Add Priorities"
ADD
159
› tri add Add Priorities
ADD
160


› tri add "Add Priorities"
ADD
161
Verb Object
Noun
› tri add 

"Add Multi Todo Support" 

"Consider usage behaviors"
ADD
162
PRIORITY
163
› tri add -p1 "Add listing"





ADD WITH PRIORITY
164
› tri add -p1 "Add listing"





ADD WITH PRIORITY
165
Verb Object
Noun adVerb
› tri add -p1 "Add listing"





PRONOUNCEABLE
166
Tri, add "Add listing"
Todo with a pri of 1


› tri add "Add listing P:1"





ALTERNATE SYNTAx
167
CONSIDERATIONS
•What priority system to use?
•Numeric
•Alpha
•High, Middle, Low
•What's the default priority? 168
MY TODO
•High, Middle, Low
•H=1, L=3, M/_=2
•Default is 2
169
LISTING
170


› tri ls





LISTING
171


› tri list





LISTING
172


› tri





LISTING
173
› tri list
(1) Add Listing
Consider usage behaviors
Add Multi Todo Support
Add Priorities
LISTING OUTPUT
174
› tri list
(1) Add Listing
Add Priorities
Add Multi Todo Support
Consider usage behaviors
LISTING OUTPUT
175
› tri list
(H) Add Listing
Consider usage behaviors
Add Priorities
(L) Add Multi Todo Support
LISTING OUTPUT
176
› tri list
(H) Add Listing
Consider usage behaviors
Add Priorities
(L) Add Multi Todo Support
LISTING OUTPUT
177
› tri list
1. (H) Add Listing
2. Consider usage behaviors
3. Add Priorities
4. (L) Add Multi Todo Support
LISTING OUTPUT
178
FILTERING
179


› tri list done





TOKENS
180


› tri list -p1





FLAGS
181
› tri list -p1
› tri list --due June
› tri list --created 12/15
› tri list --done -p1
FILTER BY PROPERTY
182
› tri list -p2
2. Consider usage behaviors
3. Add Priorities
FILTER BY PRIORITY
183
› tri list "Add"
1. (H) Add Listing
3. Add Priorities
4. (L) Add Multi Todo Support
SEARCHING
184
› tri list "Add" "Pri"
3. Add Priorities
SEARCHING
185
UPDATING
186
› tri list
1. (H) Add Listing
2. Consider usage behaviors
3. Add Priorities
4. (L) Add Multi Todo Support
LISTING OUTPUT
187


› tri done 2





COMPLETING
188


› tri edit 1 "Improve Listing"




EDITING
189
› tri edit 1 -p2
› tri edit 2 --due 05/13/15
› tri edit 3 --created
12/15
EDITING
190
› tri edit 1 -p2
› tri list -p2
› tri edit 3 --created 12/15
› tri list --created 12/15
CONSISTENCY
191
› tri edit 1 2 3 -p2
BATCH EDIT?
192
2. CREATING
A PROJECT
193
COBRA
194
•A CLI Command Framework
•A tool to generate CLI apps & commands
•Powers Kubernetes, Dropbox, Git Lfs,
CoreOS, Docker, Delve ...
195
› go get -u 
github.com/spf13/cobra/cobra

GET & INSTALL COBRA
196
› cobra
Cobra is a Cli library for Go that empowers applications. This

application is a tool to generate the needed files to quickly

create a Cobra application.
Usage:
cobra [command]
Available Commands:
add Add a command to a Cobra Application
COBRA
197
COBRA
APP
BUILDER 198
› cobra init 

github.com/<handle>/tri 
-a "<Your Name>"
COBRA INIT
199
Replace with your url,

project name & Name
› cobra init ...
Your Cobra application is
ready at
/Users/spf13/gopath/src/
github.com/spf13/tri
COBRA
200
› cd $GOPATH/src/
github.com/<name>/tri
CD TO PROJECT
201
Replace with your url,
project name & Name
› tree
.
├── LICENSE
├── cmd
│   └── root.go
└── main.go
LOOK AT YOUR PROJECT
202
› go build
› ./tri


A longer description that spans multiple lines
and likely contains examples
and usage of using your application. For
example...
BUILD & RUN IT
203
YOU'VE JUST
CREATED YOUR
1ST GO APP
204
IT'S ALL
UPHILL FROM
HERE 205
LET'S WRITE
SOME CODE
206
OPEN THE
PROJECT IN
AN EDITOR 207
208
LiteIDE
209
HTTPS://SOURCEFORGE.NET/PROJECTS/
LITEIDE/FILES/X29/ 210
WORKING
WITH THE
ROOT 211
package cmd



import (

"fmt"

"os"



"github.com/spf13/cobra"

"github.com/spf13/viper"

)
CMD/ROOT.GO
212
package cmd



import (

"fmt"

"os"



"github.com/spf13/cobra"

"github.com/spf13/viper"

)
CMD/ROOT.GO
213
Notice package
name
Matches Dir
// This represents the base command when called
without any subcommands

var RootCmd = &cobra.Command{

Use: "tri",

Short: "A brief description of your
application",

Long: `A longer description that spans multiple
lines and likely ... application.`,

}
CMD/ROOT.GO
214
// This represents the base command when called
without any subcommands

var RootCmd = &cobra.Command{

Use: "tri",

Short: "Tri is a todo application",

Long: `Tri will help you get more done in less time.

It's designed to be as simple as possible to help you
accomplish your goals.`,
}
CMD/ROOT.GO
215
var RootCmd = &cobra.Command{

Use: "tri",

...
CMD/ROOT.GO
216
Package level variable
& Exported
MAIN
217
MAIN MAIN MAIN
•Go programs are all about "main"
•main.go (convention)
•main package
•main()
218
package main



import "github.com/<yours>/tri/cmd"



func main() {

cmd.Execute()

}
MAIN.GO
219
package main



import "github.com/<yours>/tri/cmd"



func main() {

cmd.Execute()

}
MAIN.GO
220
Package
Name
package main



import "github.com/<yours>/tri/cmd"



func main() {

cmd.Execute()

}
MAIN.GO
221
Function
Name
func Execute() {

if err := RootCmd.Execute(); err !=
nil {

fmt.Println(err)

os.Exit(-1)

}

}
CMD/ROOT.GO
222
Package level

variable
>go run main.go
Tri will help you get more done in
less time.
It's designed to be as simple as
possible to help you accomplish
your goals.
RUN IT
223
3. CREATING
OUR ADD
COMMAND 224
ADD
"ADD" 225
> cd $GOPATH/src/
github.com/spf13/tri
CD TO PROJECT
226
Replace with your url,
project name & Name
> cobra add add
add created at $GOPATH/src/
github.com/spf13/tri/cmd/
add.go
COBRA ADD ADD
227
> go run main.go add
add called
RUN "ADD"
228
Bill wants me to replace go run with 

go build

./tri
MAKE 

"ADD" ADD229
package cmd
CMD/ADD.GO
230
var addCmd = &cobra.Command{

Use: "add",

Short: "A brief description of your command",

Long: `A longer description that spans multiple
lines and likely...`,

Run: func(cmd *cobra.Command, args []string) {

// TODO: Work your own magic here

fmt.Println("add called")

},

}
CMD/ADD.GO
231
var addCmd = &cobra.Command{

Use: "add",

Short: "Add a new todo",

Long: `Add will create a new todo item to the list`,

Run: func(cmd *cobra.Command, args []string) {

// TODO: Work your own magic here

fmt.Println("add called")

},

}
CMD/ADD.GO
232
func addRun(cmd *cobra.Command,
args []string){
fmt.Println("add called")
}
CMD/ADD.GO
233
var addCmd = &cobra.Command{

Use: "add",

Short: "Add a new todo",

Long: `Add will create a new todo
item to the list`,

Run: addRun,

}
CMD/ADD.GO
234
func addRun(cmd *cobra.Command,
args []string) {

for _, x := range args {

fmt.Println(x)

}

}
CMD/ADD.GO
235
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 index/key, y is value
•_ allows you to ignore naming variables
236


func init() {

RootCmd.AddCommand(addCmd)

}
CMD/ADD.GO
237
INIT()
•Special function
•Called after package variable declarations
•Called prior to main.main()
•Each package may have multiple init()
•init() order un-guaranteed
238
> go run main.go add 
"one two" three


one two
three
RUNNING ADD
239
4. CREATING
OUR DATA
MODEL 240
CREATE A
NEW
PACKAGE 241
242
New Folder
New File
package todo



type Item struct {

Text string

}

TODO/TODO.GO
243
NAMED TYPES
•Can be any known type (struct,
string, int, slice, a new type you’ve
declared, etc)
•Methods can be declared on it
•Not an alias - Explicit type 244
USING OUR
NEW TYPE
245


import (

"fmt"



"github.com/spf13/cobra"

"github.com/<yourname>/tri/todo"

)
CMD/ADD.GO
246
Replace with
yourS
func addRun(...) {

items := []todo.Item{}

for _, x := range args {

items = append(items, todo.Item{Text:x})

}

fmt.Println(items)

}
CMD/ADD.GO
247
func addRun(...) {

items := []todo.Item{}

for _, x := range args {

items = append(items, todo.Item{Text:x})

}

fmt.Println(items)

}
CMD/ADD.GO
248
APPEND
•Append adds new values to a slice
•Append will grow a slice as
needed
249
func addRun(...) {

items := []todo.Item{}

for _, x := range args {

items = append(items, todo.Item{Text:x})

}

fmt.Println(items)

}
CMD/ADD.GO
250
func addRun(...) {

items := []todo.Item{}

for _, x := range args {

items = append(items, todo.Item{Text:x})

}

fmt.Println(items)

}
CMD/ADD.GO
251
>go run main.go add 

"one two" three
[{one two} {three}]
GO RUN
252
func addRun(...) {

var items = []todo.Item{}

for _,x := range args {

items = append(items, todo.Item{Text:x})

}

fmt.Printf("%#vn", items)

}
CMD/ADD.GO
253
>go run main.go add 

"one two" three
[]todo.Item{todo.Item{Text:
"one two"},
todo.Item{Text:"three"}}
GO RUN
254
5. PERSISTING
OUR DATA
255
SAVING
DATA 256
func SaveItems(filename string,

items []Item) error {



return nil

}
TODO/TODO.GO
257
JSON
258
import (

"encoding/json"

)
TODO/TODO.GO
259
func SaveItems(filename string, items []Item) error {

b, err := json.Marshal(items)

if err != nil {

return err

}

fmt.Println(string(b))



return nil

}
TODO/TODO.GO
260
func SaveItems(filename string, items []Item) error {

b, err := json.Marshal(items)

if err != nil {

return err

}

fmt.Println(string(b))



return nil

}
TODO/TODO.GO
261
func SaveItems(filename string, items []Item) error {

b, err := json.Marshal(items)

if err != nil {

return err

}

fmt.Println(string(b))



return nil

}
TODO/TODO.GO
262
ERROR HANDLING
•Errors are not exceptional, they
are just values
•No exceptions in Go
•Errors should be handled when
they occur 263
( DON’T) PANIC
•Only use when:
1. You want to shut down your program AND
2. You need a stack trace
•Packages should never call Panic (only applications)
•Do not use as pseudo-exception handling
•Only recover a panic if you know you can properly
recover from it 264
func SaveItems(filename string, items []Item) error {

b, err := json.Marshal(items)

if err != nil {

return err

}

fmt.Println(string(b))



return nil

}
TODO/TODO.GO
265
func addRun(cmd *cobra.Command, 

args []string) {

var items = []todo.Item{}

for _, x := range args {

items = append(items, todo.Item{Text: x})

}

todo.SaveItems("x", items)

}
CMD/ADD.GO
266
>go run main.go add 
"one two" three
[{"Text":"one two"},
{"Text":"three"}]
CHECK JSON CREATION
267
WRITING
TO FILES268
import (

"io/ioutil"

"encoding/json"

)
TODO/TODO.GO
269
func SaveItems(filename string, items []Item) error {

...

err = ioutil.WriteFile(filename, b, 0644)

if err != nil {

return err

}



return nil

}
TODO/TODO.GO
270
func addRun(cmd *cobra.Command, 

args []string) {

var items = []todo.Item{}

for _, x := range args {

items = append(items, todo.Item{Text: x})

}


err := todo.SaveItems("/Users/spf13/.tridos.json", items);
if err != nil {

fmt.Errorf("%v", err)

}

}
CMD/ADD.GO
271
› go run main.go add "one two" three
› cat ~/.tridos.json
[{"Text":"one two"},
{"Text":"three"}]
CHECK FILE CREATION
272
READING

DATA 273
func ReadItems(filename
string) ([]Item, error) {



return []Item{}, nil

}
TODO/TODO.GO
274
func ReadItems(filename
string) ([]Item, error) {



return []Item{}, nil

}
TODO/TODO.GO
275
func ReadItems(filename string)
([]Item, error) {

b, err := ioutil.ReadFile(filename)

if err != nil {

return []Item{}, err

}
...
TODO/TODO.GO
276
func ReadItems(filename string)
([]Item, error) {

b, err := ioutil.ReadFile(filename)

if err != nil {

return []Item{}, err

}
...
TODO/TODO.GO
277
func ReadItems(filename string) ([]Item, error) {
...

var items []Item

if err := json.Unmarshal(b, &items); err != nil {

return []Item{}, err

}

return items, nil
}
TODO/TODO.GO
278
func ReadItems(filename string) ([]Item, error) {
...

var items []Item

if err := json.Unmarshal(b, &items); err != nil {

return []Item{}, err

}

return items, nil
}
TODO/TODO.GO
279
func ReadItems(filename string) ([]Item, error) {
...

var items []Item

if err := json.Unmarshal(b, &items); err != nil {

return []Item{}, err

}

return items, nil
}
TODO/TODO.GO
280
func ReadItems(filename string) ([]Item, error) {
...

var items []Item

if err := json.Unmarshal(b, &items); err != nil {

return []Item{}, err

}

return items, nil
}
TODO/TODO.GO
281
func ReadItems(filename string) ([]Item, error) {
...

var items []Item

if err := json.Unmarshal(b, &items); err != nil {

return []Item{}, err

}

return items, nil
}
TODO/TODO.GO
282
LIST
COMMAND
283
› cobra add list
list created at $GOPATH/
src/github.com/spf13/tri/
cmd/list.go
ADD LIST COMMAND
284
Run: func(cmd *cobra.Command, args []string) {

items, err := todo.ReadItems("/Users/
spf13/.tridos.json")


if err != nil {

log.Printf("%v", err)

}

fmt.Println(items)

},
CMD/LIST.GO
285
Run: func(cmd *cobra.Command, args []string) {

items, err := todo.ReadItems("/Users/
spf13/.tridos.json")


if err != nil {

log.Printf("%v", err)

}

fmt.Println(items)

},
CMD/LIST.GO
286
Run: func(cmd *cobra.Command, args []string) {

items, err := todo.ReadItems("/Users/
spf13/.tridos.json")


if err != nil {

log.Printf("%v", err)

}

fmt.Println(items)

},
CMD/LIST.GO
287
› go run main.go list
[{one two} {three}]
RUN LIST
288
func addRun(cmd *cobra.Command, args []string) {

var items = []todo.Item{}




for _, x := range args {

items = append(items, todo.Item{Text: x})

}
...
CMD/ADD.GO
289
func addRun(cmd *cobra.Command, args []string) {

items, err := todo.ReadItems("/Users/spf13/.tridos.json")

if err != nil {

log.Printf("%v", err)

}
for _, x := range args {

items = append(items, todo.Item{Text: x})

}
...
CMD/ADD.GO
290
6. ADDING
ROOT 

(GLOBAL)
FLAGS 291
USING
$HOME 292
› go get github.com/
mitchellh/go-homedir
GO GET
293
package cmd



import (

...

"github.com/mitchellh/go-homedir"

)
CMD/ROOT.GO
294


var dataFile string
CMD/ROOT.GO
295
func init() {

// Here you will define your flags and configuration settings

// Cobra supports Persistent Flags which if defined here will
be global for your application



home, err := homedir.Dir()

if err != nil {

log.Println("Unable to detect home directory. Please set
data file using --datafile.")

}
...
CMD/ROOT.GO
296
ADDING
A FLAG297
func init() {
...

RootCmd.PersistentFlags().StringVar(&dataFile,

"datafile",

home+string(os.PathSeparator)+".tridos.json",

"data file to store todos")
...
CMD/ROOT.GO
298
func init() {
...


RootCmd.PersistentFlags().StringVar(&dataFile,

"datafile",

home+string(os.PathSeparator)+".tridos.json",

"data file to store todos")
CMD/ROOT.GO
299
func init() {
...


RootCmd.PersistentFlags().StringVar(&dataFile,

"datafile",

home+string(os.PathSeparator)+".tridos.json",

"data file to store todos")
CMD/ROOT.GO
300
func init() {
...


RootCmd.PersistentFlags().StringVar(&dataFile,

"datafile",

home+string(os.PathSeparator)+".tridos.json",

"data file to store todos")
CMD/ROOT.GO
301
items, err := todo.ReadItems(dataFile)
...

err := todo.SaveItems(dataFile, items)
CMD/ADD.GO
302


items, err := todo.ReadItems(dataFile)
CMD/LIST.GO
303
› go build
› ./tri
...
Flags:
--datafile string data file to store todos (default "/
Users/spf13/.tridos.json")
-h, --help help for tri
Use "tri [command] --help" for more information about a
command.
SEE THE FLAG
304
› go build
› ./tri add "Add priorities" 

--datafile $HOME/.next.json
› ./tri list --datafile $HOME/.next.json
[{Add priorities}]
USE THE FLAG
305
7. ADDING
PRIORITIES
306
› go run main.go add 
"add priorities" 

"order by priority"
ADD SOME TODOS
307
ADJUSTING
OUR TYPE
308
type Item struct {

Text string

Priority int

}
TODO/TODO.GO
309
VALIDATING
INPUT
310
func (i *Item) SetPriority(pri int) {

switch pri {

case 1:

i.Priority = 1

case 3:

i.Priority = 3

default:

i.Priority = 2

}

}
TODO/TODO.GO
311
func (i *Item) SetPriority(pri int) {

switch pri {

case 1:

i.Priority = 1

case 3:

i.Priority = 3

default:

i.Priority = 2

}

}
TODO/TODO.GO
312
func (i *Item) SetPriority (pri int) {

switch pri {

case 1:

i.Priority = 1

case 3:

i.Priority = 3

default:

i.Priority = 2

}

}
TODO/TODO.GO
313
ADDING
FLAG 314
var priority int
...

func init() {

RootCmd.AddCommand(addCmd)



addCmd.Flags().IntVarP(&priority, 

"priority", "p", 2, "Priority:1,2,3")
...
CMD/ADD.GO
315
var priority int
...

func init() {

RootCmd.AddCommand(addCmd)



addCmd.Flags().IntVarP(&priority, 

"priority", "p", 2, "Priority:1,2,3")
...
CMD/ADD.GO
316
› go build
› ./tri help add
Add will create a new todo item to the list
Usage:
tri add [flags]
Flags:
-p, --priority int Priority:1,2,3 (default 2)
HELP ADD
317
SETTING
PRIORITY318
func addRun(cmd *cobra.Command, args []string) {

...

for _, x := range args {

item := todo.Item{Text: x}

item.SetPriority(priority)

items = append(items, item)

}

CMD/ADD.GO
319
func addRun(cmd *cobra.Command, args []string) {

...

for _, x := range args {

item := todo.Item{Text: x}

item.SetPriority(priority)

items = append(items, item)

}

CMD/ADD.GO
320
› ./tri add "format list" -p1
› ./tri list
[{add priorities 0} {order by
priority 0} {format list 1}]
ADD WITH PRIORITY
321
8. MAKING
OUR LIST
PRETTY 322
BREAK OUT
LISTRUN
323
// listCmd respresents the list command

var listCmd = &cobra.Command{

Use: "list",

Short: "List the todos",

Long: `Listing the todos`,

Run: listRun,

}



func listRun(cmd *cobra.Command, args []string) {
...
}
CMD/LIST.GO
324
TAB-
WRITER325
func listRun(cmd *cobra.Command, args []string) {
...
w := tabwriter.NewWriter(os.Stdout, 3, 0, 1, ' ', 0)

for _, i := range items {

fmt.Fprintln(w, strconv.Itoa(i.Priority)+"t"+i.Text+"t")

}



w.Flush()
}
CMD/LIST.GO
326
func listRun(cmd *cobra.Command, args []string) {
...
w := tabwriter.NewWriter(os.Stdout, 3, 0, 1, ' ', 0)

for _, i := range items {

fmt.Fprintln(w, strconv.Itoa(i.Priority)+"t"+i.Text+"t")

}



w.Flush()
}
CMD/LIST.GO
327
func listRun(cmd *cobra.Command, args []string) {
...
w := tabwriter.NewWriter(os.Stdout, 3, 0, 1, ' ', 0)

for _, i := range items {

fmt.Fprintln(w, strconv.Itoa(i.Priority)+"t"+i.Text+"t")

}



w.Flush()
}
CMD/LIST.GO
328
func listRun(cmd *cobra.Command, args []string) {
...
w := tabwriter.NewWriter(os.Stdout, 3, 0, 1, ' ', 0)

for _, i := range items {

fmt.Fprintln(w, strconv.Itoa(i.Priority)+"t"+i.Text+"t")

}



w.Flush()
}
CMD/LIST.GO
329
func listRun(cmd *cobra.Command, args []string) {
...
w := tabwriter.NewWriter(os.Stdout, 3, 0, 1, ' ', 0)

for _, i := range items {

fmt.Fprintln(w, strconv.Itoa(i.Priority)+"t"+i.Text+"t")

}



w.Flush()
}
CMD/LIST.GO
330
› go run main.go list
0 add priorities
0 order by priority
1 format list
LIST W/PRIORITY
331
PRETTIER
PRIORITY

PRINTING 332
func (i *Item) PrettyP() string {

if i.Priority == 1 {

return "(1)"

}

if i.Priority == 3 {

return "(3)"

}



return " "

}
TODO/TODO.GO
333
func listRun(cmd *cobra.Command, args []string) {
...
w := tabwriter.NewWriter(os.Stdout, 3, 0, 1, ' ', 0)

for _, i := range items {

fmt.Fprintln(w, i.PrettyP()+"t"+i.Text+"t")

}



w.Flush()
}
CMD/LIST.GO
334
› go run main.go list
add priorities
order by priority
(1) format list
LIST W/PRIORITY
335
LABELS
336
type Item struct {

Text string

Priority int

position int

}
TODO/TODO.GO
337
type Item struct {

Text string

Priority int

position int

}
TODO/TODO.GO
338
Notice
Lowercase p
func (i *Item) Label() string {

return strconv.Itoa(i.position) + "."

}
TODO/TODO.GO
339
func ReadItems(filename string) ([]Item, error) {

...



for i, _ := range items {

items[i].position = i + 1

}



return items, nil

}
TODO/TODO.GO
340
› go run main.go list
1. add priorities
2. order by priority
3. (1) format list
LIST W/PRIORITY
341
SORT
342
// ByPri implements sort.Interface for []Item based on

// the Priority & position field.

type ByPri []Item



func (s ByPri) Len() int { return len(s) }

func (s ByPri) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s ByPri) Less(i, j int) bool {

if s[i].Priority == s[j].Priority {

return s[i].position < s[j].position

}

return s[i].Priority < s[j].Priority

}
TODO/TODO.GO
343
// ByPri implements sort.Interface for []Item based on

// the Priority & position field.

type ByPri []Item



func (s ByPri) Len() int { return len(s) }

func (s ByPri) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s ByPri) Less(i, j int) bool {

if s[i].Priority == s[j].Priority {

return s[i].position < s[j].position

}

return s[i].Priority < s[j].Priority

}
TODO/TODO.GO
344
// ByPri implements sort.Interface for []Item based on

// the Priority & position field.

type ByPri []Item



func (s ByPri) Len() int { return len(s) }

func (s ByPri) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s ByPri) Less(i, j int) bool {

if s[i].Priority == s[j].Priority {

return s[i].position < s[j].position

}

return s[i].Priority < s[j].Priority

}
TODO/TODO.GO
345
// ByPri implements sort.Interface for []Item based on

// the Priority & position field.

type ByPri []Item



func (s ByPri) Len() int { return len(s) }

func (s ByPri) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s ByPri) Less(i, j int) bool {

if s[i].Priority == s[j].Priority {

return s[i].position < s[j].position

}

return s[i].Priority < s[j].Priority

}
TODO/TODO.GO
346
// ByPri implements sort.Interface for []Item based on

// the Priority & position field.

type ByPri []Item



func (s ByPri) Len() int { return len(s) }

func (s ByPri) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s ByPri) Less(i, j int) bool {

if s[i].Priority == s[j].Priority {

return s[i].position < s[j].position

}

return s[i].Priority < s[j].Priority

}
TODO/TODO.GO
347
// ByPri implements sort.Interface for []Item based on

// the Priority & position field.

type ByPri []Item



func (s ByPri) Len() int { return len(s) }

func (s ByPri) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s ByPri) Less(i, j int) bool {

if s[i].Priority == s[j].Priority {

return s[i].position < s[j].position

}

return s[i].Priority < s[j].Priority

}
TODO/TODO.GO
348


func listRun(cmd *cobra.Command, args []string) {

...



sort.Sort(todo.ByPri(items))



w := tabwriter.NewWriter(os.Stdout, 3, 0, 1, ' ', 0)
...
CMD/LIST.GO
349
› go run main.go list
3. (1) format list
1. add priorities
2. order by priority
LIST W/PRIORITY
350
9. DONE-ING

TODOS
351
ADD
DONE 352
› cobra add done
done created at $GOPATH/
src/github.com/spf13/tri/
cmd/done.go
COBRA ADD DONE
353
// doneCmd represents the done command

var doneCmd = &cobra.Command{

Use: "done",

Aliases: []string{"do"},

Short: "Mark Item as Done",

Run: doneRun,

}
CMD/DONE.GO
354
ADD 

.DONE 355
type Item struct {

Text string

Priority int

position int

Done bool

}
TODO/TODO.GO
356
TRI DONE 

SET 

.DONE 357
func doneRun(cmd *cobra.Command, args []string) {

items, err := todo.ReadItems(dataFile)

i, err := strconv.Atoi(args[0])



if err != nil {

log.Fatalln(args[0], "is not a valid labeln", err)

}
...
CMD/DONE.GO
358
Break out still
func doneRun(cmd *cobra.Command, args []string) {

...
if i > 0 && i < len(items) {

items[i-1].Done = true

fmt.Printf("%q %vn", items[i-1].Text, "marked done")


sort.Sort(todo.ByPri(items))

todo.SaveItems(dataFile, items)

} else {

log.Println(i, "doesn't match any items")

}

}
CMD/DONE.GO
359
Break out slide
› go run main.go done a
2016/05/14 22:22:03 a is not
a valid label
strconv.ParseInt: parsing
"a": invalid syntax
DONE WRONG
360
› go run main.go done 13
2016/05/14 22:44:06 13
doesn't match any items
DONE WRONG
361
› go run main.go done 1
DONE RIGHT
362
UPDATE
LISTING363
func (i *Item) PrettyDone() string {

if i.Done {

return "X"

}

return ""

}
TODO/TODO.GO
364
fmt.Fprintln(w, i.Label()
+"t"+i.PrettyDone()
+"t"+i.PrettyP()
+"t"+i.Text+"t")

CMD/LIST.GO
365
func (s ByPri) Less(i, j int) bool {

if s[i].Done == s[j].Done {

if s[i].Priority == s[j].Priority {

return s[i].position < s[j].position

}

return s[i].Priority < s[j].Priority

}

return !s[i].Done

}
TODO/TODO.GO
366
› go run main.go list
1. (1) format list
2. X order by priority
3. X add priorities
LIST
367
ADD
--DONE
FLAG 368
› go run main.go add "hide
done items"
ADD NEW TODO
369
fmt.Fprintln(w, i.Label()
+"t"+i.PrettyDone()
+"t"+i.PrettyP()
+"t"+i.Text+"t")

CMD/LIST.GO
370
var (

doneOpt bool

)
CMD/LIST.GO
371
func init() {

RootCmd.AddCommand(listCmd)



listCmd.Flags().BoolVar(&doneOpt,
"done", false, "Show 'Done' Todos ")
}
CMD/LIST.GO
372
func listRun(cmd *cobra.Command, args []string) {

...
for _, i := range items {

if i.Done == doneOpt {

fmt.Fprintln(w, i.Label()...)

}

}
CMD/LIST.GO
373
› go run main.go list --done
3. X order by priority
4. X add priorities
TRY --DONE
374
SHOW
ALL 375
var (

doneOpt bool

allOpt bool

)
CMD/LIST.GO
376
func init() {

...
listCmd.Flags().BoolVar(&allOpt,
"all", false, "Show all Todos")
}
CMD/LIST.GO
377
func listRun(cmd *cobra.Command, args []string) {

...
for _, i := range items {

if allOpt || i.Done == doneOpt {

fmt.Fprintln(w, i.Label()...)

}

}
CMD/LIST.GO
378
› go run main.go list --all --done
1. (1) format list
2. hide done items
3. X order by priority
4. X add priorities
TRY --ALL
379
10.
CONFIG380
›./tri list --datafile 
$HOME/Dropbox/Sync/tridos.json
›./tri add "Add config/ENV support" 
--datafile $HOME/Dropbox/Sync/tridos.json
USING DIFFERENT DATA FILE
381
CONFIG
FTW 382
•A configuration manager
•Registry for application settings
•Works well with Cobra
383
VIPER SUPPORTS
•YAML, TOML, JSON or HCL
•Etcd, Consul
•Config LiveReloading
•default < KeyVal < config < env < flag
•Aliases & Nested values 384
var cfgFile string
func init() {

cobra.OnInitialize(initConfig)
...

RootCmd.PersistentFlags().StringVar(&cfgFile,
"config", "", "config file (default is
$HOME/.tri.yaml)")

...
CMD/ROOT.GO
385
Already There
// Read in config file and ENV variables if set.

func initConfig() {

viper.SetConfigName(".tri") 

viper.AddConfigPath("$HOME")

viper.AutomaticEnv() 



// If a config file is found, read it in.

if err := viper.ReadInConfig(); err == nil {

fmt.Println("Using config file:", viper.ConfigFileUsed())

}
}
CMD/ROOT.GO
386
Already There
12 FACTOR
APPS
387
STRICT
SEPARATION OF
CONFIG FROM
CODE 388
CONFIG IS STUFF
THAT VARIES IN
DIFFERENT
ENVIRONMENTS 389
CODE IS STUFF
THAT STAYS THE
SAME
EVERYWHERE 390
THE 12 FACTOR
APP STORES
CONFIG IN ENV
VARS 391
READ
FROM
VIPER 392


func addRun(cmd *cobra.Command, args []string) {

items, err := todo.ReadItems(dataFile))
...
if err := todo.SaveItems(dataFile), items); err != nil {
CMD/ADD.GO
393


func addRun(cmd *cobra.Command, args []string) {

items, err := todo.ReadItems(viper.GetString("datafile"))
...
if err := todo.SaveItems(viper.GetString("datafile"), items);
err != nil {
CMD/ADD.GO
394


func doneRun(cmd *cobra.Command, args []string) {
...
items, err := todo.ReadItems(viper.GetString("datafile"))
...


todo.SaveItems(viper.GetString("datafile"), items)
CMD/DONE.GO
395


func listRun(cmd *cobra.Command, args []string) {
items, err := todo.ReadItems(viper.GetString("datafile"))
...
CMD/LIST.GO
396
ENV
397
›./tri list --datafile 
$HOME/Dropbox/Sync/tridos.json
›./tri add "Add config/ENV support" 
--datafile $HOME/Dropbox/Sync/tridos.json
USING DIFFERENT DATA FILE
398
› DATAFILE=$HOME/Dropbox/Sync/trido.json 
./tri list
› DATAFILE=$HOME/Dropbox/Sync/trido.json 
./tri add "Add config/ENV support"
USING ENV
399
› export DATAFILE=$HOME/Dropbox/Sync/
trido.json
› ./tri list
1. Add config/ENV support
2. Add config/ENV support
ExPORT FTW
400
PLAYING
NICE WITH
OTHERS 401
// Read in config file and ENV variables if set.

func initConfig() {

viper.SetConfigName(".tri") 

viper.AddConfigPath("$HOME")

viper.AutomaticEnv()
viper.SetEnvPrefix("tri")





// If a config file is found, read it in.

if err := viper.ReadInConfig(); err == nil {

fmt.Println("Using config file:", viper.ConfigFileUsed())

}
CMD/ROOT.GO
402
› export TRI_DATAFILE=$HOME/Dropbox/
Sync/trido.json
› ./tri list
1. Add config/ENV support
2. Add config/ENV support
ExPORT FTW
403
CONFIG
FILES 404
GOOD
FOR APPS405
› echo "datafile: /Users/
spf13/Dropbox/Sync/
trido.json" >
$HOME/.tri.yaml
CREATE CONFIG FILE
406
› go run main.go list
Using config file: /Users/
spf13/.tri.yaml
1. Add config/ENV support
2. Add config/ENV support
USE CONFIG FILE
407
11. WORKING
AHEAD
408
TRY TO
IMPLEMENT
ExTRA FEATURES
409
EDITING
410
SEARCH
411
FOLLOW US ON
TWITTER
@ASHLEYMCNAMARA
@SPF13
412
ADDITIONAL RESOURCES
•Ashley's Learn to Code Resources
•Steve's Blog
•Go Girls Who Code
413
END
414

More Related Content

PDF
GoLang Introduction
ODP
Архитектура программных систем на Node.js
PDF
7 Common Mistakes in Go (2015)
PDF
GraalVM Native and Spring Boot 3.0
PDF
Building Scalable, Highly Concurrent & Fault Tolerant Systems - Lessons Learned
PPT
Memory Optimization
PPTX
Why TypeScript?
PDF
BPF: Tracing and more
GoLang Introduction
Архитектура программных систем на Node.js
7 Common Mistakes in Go (2015)
GraalVM Native and Spring Boot 3.0
Building Scalable, Highly Concurrent & Fault Tolerant Systems - Lessons Learned
Memory Optimization
Why TypeScript?
BPF: Tracing and more

What's hot (20)

PPTX
A Step Towards Data Orientation
PDF
Introduction to yocto
PDF
Git을 조금 더 알아보자!
PDF
Prometheus Storage
PPT
Troubleshooting Linux Kernel Modules And Device Drivers
PPTX
Here Be Dragons: The Unexplored Land of Active Directory ACLs
PDF
Linux kernel debugging
PDF
Escalabilidade horizontal com PostgreSQL e Pgpool II
PDF
Nemesis - SAINTCON.pdf
PPTX
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
PPTX
Flower and celery
PDF
Linux kernel tracing
PDF
Facebook prophet
PPTX
Qt test framework
 
PDF
No drama here - E2E-testing django with playwright
PPTX
CodeChecker Overview Nov 2019
PDF
Introduction to Go programming language
PDF
The Power of Composition
PPTX
Android audio system(audiopolicy_manager)
A Step Towards Data Orientation
Introduction to yocto
Git을 조금 더 알아보자!
Prometheus Storage
Troubleshooting Linux Kernel Modules And Device Drivers
Here Be Dragons: The Unexplored Land of Active Directory ACLs
Linux kernel debugging
Escalabilidade horizontal com PostgreSQL e Pgpool II
Nemesis - SAINTCON.pdf
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
Flower and celery
Linux kernel tracing
Facebook prophet
Qt test framework
 
No drama here - E2E-testing django with playwright
CodeChecker Overview Nov 2019
Introduction to Go programming language
The Power of Composition
Android audio system(audiopolicy_manager)
Ad

Viewers also liked (20)

PDF
Getting Started with Go
PDF
Painless Data Storage with MongoDB & Go
PDF
Go for Object Oriented Programmers or Object Oriented Programming without Obj...
PDF
The Future of the Operating System - Keynote LinuxCon 2015
PDF
7 Common mistakes in Go and when to avoid them
PDF
What every successful open source project needs
KEY
MongoDB, Hadoop and Humongous Data
PDF
Build your first MongoDB App in Ruby @ StrangeLoop 2013
PPTX
Introduction to MongoDB and Hadoop
KEY
Replication, Durability, and Disaster Recovery
PDF
Time series with apache cassandra strata
PDF
NoSQL into E-Commerce: lessons learned
KEY
NoSQL databases and managing big data
PPTX
Building a Pluggable Analytics Stack with Cassandra (Jim Peregord, Element Co...
KEY
OSCON 2012 MongoDB Tutorial
PPTX
Write microservice in golang
PDF
From NASA to Startups to Big Commerce
PPTX
Big Data Testing: Ensuring MongoDB Data Quality
PDF
Python Tricks That You Can't Live Without
ODP
How to Become a Tree Hugger: Random Forests and Predictive Modeling for Devel...
Getting Started with Go
Painless Data Storage with MongoDB & Go
Go for Object Oriented Programmers or Object Oriented Programming without Obj...
The Future of the Operating System - Keynote LinuxCon 2015
7 Common mistakes in Go and when to avoid them
What every successful open source project needs
MongoDB, Hadoop and Humongous Data
Build your first MongoDB App in Ruby @ StrangeLoop 2013
Introduction to MongoDB and Hadoop
Replication, Durability, and Disaster Recovery
Time series with apache cassandra strata
NoSQL into E-Commerce: lessons learned
NoSQL databases and managing big data
Building a Pluggable Analytics Stack with Cassandra (Jim Peregord, Element Co...
OSCON 2012 MongoDB Tutorial
Write microservice in golang
From NASA to Startups to Big Commerce
Big Data Testing: Ensuring MongoDB Data Quality
Python Tricks That You Can't Live Without
How to Become a Tree Hugger: Random Forests and Predictive Modeling for Devel...
Ad

Similar to Building Awesome CLI apps in Go (20)

PPTX
Golang - Overview of Go (golang) Language
PDF
Introduction to Go
PDF
Happy Go Programming Part 1
PDF
Go for SysAdmins - LISA 2015
PDF
Golang workshop
PDF
The GO programming language
PPTX
Lab1GoBasicswithgo_foundationofgolang.pptx
PDF
Finding a useful outlet for my many Adventures in go
PDF
Tiny C Projects 1st Edition Daniel Gookin
PDF
Go. why it goes v2
PPTX
Go programming language
PDF
Building Command Line Tools with Golang
PDF
On the Edge Systems Administration with Golang
PDF
Go: Beyond the Basics
PPT
A First Look at Google's Go Programming Language
PPT
Google's Go Programming Language - Introduction
PPTX
Go programing language
PDF
Introduction to Programming in Go
PDF
Lecture 1 - Overview of Go Language 1.pdf
PDF
Golang
Golang - Overview of Go (golang) Language
Introduction to Go
Happy Go Programming Part 1
Go for SysAdmins - LISA 2015
Golang workshop
The GO programming language
Lab1GoBasicswithgo_foundationofgolang.pptx
Finding a useful outlet for my many Adventures in go
Tiny C Projects 1st Edition Daniel Gookin
Go. why it goes v2
Go programming language
Building Command Line Tools with Golang
On the Edge Systems Administration with Golang
Go: Beyond the Basics
A First Look at Google's Go Programming Language
Google's Go Programming Language - Introduction
Go programing language
Introduction to Programming in Go
Lecture 1 - Overview of Go Language 1.pdf
Golang

More from Steven Francia (17)

PDF
State of the Gopher Nation - Golang - August 2017
PDF
Modern Database Systems (for Genealogy)
PPTX
Future of data
PDF
MongoDB, Hadoop and humongous data - MongoSV 2012
KEY
Big data for the rest of us
KEY
Multi Data Center Strategies
KEY
MongoDB and hadoop
KEY
MongoDB for Genealogy
KEY
Hybrid MongoDB and RDBMS Applications
KEY
Building your first application w/mongoDB MongoSV2011
KEY
MongoDB, E-commerce and Transactions
KEY
MongoDB, PHP and the cloud - php cloud summit 2011
KEY
MongoDB and PHP ZendCon 2011
KEY
KEY
Blending MongoDB and RDBMS for ecommerce
KEY
Augmenting RDBMS with MongoDB for ecommerce
KEY
MongoDB and Ecommerce : A perfect combination
State of the Gopher Nation - Golang - August 2017
Modern Database Systems (for Genealogy)
Future of data
MongoDB, Hadoop and humongous data - MongoSV 2012
Big data for the rest of us
Multi Data Center Strategies
MongoDB and hadoop
MongoDB for Genealogy
Hybrid MongoDB and RDBMS Applications
Building your first application w/mongoDB MongoSV2011
MongoDB, E-commerce and Transactions
MongoDB, PHP and the cloud - php cloud summit 2011
MongoDB and PHP ZendCon 2011
Blending MongoDB and RDBMS for ecommerce
Augmenting RDBMS with MongoDB for ecommerce
MongoDB and Ecommerce : A perfect combination

Recently uploaded (20)

PPTX
Group 1 Presentation -Planning and Decision Making .pptx
PDF
Machine learning based COVID-19 study performance prediction
PPTX
A Presentation on Artificial Intelligence
PDF
Encapsulation_ Review paper, used for researhc scholars
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
SOPHOS-XG Firewall Administrator PPT.pptx
PPTX
1. Introduction to Computer Programming.pptx
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PPTX
Spectroscopy.pptx food analysis technology
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
A comparative study of natural language inference in Swahili using monolingua...
PDF
A comparative analysis of optical character recognition models for extracting...
PPTX
TLE Review Electricity (Electricity).pptx
PDF
Heart disease approach using modified random forest and particle swarm optimi...
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Accuracy of neural networks in brain wave diagnosis of schizophrenia
Group 1 Presentation -Planning and Decision Making .pptx
Machine learning based COVID-19 study performance prediction
A Presentation on Artificial Intelligence
Encapsulation_ Review paper, used for researhc scholars
Programs and apps: productivity, graphics, security and other tools
Building Integrated photovoltaic BIPV_UPV.pdf
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
SOPHOS-XG Firewall Administrator PPT.pptx
1. Introduction to Computer Programming.pptx
Mobile App Security Testing_ A Comprehensive Guide.pdf
Reach Out and Touch Someone: Haptics and Empathic Computing
Spectroscopy.pptx food analysis technology
Network Security Unit 5.pdf for BCA BBA.
A comparative study of natural language inference in Swahili using monolingua...
A comparative analysis of optical character recognition models for extracting...
TLE Review Electricity (Electricity).pptx
Heart disease approach using modified random forest and particle swarm optimi...
Advanced methodologies resolving dimensionality complications for autism neur...
Spectral efficient network and resource selection model in 5G networks
Accuracy of neural networks in brain wave diagnosis of schizophrenia

Building Awesome CLI apps in Go