Go from a PHP Perspective
-
Upload
barry-jones -
Category
Software
-
view
445 -
download
0
Transcript of Go from a PHP Perspective
Go (or Golang) from Google
From golang.org
“Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.”
Valiant attempt to balance
• Productivity
• Workflow
• Growth
• Portability
• Efficiency
• Concurrency
Let’s talk PHP
• A few months back I gave a presentation called:
What’s the “right” PHP framework?
• With the shocking conclusion that there isn’t one
– It was very “meta” as the kids say
PHP gives 90% of needs
• Frameworks largely just arrange them
– While locking you into them
• The most successful PHP ecosystem is one driven by Composer
– Lot’s of great parts
– Assemble them to your needs
– Skip the frameworks completely
My solution was going to be…
• Routes defined in PHP– For development– But generated as a file for nginx in production– Framework routing is insanely expensive
• PHP is stupid fast when it’s lightweight• Route direct to a PHP file
– Include only what you need for that file– Share templates with straight PHP
• Because APC will hold that in RAM
• Use the power of the PostgreSQL• Let PHP be the only real upgrade path
Random stats
Java takes the top 8 spots before
= 914,749 to 731,583
Go appears
= 348,555
Then more Java, jRuby, Go and Java
= 344,032 to 245,709
Before Node.js
= 228,887
Until we get to PHP at
= 180,147
Impact of frameworksUnderstand how far things fall when frameworks are added to the stack
Leaner is better with dynamics
Needed to learn Go for work
• Frameworks largely rejected (exist though)
• Code as interchangeable parts
– There are about 10 different URL routers
• Range from features to speed…depending on your needs
• Even the frameworks are mostly
– “bring your own ORM…if you want”
So I started looking at trade offs
There’s a lot of trade offs with ALMOST
• Serves static files ALMOST as fast as nginx– But better than just about everything else
• Composite objects ALMOST as good as Ruby– But better than just about everything else
• Performance and garbage collection ALMOST as good as Java (portability too)– But better than just about everything else
• Concurrency model ALMOST as good as Erlang– But better than just about everything else
• Save refresh workflow from a statically typed language ALMOST as efficient as PHP– But better than just about everything else
Other perks
• Default, programmatically enforced code style– gofmt
• Compiler won’t allow includes/imports that aren’t used– Avoids bloat
• Won’t even allow declaring VARIABLES that aren’t used– Guardian of your RAM
• Other things to save your team from arguments– Testing built in, standardized– Templates built in, standardized– HTTP and other protocol servers, built in, standardized– Documentation built in, standardized– Sort of a convention over configuration approach to standard
libraries
So…compared to my solution
PHP + nginx routing/static Go for static/routing/logic
• Same result, one binary
• Zero server config
• Assemble parts as needed
It’s not all gophers and rainbows
For “code heavy” projects
• Great performance
• Excellent for development teams
• Code structure works great for iterative development
• Concurrency, computation, API, Services, encapsulation, sharing code between projects, portable scripts for agents running reliably on client machines
For “websites”
• Lot’s of assembly required
• HTML templates are tedious– Rewriting lots of loading,
caching code
– Breaking large templates into pieces is an exercise in pain
• CSS/JS minify/versioning solutions are fairly clunky
• Better for refinement than prototype or MVP dev
Or at least it did last year…
Unofficial, preliminary, unpublished, disclaimer heavy Round 10 benchmarks
Where does Go “fit” for a PHP dev?
• Services / APIs / JSON
• SPA Backend
• Background jobs
• Queue workers
• Portability
• Client installed agent code
• High concurrency workload
• Server level code– Drop uploads after seeing
bad headers
• Long polling / websockets
Basically, Go is good at the things that PHP is really bad at without the development time requirement of doing it in Java.
PHP is really good at the things that Go is really bad at, efficiently developing complete web sites
LET’S LOOK AT SOME GO EXAMPLES
It’s about dang time
* Most of the examples come directly from the free golang-book.com
Compile Time
This 1 minute video explains it best
https://youtu.be/wwoWei-GAPo
Data Types
• uint = uint8 (byte), uint16, uint32, uint64
• int = int8, int16, int32 (rune), int64
• float32, float64
• complex64, complex128 (for imaginaries)
• string (byte[])
• Use := to infer type automatically– x := “some cool text”
– var x string = “some cool text”
Array, Map, Interface
• Array = Numerically indexed set of Type
• Map = Key of Type and Value of Type
private / Public
Starts with capital letter = Public
Starts with lower case letter = private
Yes. Really.
Functions
func methodName(argument type) returnType {
}
// From the Go doc’s template tutorial
func loadPage(title string) *Page {
filename := title + ".txt"
body, _ := ioutil.ReadFile(filename)
return &Page{Title: title, Body: body}
}
Structs
type Circle struct {
x float64
y float64
r float64
}
// OR
type Circle struct {
x, y, r float64
}
var c Circle
// OR
c := new(Circle)
// OR with values
c := Circle{x: 0, y: 0,
r: 5}
// OR by definition order
c := Circle{0, 0, 5}
Compositional Object
type Circle struct {
x, y, r float64
} // Look…a closing bracket
func (c *Circle) area() float64 {
return math.Pi * c.r*c.r
}
• (c *Circle) means Circles can call this function.
• Meaning object data and methods are SEPARATE
• Data in the struct, methods on the type
• So you can keep adding methods as your application requires
without inheriting, extending, and reworking the entire
inheritance chain
• Similar to object Includes and Monkey Patching in Rails
– One of the strengths of the language for productivity
Interfaces
• Java / most Object Oriented languages
– Object defined to implement an interface
• Go
– Object just needs to match an interface
– Solves a big pain point of OO development
– Create interfaces for existing objects
• Without modifying or extending the objects
Interface Example
type Circle struct {
x, y, r float64
}
func (c *Circle) area() float64 {
return math.Pi * c.r*c.r
}
type Rectangle struct {
x1, y1, x2, y2 float64
}
func (r *Rectangle) area() float64 {
l := distance(r.x1, r.y1, r.x1, r.y2)
w := distance(r.x1, r.y1, r.x2, r.y1)
return l * w
}
// Any type with an area() float64 method is a Shape
type Shape interface {
area() float64
}
Interface Functions
type Shape interface {
area() float64
}
func totalArea(shapes ...Shape) float64 {
var area float64
for _, s := range shapes {
area += s.area()
}
return area
}
fmt.Println(totalArea(&c, &r))
Interfaces as Fields
type MultiShape struct {
shapes []Shape
}
// This actually makes MultiShape into a Shape
func (m *MultiShape) area() float64 {
var area float64
for _, s := range m.shapes {
area += s.area()
}
return area
}
Defer / Panic / Recover
func readFile(filename string) string {
f, _ := os.Open(filename)
defer f.Close() // Will always run before end
if filename == “SOME CONDITION” {
return f.getDataSpecialWay
} else {
return f.getDataNormalWay
}
} // Exception handling
defer func() {
str := recover()
fmt.Println(str)
}()
panic("PANIC”)
Mo Concurrency Mo Problems
• Concurrent / threaded operations fight for variables
– Mutex locks
– Halt threads and wait
• Go uses channels to avoid this
Channels
func pinger(c chan string) {
for i := 0; ; i++ {
c <- "ping"
}
}
func ponger(c chan string) {
for i := 0; ; i++ {
c <- "pong"
}
}
func printer(c chan string) {
for {
msg := <- c
fmt.Println(msg)
time.Sleep(time.Second * 1)
}
}
func main() {
var c chan string = make(chan string)
go pinger(c)
go ponger(c)
go printer(c)
}
Send a message
c <- “ping”
Receive a message
msg := <- c
OR
fmt.Println(<-c)
Pinger and Ponger won’t send until something is waiting to receive
- Unless it’s a buffered channel
- Only waits when buffer is full
Printer will wait to receive until something sends it a message
More on Channels
// Send only
func pinger(c chan<- string)
// Receive only
func printer(c <-chan string)
// Listen to multiple
select {
case msg1 := <- c1:
fmt.Println(msg1)
case msg2 := <- c2:
fmt.Println(msg2)
case <- time.After(time.Second):
fmt.Println("timeout")
default:
fmt.Println("nothing ready")
}
Define channel direction
- Send only
- Receive only
Listen to multiple with select/case
- Whichever is ready first
- OR random
- OR set a timeout
- OR default if neither are ready
Fake Real World Example
type Job interface {
process()
complete()
failure()
}
func redisListener(c chan<- Job) {
c <- RedisJob()
}
func postrgresListener(c chan<- Job) {
c <- PostgresJob()
}
func awsSqsListener(c chan<- Job) {
c <- SqsJob()
}
func jobRunner(c <-chan Job) {
job := <- c
go job.process()
}
func main() {
// channel of Jobs with a buffer of 50
var c chan Job = make(chan Job, 50)
go redisListener(c)
go postrgresListener(c)
go awsSqsListener(c)
go jobRunner(c)
}
Multi-Queue Worker
- This is purely for insanity sake
- Create infinite job go routines
- Listen on 1 connection per queue
- Use an interface to define common execution needs
Example could continue by
- Create a result channel per queue
- Use a single connection per to report ALL job results in their own way
TCP Servers and Routing
package main
import ("net/http" ; "io")
func hello(res http.ResponseWriter, req *http.Request) {
res.Header().Set(
"Content-Type",
"text/html",
)
io.WriteString(
res,
`<doctype html><html>
<head><title>Hello World</title></head>
<body>Hello World!</body>
</html>`,
)
}
func main() {
http.HandleFunc("/hello", hello)
http.ListenAndServe(":9000", nil)
}
Gorilla Mux Router
func main() {
r := mux.NewRouter()
r.HandleFunc("/", HomeHandler)
r.HandleFunc("/products", ProductsHandler)
r.HandleFunc("/articles", ArticlesHandler)
r.HandleFunc("/products/{key}", ProductHandler)
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
// You could use multiple routers too
http.Handle("/", r)
}
Dependency Management
go get github.com/myname/mypackage
• Copies it locally• Bundles it with your deployed binary• Sits right next to your local packages• Single “src” directory with all packages• Makes code sharing between multiple packages
very simple• Never depend on “remote library host” being
down to deploy again
Gopher It!
References / Credits• Go
– http://golang.org/
• Golang Book– http://www.golang-book.com/
• Gorilla Web Toolkit– http://www.gorillatoolkit.org/
• Techempower Benchmarks– Official Round 9
• http://www.techempower.com/benchmarks/#section=data-r9
– Preview Round 10• http://www.techempower.com/benchmarks/previews/round10/
*Hulkbuster written in Go
Additional Resources
Who’s using Go?• Sendgrid
– Convice Your Company
– Intro and Love
• IronMQ– From 30 Servers to 2
– Go after 2 Years in Prod
• Heroku– Go at Heroku
• Digital Ocean– Super Fast Console. Thanks Go!
• Others– Dropbox, StatHat, Hailo,
Soundcloud, TimeHop
Other good reading• Concurrency is not Parallelism• Scaling VividCortex• Stability at Timehop• Simplicity and Maintenance• Worker Queues in Go• A RESTful Microframework• Monte Carlo Benchmarks• Taking Cloud Dev by Storm• Structuring Applications in Go• Go by Example• Let’s Learn Go!• Going Go – Playground• GopherCasts
Thanks to James, Josh and ACS Technologies