David [email protected]
Programando em Go
David [email protected]
linkedin.com/in/davidrobert
Go é uma linguagem de programação open source que faz com que seja fácil construir software simples,
confiável, e eficiente https://golang.org
tem grandes, grandes problemas!
Quais (grandes) problemas?
❏ Tanto hardware quanto software são gigantes❏ Milhões de linhas de código❏ Servidores principalmente em C++ e uma grande
quantidade em Java e Python❏ Milhares de desenvolvedores trabalhando ❏ Softwares sendo executado em zilhões de maquinas❏ Sistemas distribuídos em larga escala
Software em larga escala
❏ Builds lentos ❏ Dependências não controladas ❏ Custo de updates ❏ Dificuldade para automatizar tarefas ❏ Builds entre várias linguagens de programação❏ Código difícil de compreender
No geral, o desenvolvimento no é grande, lento, e muitas vezes
desajeitado. Mas é efetivo
''''
https://talks.golang.org/2012/splash.article
❏ Ken Thompson (B, C, Unix, UTF-8) ❏ Rob Pike (Unix, UTF-8) ❏ Robert Griesemer (Hotspot, JVM) … e muitos outros engenheiros do Google
Muitas pessoas ajudam a transformar o
protótipo em realidade
Go se tornou um projeto Open
Source
https://golang.org/doc/faq#history
2008 2009 20102007
Começa a ter adoção por outros desenvolvedores
Iniciado e desenvolvido por Robert Griesemer,
Rob Pike e Ken Thompson em um projeto part-time
História
http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
2008 2009 20102007
História
Programming Language Hall of Fame
Histórico de Versões
Go 1.4
Go 1.3
Go 1
Go 1.2
Go 1.1
https://golang.org/project/
2013 2014 20152012
Go 1.5
Google Trends "golang"
❏ Eliminar lentidão❏ Melhorar a eficacia❏ Aumentar a produtividade ❏ Manutenção escalável
Go foi projetado para que pessoas possam escrever, ler, debugar e manter grandes sistemas de software.
O proposito do Go não é ser uma pesquisa sobre design de linguagens de programação.
O objetivo do Go é fazer com que os programadores vivam melhor.
Por que usar Go?
Performance
http://benchmarksgame.alioth.debian.org
fix, fmt, get, install, list, tool, version, vet.
build compila pacotes e dependencias
run compila e executa programas Go
clean remove arquivos objeto
env imprime informações do ambiente
test testa pacotes e benchmarks
Go contém um conjunto de ferramentas para gerir código fonte...
Principais ferramentas:
Outras ferramentas:
Mas quem usa Go ?
https://github.com/golang/go/wiki/GoUsers
❏ Compilado❏ Memoria gerenciada (garbage-collected)❏ Tem seu próprio runtime❏ Sintaxe simples❏ Excelente biblioteca padrão❏ Multi plataforma❏ Orientação a Objetos❏ Estaticamente e fortemente tipado❏ Concorrência (goroutines)❏ Dependências explicitas❏ Retorno multi valorado❏ Ponteirose mais...
O que você vai ver em Go
Estas características não foram implementadas em favor da
eficiência e simplicidade
❏ Tratamento de exceções❏ Herança❏ Generics❏ Assert❏ Sobrecarga de métodos
O que você não vai ver em Go
um pouco de código!
Pacotes
❏ Todo programa Go é composto por pacotes❏ Programas começam com o pacote main❏ Este exemplo usa os pacotes ftm e math
$ go run packages.goMy favorite number is 1
❏ A instrução var declara uma lista de variavéis❏ O tipo é informado no fim❏ A instrução var pode incluir inicialização, 1 por variavél. Neste
caso, o tipo pode ser omitido porque será inferido
Variavéis
$ go run variables.go0 false false false
$ go run variables-with-initiali1 2 true false no!
❏ Dentro de uma função, pode ser usada a instrução := para inicializar e declarar a variavél
Declaração de Variáveis
$ go run short-variable-declarations.go1 2 3 true false no!
$ go run constants.goHello world! Happy 3.14 Day! Go rules? true
❏ Constantes são declaradas com a keyword const❏ Não é possível usar :=
Constantes
Funções❏ Funções podem ter argumentos❏ O tipo fica após o nome do argumento
$ go run functions.go55
❏ Uma função pode ter múltiplos retornos
Retorno de valores múltiplos
$ go run multiple-results.goworld hello
❏ A única estrutura do laço que o Go tem é for❏ Muito similar com Java ou C, exceto pelos ( )❏ A parte inicial e final da declaração podem estar vazias
Laço For
$ go run for.go45
$ go run for-continu1024
$ go run for-is-go-while.go1024
❏ Ponto e vírgula pode ser removidos para simular um while ❏ for pode executar para "sempre"
Laço while
$ go run forever.goprocess took too long
❏ Muito similar com Java ou C, exceto pelos ( )
Condicional
$ go run if.go1.4142135623730951 2i
$ go run switch.goGo runs on nacl.
❏ Muito similar com Java ou C, exceto pelos ( )
Switch
$ go run defer.gohello world
Defer❏ A declaração defer adia a execução de uma função até o final do
retorno da função❏ Os argumentos das chamadas adiadas são avaliados imediatamente
Orientação a Objetos
Orientação a Objetos
type retangulo struct { largura, altura int}
Estruturas do Go (similares a classes)
Orientação a Objetos
type retangulo struct { largura, altura int}
Go suporta métodos definidos em tipos struct
func (r retangulo) area() int { return r.largura * r.altura}
Estruturas do Go (similares a classes)
Orientação a Objetos
type retangulo struct { largura, altura int}
Go suporta métodos definidos em tipos struct
func (r retangulo) area() int { return r.largura * r.altura}
Estruturas do Go (similares a classes)
retangulo{10, 20}retangulo{largura: 10, altura: 20}
Inicialização de estruturas
Orientação a Objetos
package vingadores
type vingador struct {nome string
}func NewVingador(nome string) *vingador {
v := new(vingador)v.nome = nomereturn v
}
func main() {capitao := vingadores.NewVingador("Capitão América")fmt.Println(capitao.nome)
}
Construtores
Orientação a Objetos
package vingadores
type vingador struct {nome string
}func NewVingador(nome string) *vingador {
v := new(vingador)v.nome = nomereturn v
}
func main() {capitao := vingadores.NewVingador("Capitão América")fmt.Println(capitao.nome)
}
Construtores ❏ Depois de importar um pacote, você pode consultar os nomes que exporta
❏ Um nome é exportado se começa com uma LETRA MAIÚSCULA
Orientação a Objetosstruct.go
12345678910111213141516171819
package main
import "fmt"
type pessoa struct {nome stringidade int
}
func main() {fmt.Println(pessoa{"Homem de Ferro", 40})fmt.Println(pessoa{nome: "Thor", idade: 100})
s := pessoa{nome: "Hulk", idade: 45}fmt.Println(s.nome)
s.idade = 42fmt.Println(s.idade)
}
Orientação a Objetosstruct.go
12345678910111213141516171819
package main
import "fmt"
type pessoa struct {nome stringidade int
}
func main() {fmt.Println(pessoa{"Homem de Ferro", 40})fmt.Println(pessoa{nome: "Thor", idade: 100})
s := pessoa{nome: "Hulk", idade: 45}fmt.Println(s.nome)
s.idade = 51fmt.Println(s.idade)
}
$ go run struct.go{Homem de Ferro 40}
{Thor 100}
Hulk
42
Orientação a Objetosmethods.go
12345678910111213141516171819
package mainimport "fmt"
type retangulo struct { largura, altura int}func (r retangulo) area() int { return r.largura * r.altura}
func (r retangulo) perimetro() int { return 2 * r.largura + 2 * r.altura}func main() { r := retangulo{largura: 10, altura: 5}
fmt.Println("area: ", r.area()) fmt.Println("perim:", r.perimetro())}
Orientação a Objetosmethods.go
12345678910111213141516171819
package mainimport "fmt"
type retangulo struct { largura, altura int}func (r retangulo) area() int { return r.largura * r.altura}
func (r retangulo) perimetro() int { return 2 * r.largura + 2 * r.altura}func main() { r := retangulo{largura: 10, altura: 5}
fmt.Println("area: ", r.area()) fmt.Println("perim:", r.perimetro())}
$ go run methods.goarea: 50perim: 30
HERANÇA
HERANÇA
Como assim não tem
herança !?
Por que usamos herança?
Herança
Por que usamos herança?
❏ Reuso de código
Herança
Por que usamos herança?
❏ Reuso de código
Existe efeito colateral em seu uso?
Herança
Por que usamos herança?
❏ Reuso de código
Existe efeito colateral em seu uso?
Acoplamos a implementação da classe mãe muito precocemente. A classe filha precisa
conhecer muito bem o código interno da mãe.
Quebra de encapsulamento
Herança
Alguns críticos afirmam que ela nunca deveria ser utilizada
Herança
Alguns críticos afirmam que ela nunca deveria ser utilizada
Go não tem Herança !
Herança
Alguns críticos afirmam que ela nunca deveria ser utilizada
Go não tem Herança !
Mas tem composição !
Um dos princípios do livro "Design Patterns": Evite herança, favoreça composição
Herança
Herança composition.go
12345678910111213141516171819
package mainimport "fmt"
type Car struct {wheelCount int
}func (car Car) numberOfWheels() int {
return car.wheelCount}type Ferrari struct {
Car //anonymous field Car}
func main() {f := Ferrari{Car{4}}
fmt.Println("A Ferrari tem ", f.numberOfWheels(), " rodas")
}
Herança composition.go
12345678910111213141516171819
package mainimport "fmt"
type Car struct {wheelCount int
}func (car Car) numberOfWheels() int {
return car.wheelCount}type Ferrari struct {
Car //anonymous field Car}
func main() {f := Ferrari{Car{4}}
fmt.Println("A Ferrari tem ", f.numberOfWheels(), " rodas")
}
$ go run composition.goA Ferrari tem 4 rodas
Herança (anonymous field) anonymous-field.go
12345678910111213141516171819
package mainimport "fmt"type Cozinha struct { lampadas int}
type Casa struct { Cozinha }
func main() { c := Casa{Cozinha{2}} fmt.Println("A casa tem ", c.lampadas , " lampadas") }
Herança (anonymous field) anonymous-field.go
12345678910111213141516171819
package mainimport "fmt"type Cozinha struct { lampadas int}
type Casa struct { Cozinha }
func main() { c := Casa{Cozinha{2}} fmt.Println("A casa tem ", c.lampadas , " lampadas") }
$ go run anonymous-field.goA casa tem 2 lampadas
Herança (anonymous field) anonymous-field.go
12345678910111213141516171819
package mainimport "fmt"type Cozinha struct { lampadas int}type Quarto struct { lampadas int}type Casa struct { Cozinha Quarto}
func main() { c := Casa{Cozinha{2}, Quarto{3}} fmt.Println("A casa tem ", c.lampadas , " lampadas") }
Herança (anonymous field) anonymous-field.go
12345678910111213141516171819
package mainimport "fmt"type Cozinha struct { lampadas int}type Quarto struct { lampadas int}type Casa struct { Cozinha Quarto}
func main() { c := Casa{Cozinha{2}, Quarto{3}} fmt.Println("A casa tem ", c.lampadas , " lampadas") }
$ go run anonymous-field.goambiguous selector c.lampadas
Herança (anonymous field) anonymous-field.go
12345678910111213141516171819
package mainimport "fmt"type Cozinha struct { lampadas int}type Quarto struct { lampadas int}type Casa struct { Cozinha Quarto}func (c Casa) lampadas() int { return c.Cozinha.lampadas + c.Quarto.lampadas}func main() { c := Casa{Cozinha{2}, Quarto{3}} fmt.Println("A casa tem ", c.lampadas(), " lampadas") }
Herança (anonymous field) anonymous-field.go
12345678910111213141516171819
package mainimport "fmt"type Cozinha struct { lampadas int}type Quarto struct { lampadas int}type Casa struct { Cozinha Quarto}func (c Casa) lampadas() int { return c.Cozinha.lampadas + c.Quarto.lampadas}func main() { c := Casa{Cozinha{2}, Quarto{3}} fmt.Println("A casa tem ", c.lampadas(), " lampadas") }
$ go run anonymous-field.goA casa tem 5 lampadas
Go
Tratando Erros
http://blog.golang.org/error-handling-and-go
Assinatura da função:func Open(name string) (file *File, err error)
Exemplo de uso com tratamento de erro:f, err := os.Open("filename.ext")
if err != nil {
log.Fatal(err)
}
// faça algo com o arquivo f
Estados inconsistentes ou anormais são indicados através do error. Por exemplo a função os.Open
Tratamento de Erros
Todo erro em Go é representado pela interface errortype error interface { Error() string}
A implementação mais comum é a errorString.type errorString struct {
s string}
func (e *errorString) Error() string { return e.s
}
Representação do erro
A forma mais simples de criar um errorString é a partir da função errors.New
func New(text string) error { return &errorString{text}}
Usando a função para disparar um erro:func Sqrt(f float64) (float64, error) { if f < 0 { return 0, errors.New("negative number") } // implementaçào caso f >= 0}
Disparando um errorString
Usando a função para disparar um erro:func Sqrt(f float64) (float64, error) { if f < 0 { return 0, errors.New("negative number") } // implementaçào caso f >= 0}
A forma mais simples de criar um errorString é a partir da função errors.New
func New(text string) error { return &errorString{text}}
Disparando um errorString
Não estamos informando qual o número passado para a função. Informação muito importante sendo perdida!
De forma similar como disparamos um errorString através da função errors.New ... podemos usar a função Errorf do pacote fmt para disparar erros mais completos.
Internamente a função Errorf se utiliza da função errors.New
Disparando erros com Errorf
if f < 0 { return 0, fmt.Errof("negative number %g", f) }
Esta é uma abordagem muito mais sofisticada do que usar apenas errorString pois permite type assertions.
type NegativeSqrtError float64
func (f NegativeSqrtError) Error() string { return fmt.Sprintf("negative number %g", float64(f))}
É possível criar suas próprias implementações de erros.
Como por exemplo deste caso do número negativo, poderíamos por exemplo:
Customizando seus erros
tratamento de erros é importante!
As convenções e design da linguagem nos encorajam a verificar explicitamente por erros onde eles possam ocorrer
indo em desencontro com muitas outras linguagens.
Em alguns casos, isto pode fazer Go um tanto verbosa, mas felizmente existem técnicas para lidar com isso.
Concorrência & Paralelismo
Concorrência & Paralelismo
O mundo moderno é paralelo
❏ Multicore❏ Networks❏ Cloud Computing❏ Grande quantidade de usuários.
Go suporta concorrência
❏ execução concorrente (goroutines)❏ sincronização e mensagens (channels)❏ controle concorrente (select)
Concorrência é legal !
Uhu paralelismo !
Isso é uma falacia!
Quando o Go anunciou, muitos ficaram confusos com a distinção
❏ A concorrência é sobre como lidar com um monte de coisas ao mesmo tempo.
❏ O paralelismo é sobre fazer muitas coisas ao mesmo tempo.
❏ A concorrência é sobre a estrutura, o paralelismo é sobre a execução.
❏ Concorrência fornece uma maneira de estruturar uma solução para resolver um problema que pode (mas não necessariamente) ser paralelizável.
Concorrência versus Paralelismo
Concorrência versus Paralelismo
❏ Com apenas um Gopher isso vai levar muito tempo
Concorrência versus Paralelismo
❏ Mais Gopher não são suficientes ❏ Eles precisam de mais carrinhos
Concorrência versus Paralelismo
❏ Vai ir mais rápido, mas haverá gargalos na pilha e no incinerador
❏ Precisa sincronizar os Gophers❏ Comunicação entre os esquilos sera necessária
Concorrência versus Paralelismo
❏ Remover os gargalos torna realmente independente❏ Vai consumir duas vezes mais rápido❏ Concorrência de dois processos Gopher
Concorrência versus Paralelismo
❏ Três Gophers em ação, mas com atrasos prováveis❏ Cada Gopher é um processo independente, acrescido de
coordenação (comunicação)
Concorrência versus Paralelismo
❏ Quatro Gophers em ação, cada com uma tarefa simples❏ Quatro vezes mais rápido que a versão original com um
Concorrência versus Paralelismo
Procedimentos concorrentes
Para cada Gopher um procedimento distinto:❏ Carregar o carrinho com livros❏ Mover o carrinho para incinerador❏ Descarregar o carrinho no incinerador❏ Retornar o carrinho vazio
Diferentes designs concorrentes permitem diferentes formas de paralelizar
Concorrência versus Paralelismo
❏ Mais paralelismo❏ Oito Gophers totalmente ocupados
Concorrência versus Paralelismo
❏ Mesmo que apenas um Gopher esteja ativo (sem paralelismo), ainda é uma solução correta e concorrente
Concorrência versus Paralelismo
❏ Outra maneira: Composição simultânea de procedimentos❏ Dois procedimentos e uma pilha de preparo
Concorrência versus Paralelismo
❏ Executar mais procedimentos concorrentes para obter mais throughput
Concorrência versus Paralelismo
❏ Utilizando a pilha no modelo multi gopher
Concorrência versus Paralelismo
❏ Otimização total❏ Usando todas as técnicas, dezesseis Gopher estão
trabalhando
Concorrência versus Paralelismo
❏ Há muitas maneiras de dividir o processamento
❏ Isso é design concorrente
❏ Uma vez que temos a divisão, a paralelização fica mais fácil
É uma função que executa no mesmo endereço de outras goroutines
❏ Como uma chamada de função no shell com &
Goroutines
Goroutinesgoroutines.go
12345678910111213141516171819
package main
import ("fmt""time"
)
func say(s string) {for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)}
}
func main() {go say("world")say("hello")
}
$ go run goroutines.gohelloworldhelloworldhelloworldhelloworldworldhello
Apesar de serem parecidas com threads, elas são muito mais baratas
❏ Goroutines são multiplexados em threads no S.O. conforme necessário
❏ Quando uma goroutine fica bloqueada, aquela thread fica bloqueada, mas não impacta em nenhuma outra goroutine
Goroutines não são threads
❏ Channels são canais que conectam goroutines concorrentes. Você pode enviar valores para os canais de uma goroutine e receber esses valores em outra goroutine
❏ Cria um novo canal com make(chan tipo-val)
❏ A sintaxe <- server para enviar ou receber mensagens
Channels
Channelschannels.go
12345678910111213141516171819
package mainimport "fmt"
func sum(a []int, c chan int) {sum := 0for _, v := range a {
sum += v}c <- sum // send sum to c
}func main() {
a := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)go sum(a[:len(a)/2], c)go sum(a[len(a)/2:], c)x, y := <-c, <-c // receive from cfmt.Println(x, y, x+y)
}
$ go run channels.go17 -5 12
http://www.goinggo.net/2014/02/the-nature-of-channels-in-go.html
c := make (chan int)
Channels
❏ Por padrão canais são não buferizados. Só aceitarão envios se houver um receptor pronto para receber o valor
❏ Canais buferizados aceitam um número limitado de valores sem um receptor correspondente para esses valores
Buffered Channels
Buffered Channelsbuffered-channels.go
12345678910111213
package main
import "fmt"
func main() { mensagens := make(chan string, 2) mensagens <- "buferizado" mensagens <- "canal" fmt.Println(<-mensagens) fmt.Println(<-mensagens)}
$ go run buffered-channels.go
buferizado
canal
http://www.goinggo.net/2014/02/the-nature-of-channels-in-go.html
c := make (chan int, 10)
Buffered Channels
❏ Para executar uma goroutine: go
❏ Para enviar ou receber informações entre goroutines: channels
❏ Use a variável de ambiente GOMAXPROCS para definir a quantidade de threads
Concorrência em Go
Go Runtime
https://www.quora.com/How-does-the-Go-runtime-workhttp://www.cs.columbia.edu/~aho/cs6998/reports/12-12-11_DeshpandeSponslerWeiss_GO.pdfhttp://blog.altoros.com/golang-internals-part-5-runtime-bootstrap-process.html
❏ Um pacote como qualquer outro em Go.
❏ É implementado em GO, C e Assembly
❏ É empacotado junto com o programa no momento do build
❏ Responsável pelo:❏ Gerencimento de mémória❏ Criação das GO Routines❏ Comunicação entre channels
Go Runtime
Go Runtime
Só isso ou tem mais?❏ Pointer❏ Struct❏ Matrix❏ Slice❏ Range❏ Map❏ Value function❏ Closures❏ Method❏ Interface❏ Stringer❏ Error
e muito mais!!!
http://go-tour-br.appspot.com
$ go run http.go
Servidor Web❏ Um servidor web com menos de 15 lines!!
Now you are ready to
!
Perguntas?
Obrigado!
David [email protected]
Bibliografia❏ http://golang.org❏ http://go-tour-br.appspot.com/❏ https://tour.golang.org❏ http://www.golangbr.org/❏ https://vimeo.com/49718712❏ http://talks.golang.org/2012/waza.slide❏ http://gophercon.com❏ http://www.infoq.com/br/news/2014/09/go-1-3❏ http://www.casadocodigo.com.br/products/livro-google-go❏ http://www.grokpodcast.com/series/a-linguagem-go/❏ https://pt.wikipedia.org/wiki/Go_(linguagem_de_programação)❏ https://gobyexample.com❏ http://goporexemplo.golangbr.org/❏ http://www.goinggo.net/2014/02/the-nature-of-channels-in-go.html❏ http://www.goinggo.net/2013/09/detecting-race-conditions-with-go.html❏ http://golangtutorials.blogspot.com.br/2011/06/inheritance-and-subclassing-in-go-or.html❏ http://golangtutorials.blogspot.com.br/2011/06/anonymous-fields-in-structs-like-object.html❏ http://commandcenter.blogspot.ca/2012/06/less-is-exponentially-more.html❏ http://www.toptal.com/go/go-programming-a-step-by-step-introductory-tutorial❏ http://www.slideshare.net/while42/programando-em-Go
Estamos contratando