SlideShare a Scribd company logo
1 of 57
Download to read offline
High Order Functions e Functional Interfaces
Devcamp
16/08/2019
1
Especialista em desenvolvimento
backend.
11 anos em desenvolvimento
Java Certi ed Associate
Go desde 2016
Sobre
2
Idiomático?!
3
Foco em simplicidade de soluções
Sintaxe simples
Uma única (ou poucas) formas de se
fazer algo
Leitura e escrita homogêneas por todo
ecossistema
Por que os exemplos em Go?
4
Idiomático
public class SimpleHashSetExample {
public static void main(String[] args) {
HashSet hSet = new HashSet();
hSet.add(new Integer("1"));
hSet.add(new Integer("2"));
hSet.add(new Integer("3"));
System.out.println("HashSet contains.." + hSet);
}
}
5
Idiomático
class Animal(val name: String)
class Zoo(val animals: List<Animal>) {
operator fun iterator(): Iterator<Animal> {
return animals.iterator()
}
}
fun main() {
val zoo = Zoo(listOf(Animal("zebra"), Animal("lion")))
for (animal in zoo) {
println("Watch out, it's a ${animal.name}")
}
}
6
Funções idiomáticas
7
Domínio
Estrutura das entidades
Composição ou herança
Estrutura de persistência
type Entity struct {
name string
...
}
Regra de negócio
Fluxo e manipulação de entidades
Regra de negócio
Adição ou remoção de etapas de
processamento
func (e Entity) transformedName() string {
return e.name + " with transformation"
}
...
The right tool for the right job
8
Server simples em Go
package main
import (
"log"
"net/http"
)
func main() {
log.Println(NewServer(":8080"))
}
func NewServer(address string) error {
r := http.NewServeMux()
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("My Web Servern"))
})
r.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("{"success":true}"))
})
srv := &http.Server{
Addr: address,
Handler: r,
}
return srv.ListenAndServe()
}
Server simples em Go + Timeout
func main() {
log.Println(NewServer(":8080", 2*time.Second, 5*time.Second))
}
func NewServer(address string, rt, wt time.Duration) error {
r := http.NewServeMux()
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("My Web Servern"))
})
r.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("{"success":true}"))
})
srv := &http.Server{
Addr: address,
Handler: r,
ReadTimeout: rt,
WriteTimeout: wt,
}
return srv.ListenAndServe()
}
10
Server simples em Go + Timeout + TLS
func main() {
log.Println(NewServer(":8080", "cert.pem", "key.pem", 2*time.Second, 5*time.Second))
}
func NewServer(address, cert, key string, rt, wt time.Duration) error {
r := http.NewServeMux()
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("My Web Servern"))
})
r.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("{"success":true}"))
})
srv := &http.Server{
Addr: address,
Handler: r,
ReadTimeout: rt,
WriteTimeout: wt,
}
return srv.ListenAndServeTLS(cert, key)
}
11
Muitas assinaturas para "mesma" função
func NewServer(address string) error {}
func NewServer(address string, rt, wt time.Duration) error {}
func NewServer(address, cert, key string) error {}
func NewServer(address, cert, key string, rt, wt time.Duration) error {}
12
Server simples em Go + Con g
type Config struct {
Address string
CertPath string
KeyPath string
ReadTimeout time.Duration
WriteTimeout time.Duration
}
func main() {
config := Config{":8080", "cert.pem", "key.pem", 2 * time.Second, 5 * time.Second}
log.Println(NewServer(config))
}
13
Server simples em Go + Con g
func NewServer(c Config) error {
r := http.NewServeMux()
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("My Web Servern"))
})
r.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("{"success":true}"))
})
srv := &http.Server{
Addr: c.Address,
Handler: r,
ReadTimeout: c.ReadTimeout,
WriteTimeout: c.WriteTimeout,
}
return srv.ListenAndServeTLS(c.CertPath, c.KeyPath)
}
14
Con guration structs
Vantagens
Melhora a documentação e entendimento do código.
Permite utilizar "zero values" como regra
Crescimento das con gurações sem quebrar assinatura
15
Con guration structs
Desvantagens
Gera diversos possíveis problemas com "zero values", exemplo: porta 0
c := Config{
"cert.pem", "key.pem"
}
O cenário ideal para "default" value seria aleatoriamente escolher uma porta e não ir
direto para a zero. Mas e se quisermos tentar a porta zero?
Quais campos são obrigatórios e quais são opcionais?
16
Con guration structs
Problema da mutabilidade
config := Config{
":8080", "cert.pem", "key.pem", 2 * time.Second, 5 * time.Second
}
go func() {
config.Address = ":9090"
}()
log.Println(NewServer(config))
Problema da obrigatoridade
func main() {
//Quero o server mais simples possível!!
log.Println(NewServer(????))
}
17
High-Order Function
Função que faz pelo menos uma das duas:
1. Recebe uma (ou mais) funções como parâmetros
2. Retorna uma função
Exemplos:
Cálculo: dy/dx (operador de diferencial) que recebe uma função e retorna a sua
derivada
callbacks em Javascript
http.HandlerFunc(pattern, handlerFunc)
18
High-Order Function + rst class citizen
package main
import "fmt"
//High-Order: retorna uma função
func myFunction() func(int, int) int {
return func(a, b int) int {
return a + b
}
}
func main() {
//first class citizen: atribuir a uma variável
f := myFunction()
//first class citizen: chamar através da variável
soma := f(2, 3)
fmt.Println(soma)
}
19
High-Order Function + Type Alias
package main
import "fmt"
//type alias
type SomaFunc func(int, int) int
//High-Order: retorna uma função
func myFunction() SomaFunc {
return func(a, b int) int {
return a + b
}
}
func main() {
//first class citizen: atribuir a uma variável
f := myFunction()
//first class citizen: chamar através da variável
soma := f(2, 3)
fmt.Println(soma)
}
20
High-Order na Prática
package main
import "net/http"
func main() {
//first class citizen: atribuir a uma variável
f := handlerFunction()
http.HandleFunc("/", f)
http.ListenAndServe(":8080", nil)
}
//High-Order: retorna uma função
func handlerFunction() func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Contentn"))
}
}
21
High-order functions como ferramenta
22
Relembrar: server deprecado
func main() {
log.Println(NewServer(":8080", "cert.pem", "key.pem", 2*time.Second, 5*time.Second))
}
func NewServer(address, cert, key string, rt, wt time.Duration) error {
r := http.NewServeMux()
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("My Web Servern"))
})
r.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("{"success":true}"))
})
srv := &http.Server{
Addr: address,
Handler: r,
ReadTimeout: rt,
WriteTimeout: wt,
}
return srv.ListenAndServeTLS(cert, key)
23
Functional Server
Ajuste na estrutura do server: criando a struct
type Server struct {
Ltn net.Listener
ReadTimeout time.Duration
WriteTimeout time.Duration
Handler http.Handler
}
func NewServer(addr string) (*Server, error) {
dftLtn, err := net.Listen("tcp", addr)
return &Server{
Ltn: dftLtn,
ReadTimeout: 3 * time.Second,
WriteTimeout: 5 * time.Second,
}, err
}
24
Functional Server
Ajuste na estrutura do server: usando a struct
func (s *Server) Serve() error {
srv := &http.Server{
Handler: s.Handler,
ReadTimeout: s.ReadTimeout,
WriteTimeout: s.WriteTimeout,
}
return srv.Serve(s.Ltn)
}
func main() {
sv, err := NewServer(":8080")
if err != nil {
panic(err)
}
log.Println(sv.Serve())
}
25
Functional Server Com Options
Como inserir um read time out no nosso functional server?
Opção 1: parametro na criação (muda algo?)
func NewServer(addr string, readTimeout time.Duration) (*Server, error) {
dftLtn, err := net.Listen("tcp", addr)
return &Server{
Ltn: dftLtn,
ReadTimeout: readTimeout,
WriteTimeout: 5 * time.Second,
}, err
}
26
Functional Server Com Options
Opção 2: mutar o server depois de criado
func main() {
sv, err := NewServer(":8080")
if err != nil {
panic(err)
}
sv.ReadTimeout = 3*time.Second
log.Println(sv.Serve())
}
Imperativo: baixo reaproveitamento
Poucas abstrações
Clara e distribuída quebra de imutabilidade
27
Functional Server Com Options
Opção 3: criar um método no server
func (s *Server) setTimeout(timeout time.Duration) error {
sv.ReadTimeout = timeout
}
func main() {
sv, err := NewServer(":8080")
if err != nil {
panic(err)
}
sv.setTimeout(3*time.Second)
log.Println(sv.Serve())
}
Clara e distribuída quebra de imutabilidade
28
Functional Server Com Options
Opção 4: criar uma função que altera timeout
func WithTimeout(read, write time.Duration) func(*Server) {
return func(s *Server) {
s.ReadTimeout = read
s.WriteTimeout = write
}
}
func main() {
sv, err := NewServer(":8080")
if err != nil {
panic(err)
}
f := WithTimeout(3*time.Second, 5*time.Second)
f(sv)
log.Println(sv.Serve())
}
Sensação de maior encapsulamento
Clara e distribuída quebra de imutabilidade
29
Functional Server Com Option
Opção 5: criar uma função que altera timeout E recebê-la somente no Serve
func WithTimeout(read, write time.Duration) func(*Server) {...}
func (s *Server) Serve(option func(*Server)) error {
option(s)
srv := &http.Server{
Handler: s.Handler,
ReadTimeout: s.ReadTimeout,
WriteTimeout: s.WriteTimeout,
}
return srv.Serve(s.Ltn)
}
func main() {
sv, err := NewServer(":8080")
if err != nil {
panic(err)
}
log.Println(sv.Serve(
WithTimeout(3*time.Second, 5*time.Second)
))
}
Mutação ainda acontece, mas somente no uso nal
Functional Server Com Options (plural)
func (s *Server) Serve(options ...func(*Server)) error {
for _, opt := range options {
opt(s)
}
srv := &http.Server{
Handler: s.Handler,
ReadTimeout: s.ReadTimeout,
WriteTimeout: s.WriteTimeout,
}
return srv.Serve(s.Ltn)
}
func main() {
sv, err := NewServer(":8080")
if err != nil {
panic(err)
}
log.Println(sv.Serve(
WithTimeout(3*time.Second, 5*time.Second)
))
}
31
Functional Server Com Options (plural)
Inserindo rotas
func WithRoutes() func(*Server) {
return func(s *Server) {
r := http.NewServeMux()
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("My Web Servern"))
})
r.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("{"success":true}"))
})
s.Handler = r
}
}
32
Functional Server Com Options (plural)
Inserindo certi cado
func WithCertificate(cert, key string) func(*Server) {
return func(s *Server) {
cert, err := tls.LoadX509KeyPair(cert, key)
if err != nil {
panic(err)
}
config := &tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true}
//Close old listener
if err := s.Ltn.Close(); err != nil {
panic(err)
}
//Keep old address
originalAddr := s.Ltn.Addr().String()
ltn, err := tls.Listen("tcp", originalAddr, config)
if err != nil {
panic(err)
}
s.Ltn = ltn
}
}
33
Criando o server com Go idiomático
34
Functional Server Com Options (plural)
Criando o server
func WithCertificate(cert, key string) func(*Server) {...}
func WithTimeout(read, write time.Duration) func(*Server) {...}
func WithRoutes() func(*Server) {...}
func main() {
sv, err := NewServer(":8080")
if err != nil {
panic(err)
}
log.Println(sv.Serve(
WithRoutes(),
WithTimeout(2*time.Second, 3*time.Second),
WithCertificate("cert.pem", "key.pem"),
))
}
Toda a con guração do server está no uxo de criação do server
Permite o criação de uma API uente
35
Onde usar?
36
Onde usar?
Con guração de serviços, clientes ou structs
De nição de strategy pattern
Cenários de sincronia -> passagem de comportamento vs
passagem de dados
37
Onde usar?
Con guração de serviços, clientes ou structs
De nição de strategy pattern
Cenários de sincronia -> passagem de comportamento vs
passagem de dados
38
Mais simples bank account
package main
import "fmt"
type BankAccount struct {
balance float64
}
func (b *BankAccount) Deposit(amount float64) { b.balance += amount }
func (b *BankAccount) Withdraw(amount float64) { b.balance -= amount }
func (b *BankAccount) Balance() float64 { return b.balance }
func main() {
acc := BankAccount{}
acc.Deposit(50)
acc.Withdraw(40)
fmt.Println(acc.Balance())
}
39
Cenário de simples "concorrência"
type BankAccount struct{ balance float64 }
func (b *BankAccount) Deposit(amount float64) { b.balance += amount }
func (b *BankAccount) Withdraw(amount float64) { b.balance -= amount }
func (b *BankAccount) Balance() float64 { return b.balance }
func main() {
var wg sync.WaitGroup
acc := BankAccount{}
for i := 0; i < 100000; i++ {
wg.Add(1)
go func(account *BankAccount) {
account.Deposit(10)
account.Withdraw(account.Balance() / 2)
wg.Done()
}(&acc)
}
wg.Wait()
fmt.Println(acc.Balance())
}
40
Tratamento padrão de concorrência
package main
import (
"fmt"
"sync"
)
type BankAccount struct {
balance float64
mu sync.Mutex
}
func (b *BankAccount) Deposit(amount float64) {
b.mu.Lock()
defer b.mu.Unlock()
b.balance += amount
}
func (b *BankAccount) Withdraw(amount float64) {
b.mu.Lock()
defer b.mu.Unlock()
b.balance -= amount
}
...
41
Tratamento funcional de concorrência
type BankAccount struct {
balance float64
operations chan func(float64) float64
}
func (b *BankAccount) Deposit(amount float64) {
b.operations <- func(oldBalance float64) float64 {
return oldBalance + amount
}
}
func (b *BankAccount) Withdraw(amount float64) {
b.operations <- func(oldBalance float64) float64 {
return oldBalance - amount
}
}
42
Tratamento funcional de concorrência
func (b *BankAccount) Loop() {
for op := range b.operations {
b.balance = op(b.balance)
}
}
func NewBankAccount() *BankAccount {
return &BankAccount{
balance: 0,
operations: make(chan func(float64) float64),
}
}
func main() {
acc := NewBankAccount()
...
go func(account *BankAccount) {
acc.Loop()
}(acc)
43
func(func(func(func(func(func(...))))))
44
Simple Server Novamente
package main
import (
"log"
"net/http"
)
func main() {
log.Println(NewServer(":8080"))
}
func NewServer(address string) error {
r := http.NewServeMux()
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("My Web Servern"))
})
srv := &http.Server{
Addr: address,
Handler: r,
}
return srv.ListenAndServe()
}
45
Simple Server com Funções
func main() {
log.Println(NewServer(":8080"))
}
func NewServer(address string) error {
r := http.NewServeMux()
r.HandleFunc("/", GetMainResponse())
srv := &http.Server{
Addr: address,
Handler: r,
}
return srv.ListenAndServe()
}
func GetMainResponse() func (http.ResponseWriter,*http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("My Web Servern"))
}
}
46
Simple Server - Assinatura
func GetMainResponse() func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("My Web Servern"))
}
}
func(w http.ResponseWriter, r *http.Request)
47
Decorated Simple Server
func TraceRequest(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
log.Printf("Start request: %s", time.Now())
f(w, r)
log.Printf("End request: %s", time.Now())
}
}
48
Decorated Simple Server
func Authenticate(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
auth := r.Header.Get("Authorization")
if len(auth) == 0 { //Check token
w.WriteHeader(401)
} else {
f(w, r)
}
}
}
49
Decorated Simple Server
func NewServer(address string) error {
r := http.NewServeMux()
r.HandleFunc("/", Authenticate(TraceRequest(GetMainResponse())))
srv := &http.Server{
Addr: address,
Handler: r,
}
return srv.ListenAndServe()
}
50
Real world examples!!!
https://github.com/prometheus/prometheus/blob/master/web/api/v1/api.go
type apiFunc func(r *http.Request) apiFuncResult
func (api *API) Register(r *route.Router) {
wrap := func(f apiFunc) http.HandlerFunc {
hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
httputil.SetCORS(w, api.CORSOrigin, r)
result := f(r)
if result.err != nil {
api.respondError(w, result.err, result.data)
} else if result.data != nil {
api.respond(w, result.data, result.warnings)
} else {
w.WriteHeader(http.StatusNoContent)
}
if result.finalizer != nil {
result.finalizer()
}
})
return api.ready(httputil.CompressionHandler{
Handler: hf,
}.ServeHTTP)
}
...
Real world examples!!!
https://github.com/prometheus/prometheus/blob/master/web/api/v1/api.go
wrap := func(f apiFunc) http.HandlerFunc {}
r.Options("/*path", wrap(api.options))
r.Get("/query", wrap(api.query))
r.Post("/query", wrap(api.query))
r.Get("/query_range", wrap(api.queryRange))
52
Real world examples!!!
https://github.com/golang/text/blob/master/cases/cases.go#L93
type Option func(o options) options
func Fold(opts ...Option) Caser {
return Caser{makeFold(getOpts(opts...))}
}
func getOpts(o ...Option) (res options) {
for _, f := range o {
res = f(res)
}
return
}
53
Real world examples!!!
Gorm Database Client
Formato com encadeamento de métodos
db, _ := gorm.Open(...)
var user User
err := db.Where("email = ?", "email@host.com").
Where("age >= ?", 18).
First(&user).
Error
Exige a codi cação de uma estrutura
var user User
err = db.First(&user,
Where("email = ?", "jon@calhoun.io"),
Where("id = ?", 2),
)
54
Vantagens
API mais fáceis e compreensíveis no
uso
Possibilidade de se entregar a closure
pronta para uso
Facilidade de se estender (novas
closures)
Valores default já pré-con gurados
Criação de uent-API com
encadeamento de closures
Decorator pattern com baixa
complexidade
Desvantagens
Mutabilidade da estrutura de
con guração
Maior quantidade de código
Maior demanda cognitiva
Mudança de paradigma para criação
soluções
The right tool for the right job
55
High-order functions como ferramenta
56
Muito obrigado!
Conteúdo
slides: https://zamariola.com.br/slides/devcamp2019
exemplos: https://github.com/zamariola
Referências
https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-
design.html
https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
https://www.youtube.com/watch?v=5IKcPMJXkKs
https://dave.cheney.net/2016/11/13/do-not-fear- rst-class-functions
https://www.calhoun.io/using-functional-options-instead-of-method-chaining-in-go/
57

More Related Content

What's hot

007 programando em python - funcoes
007   programando em python - funcoes007   programando em python - funcoes
007 programando em python - funcoes
Leandro Barbosa
 
Implementação em ActionScript 3 do Protocolo IRC
Implementação em ActionScript 3 do Protocolo IRCImplementação em ActionScript 3 do Protocolo IRC
Implementação em ActionScript 3 do Protocolo IRC
José Travado
 

What's hot (20)

Tutorial dev cpp 002 - criação, leitura e alteração de arquivos
Tutorial dev cpp   002 - criação, leitura e alteração de arquivosTutorial dev cpp   002 - criação, leitura e alteração de arquivos
Tutorial dev cpp 002 - criação, leitura e alteração de arquivos
 
007 programando em python - funcoes
007   programando em python - funcoes007   programando em python - funcoes
007 programando em python - funcoes
 
Design de código: princípios e práticas para ter um código sustentável
Design de código: princípios e práticas para ter um código sustentávelDesign de código: princípios e práticas para ter um código sustentável
Design de código: princípios e práticas para ter um código sustentável
 
Threads 07: Sincronizadores
Threads 07: SincronizadoresThreads 07: Sincronizadores
Threads 07: Sincronizadores
 
Curso de Node JS Básico
Curso de Node JS BásicoCurso de Node JS Básico
Curso de Node JS Básico
 
Proxy, Man-In-The-Middle e testes
Proxy, Man-In-The-Middle e testesProxy, Man-In-The-Middle e testes
Proxy, Man-In-The-Middle e testes
 
Threads 09: Paralelismo
Threads 09: ParalelismoThreads 09: Paralelismo
Threads 09: Paralelismo
 
Doctrine2 Seminário PHP
Doctrine2 Seminário PHPDoctrine2 Seminário PHP
Doctrine2 Seminário PHP
 
Implementação em ActionScript 3 do Protocolo IRC
Implementação em ActionScript 3 do Protocolo IRCImplementação em ActionScript 3 do Protocolo IRC
Implementação em ActionScript 3 do Protocolo IRC
 
servlet-respostas
servlet-respostasservlet-respostas
servlet-respostas
 
Al sweigart, cap 3
Al sweigart, cap 3Al sweigart, cap 3
Al sweigart, cap 3
 
Threads 06: Coleções concorrentes
Threads 06: Coleções concorrentesThreads 06: Coleções concorrentes
Threads 06: Coleções concorrentes
 
Threads 10: CompletableFuture
Threads 10: CompletableFutureThreads 10: CompletableFuture
Threads 10: CompletableFuture
 
Curso de Java: Threads
Curso de Java: ThreadsCurso de Java: Threads
Curso de Java: Threads
 
Threads 04 Variáveis atômicas
Threads 04 Variáveis atômicasThreads 04 Variáveis atômicas
Threads 04 Variáveis atômicas
 
Aula c++ estruturas de dados
Aula c++   estruturas de dadosAula c++   estruturas de dados
Aula c++ estruturas de dados
 
A Classe StringBuilder em Java
A Classe StringBuilder em JavaA Classe StringBuilder em Java
A Classe StringBuilder em Java
 
Membros da Classe - Preparatório Certificação - OCAJP7 - Aula 2 - D
Membros da Classe - Preparatório Certificação - OCAJP7 - Aula 2 - DMembros da Classe - Preparatório Certificação - OCAJP7 - Aula 2 - D
Membros da Classe - Preparatório Certificação - OCAJP7 - Aula 2 - D
 
Grupo2
Grupo2Grupo2
Grupo2
 
TDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.JsTDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.Js
 

Similar to Leonardo Zamariola - High Order Functions e Functional Interfaces

Python para quem sabe Python (aula 2)
Python para quem sabe Python (aula 2)Python para quem sabe Python (aula 2)
Python para quem sabe Python (aula 2)
Luciano Ramalho
 
Java orientação a objetos (interfaces)
Java   orientação a objetos (interfaces)Java   orientação a objetos (interfaces)
Java orientação a objetos (interfaces)
Armando Daniel
 

Similar to Leonardo Zamariola - High Order Functions e Functional Interfaces (20)

Pythonfuncional
PythonfuncionalPythonfuncional
Pythonfuncional
 
Python Funcional
Python FuncionalPython Funcional
Python Funcional
 
Refatoração de código com Capitão Nascimento versão completa
Refatoração de código com Capitão Nascimento versão completaRefatoração de código com Capitão Nascimento versão completa
Refatoração de código com Capitão Nascimento versão completa
 
Desmistificando Built-in Functions, Lambda e List Comprehension...
Desmistificando Built-in Functions, Lambda e List Comprehension...Desmistificando Built-in Functions, Lambda e List Comprehension...
Desmistificando Built-in Functions, Lambda e List Comprehension...
 
Ecosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javEcosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_jav
 
Parte1c
Parte1cParte1c
Parte1c
 
Spock Framework 2
Spock Framework 2Spock Framework 2
Spock Framework 2
 
Introdução a python
Introdução a pythonIntrodução a python
Introdução a python
 
Python para quem sabe Python (aula 2)
Python para quem sabe Python (aula 2)Python para quem sabe Python (aula 2)
Python para quem sabe Python (aula 2)
 
Linguagem Go
Linguagem GoLinguagem Go
Linguagem Go
 
Golang para desenvolvedores pragmáticos parte 2
Golang para desenvolvedores pragmáticos  parte 2Golang para desenvolvedores pragmáticos  parte 2
Golang para desenvolvedores pragmáticos parte 2
 
Evento Front End SP - Organizando o Javascript
 Evento Front End SP - Organizando o Javascript Evento Front End SP - Organizando o Javascript
Evento Front End SP - Organizando o Javascript
 
Sobrecarga operadores
Sobrecarga operadoresSobrecarga operadores
Sobrecarga operadores
 
Entre na fila. Processamento distribuído usando Gearman
Entre na fila. Processamento distribuído usando GearmanEntre na fila. Processamento distribuído usando Gearman
Entre na fila. Processamento distribuído usando Gearman
 
Introdução a linguagem Go
Introdução a linguagem GoIntrodução a linguagem Go
Introdução a linguagem Go
 
Java orientação a objetos (interfaces)
Java   orientação a objetos (interfaces)Java   orientação a objetos (interfaces)
Java orientação a objetos (interfaces)
 
Scala na soundcloud [QCon]
Scala na soundcloud [QCon]Scala na soundcloud [QCon]
Scala na soundcloud [QCon]
 
Design patterns
Design patternsDesign patterns
Design patterns
 
Java para iniciantes
Java para iniciantesJava para iniciantes
Java para iniciantes
 
App scala
App scalaApp scala
App scala
 

More from DevCamp Campinas

Dylan Butler & Oliver Hager - Building a cross platform cryptocurrency app
Dylan Butler & Oliver Hager - Building a cross platform cryptocurrency appDylan Butler & Oliver Hager - Building a cross platform cryptocurrency app
Dylan Butler & Oliver Hager - Building a cross platform cryptocurrency app
DevCamp Campinas
 
Thaissa Bueno - Implantando modelos Deep Learning em cluster Kubernetes com G...
Thaissa Bueno - Implantando modelos Deep Learning em cluster Kubernetes com G...Thaissa Bueno - Implantando modelos Deep Learning em cluster Kubernetes com G...
Thaissa Bueno - Implantando modelos Deep Learning em cluster Kubernetes com G...
DevCamp Campinas
 
Gabriel Pacheco e Felipe Cardoso - Nextel + React Native: Lições aprendidas a...
Gabriel Pacheco e Felipe Cardoso - Nextel + React Native: Lições aprendidas a...Gabriel Pacheco e Felipe Cardoso - Nextel + React Native: Lições aprendidas a...
Gabriel Pacheco e Felipe Cardoso - Nextel + React Native: Lições aprendidas a...
DevCamp Campinas
 
Everton Gago - Ciência de Dados: O melhor caminho para alinhar o produto com ...
Everton Gago - Ciência de Dados: O melhor caminho para alinhar o produto com ...Everton Gago - Ciência de Dados: O melhor caminho para alinhar o produto com ...
Everton Gago - Ciência de Dados: O melhor caminho para alinhar o produto com ...
DevCamp Campinas
 
Eiti Kimura - Analisador de dados automatizado utilizando machine learning
Eiti Kimura - Analisador de dados automatizado utilizando machine learningEiti Kimura - Analisador de dados automatizado utilizando machine learning
Eiti Kimura - Analisador de dados automatizado utilizando machine learning
DevCamp Campinas
 
Bárbara Silveira e Giovanna Victorino - Desenvolva também para TVs (AppleTV e...
Bárbara Silveira e Giovanna Victorino - Desenvolva também para TVs (AppleTV e...Bárbara Silveira e Giovanna Victorino - Desenvolva também para TVs (AppleTV e...
Bárbara Silveira e Giovanna Victorino - Desenvolva também para TVs (AppleTV e...
DevCamp Campinas
 
Eduardo Merighi - Escalabilidade tecnológica de uma fintech: como a Neon faz?
Eduardo Merighi - Escalabilidade tecnológica de uma fintech: como a Neon faz?Eduardo Merighi - Escalabilidade tecnológica de uma fintech: como a Neon faz?
Eduardo Merighi - Escalabilidade tecnológica de uma fintech: como a Neon faz?
DevCamp Campinas
 

More from DevCamp Campinas (20)

Dylan Butler & Oliver Hager - Building a cross platform cryptocurrency app
Dylan Butler & Oliver Hager - Building a cross platform cryptocurrency appDylan Butler & Oliver Hager - Building a cross platform cryptocurrency app
Dylan Butler & Oliver Hager - Building a cross platform cryptocurrency app
 
Thaissa Bueno - Implantando modelos Deep Learning em cluster Kubernetes com G...
Thaissa Bueno - Implantando modelos Deep Learning em cluster Kubernetes com G...Thaissa Bueno - Implantando modelos Deep Learning em cluster Kubernetes com G...
Thaissa Bueno - Implantando modelos Deep Learning em cluster Kubernetes com G...
 
Gabriel Pacheco e Felipe Cardoso - Nextel + React Native: Lições aprendidas a...
Gabriel Pacheco e Felipe Cardoso - Nextel + React Native: Lições aprendidas a...Gabriel Pacheco e Felipe Cardoso - Nextel + React Native: Lições aprendidas a...
Gabriel Pacheco e Felipe Cardoso - Nextel + React Native: Lições aprendidas a...
 
Everton Gago - Ciência de Dados: O melhor caminho para alinhar o produto com ...
Everton Gago - Ciência de Dados: O melhor caminho para alinhar o produto com ...Everton Gago - Ciência de Dados: O melhor caminho para alinhar o produto com ...
Everton Gago - Ciência de Dados: O melhor caminho para alinhar o produto com ...
 
Eiti Kimura - Analisador de dados automatizado utilizando machine learning
Eiti Kimura - Analisador de dados automatizado utilizando machine learningEiti Kimura - Analisador de dados automatizado utilizando machine learning
Eiti Kimura - Analisador de dados automatizado utilizando machine learning
 
Bárbara Silveira e Giovanna Victorino - Desenvolva também para TVs (AppleTV e...
Bárbara Silveira e Giovanna Victorino - Desenvolva também para TVs (AppleTV e...Bárbara Silveira e Giovanna Victorino - Desenvolva também para TVs (AppleTV e...
Bárbara Silveira e Giovanna Victorino - Desenvolva também para TVs (AppleTV e...
 
Lara Rejane - Gestão ágil de pessoas
Lara Rejane - Gestão ágil de pessoasLara Rejane - Gestão ágil de pessoas
Lara Rejane - Gestão ágil de pessoas
 
Eduardo Merighi - Escalabilidade tecnológica de uma fintech: como a Neon faz?
Eduardo Merighi - Escalabilidade tecnológica de uma fintech: como a Neon faz?Eduardo Merighi - Escalabilidade tecnológica de uma fintech: como a Neon faz?
Eduardo Merighi - Escalabilidade tecnológica de uma fintech: como a Neon faz?
 
Erick Zanardo - Desenvolvimento de Jogos em Flutter
Erick Zanardo - Desenvolvimento de Jogos em FlutterErick Zanardo - Desenvolvimento de Jogos em Flutter
Erick Zanardo - Desenvolvimento de Jogos em Flutter
 
Davi Silva e Izabela Amaral - Oferecendo soluções de negócio mais assertivas ...
Davi Silva e Izabela Amaral - Oferecendo soluções de negócio mais assertivas ...Davi Silva e Izabela Amaral - Oferecendo soluções de negócio mais assertivas ...
Davi Silva e Izabela Amaral - Oferecendo soluções de negócio mais assertivas ...
 
Andre Fossa - Reinventando a Nextel: como a transformação digital ajudou a qu...
Andre Fossa - Reinventando a Nextel: como a transformação digital ajudou a qu...Andre Fossa - Reinventando a Nextel: como a transformação digital ajudou a qu...
Andre Fossa - Reinventando a Nextel: como a transformação digital ajudou a qu...
 
Alceu Bravo - Intraempreendedorismo – desafios da inovação para quem tem base...
Alceu Bravo - Intraempreendedorismo – desafios da inovação para quem tem base...Alceu Bravo - Intraempreendedorismo – desafios da inovação para quem tem base...
Alceu Bravo - Intraempreendedorismo – desafios da inovação para quem tem base...
 
Fábio Lima Santos - Desenhando aplicações que evoluem
Fábio Lima Santos - Desenhando aplicações que evoluemFábio Lima Santos - Desenhando aplicações que evoluem
Fábio Lima Santos - Desenhando aplicações que evoluem
 
João Emilio Santos Bento da Silva - Estratégia de APIs
João Emilio Santos Bento da Silva - Estratégia de APIsJoão Emilio Santos Bento da Silva - Estratégia de APIs
João Emilio Santos Bento da Silva - Estratégia de APIs
 
José Guedes - Como encaramos quando as coisas dão errado
José Guedes - Como encaramos quando as coisas dão erradoJosé Guedes - Como encaramos quando as coisas dão errado
José Guedes - Como encaramos quando as coisas dão errado
 
Rafael Calsaverini - Inteligência Artificial para recrutar pessoas – Tecnolog...
Rafael Calsaverini - Inteligência Artificial para recrutar pessoas – Tecnolog...Rafael Calsaverini - Inteligência Artificial para recrutar pessoas – Tecnolog...
Rafael Calsaverini - Inteligência Artificial para recrutar pessoas – Tecnolog...
 
Isac Sacchi e Souza - Migrando uma infraestrutura mutável para imutável e Kub...
Isac Sacchi e Souza - Migrando uma infraestrutura mutável para imutável e Kub...Isac Sacchi e Souza - Migrando uma infraestrutura mutável para imutável e Kub...
Isac Sacchi e Souza - Migrando uma infraestrutura mutável para imutável e Kub...
 
Ingrid Barth - Blockchain, Criptomoedas e a nova maneira de entender o dinheiro
Ingrid Barth - Blockchain, Criptomoedas e a nova maneira de entender o dinheiroIngrid Barth - Blockchain, Criptomoedas e a nova maneira de entender o dinheiro
Ingrid Barth - Blockchain, Criptomoedas e a nova maneira de entender o dinheiro
 
Igor Hjelmstrom Ribeiro - Bitcoin: desafios de segurança frente à ataques de...
Igor Hjelmstrom Ribeiro -  Bitcoin: desafios de segurança frente à ataques de...Igor Hjelmstrom Ribeiro -  Bitcoin: desafios de segurança frente à ataques de...
Igor Hjelmstrom Ribeiro - Bitcoin: desafios de segurança frente à ataques de...
 
Fabio De Santi e Thiago Urtaran - Smart cities: um caso real, a arquitetura d...
Fabio De Santi e Thiago Urtaran - Smart cities: um caso real, a arquitetura d...Fabio De Santi e Thiago Urtaran - Smart cities: um caso real, a arquitetura d...
Fabio De Santi e Thiago Urtaran - Smart cities: um caso real, a arquitetura d...
 

Recently uploaded

Assessement Boas Praticas em Kubernetes.pdf
Assessement Boas Praticas em Kubernetes.pdfAssessement Boas Praticas em Kubernetes.pdf
Assessement Boas Praticas em Kubernetes.pdf
Natalia Granato
 

Recently uploaded (6)

Assessement Boas Praticas em Kubernetes.pdf
Assessement Boas Praticas em Kubernetes.pdfAssessement Boas Praticas em Kubernetes.pdf
Assessement Boas Praticas em Kubernetes.pdf
 
ATIVIDADE 1 - LOGÍSTICA EMPRESARIAL - 52_2024.docx
ATIVIDADE 1 - LOGÍSTICA EMPRESARIAL - 52_2024.docxATIVIDADE 1 - LOGÍSTICA EMPRESARIAL - 52_2024.docx
ATIVIDADE 1 - LOGÍSTICA EMPRESARIAL - 52_2024.docx
 
Boas práticas de programação com Object Calisthenics
Boas práticas de programação com Object CalisthenicsBoas práticas de programação com Object Calisthenics
Boas práticas de programação com Object Calisthenics
 
Padrões de Projeto: Proxy e Command com exemplo
Padrões de Projeto: Proxy e Command com exemploPadrões de Projeto: Proxy e Command com exemplo
Padrões de Projeto: Proxy e Command com exemplo
 
ATIVIDADE 1 - GCOM - GESTÃO DA INFORMAÇÃO - 54_2024.docx
ATIVIDADE 1 - GCOM - GESTÃO DA INFORMAÇÃO - 54_2024.docxATIVIDADE 1 - GCOM - GESTÃO DA INFORMAÇÃO - 54_2024.docx
ATIVIDADE 1 - GCOM - GESTÃO DA INFORMAÇÃO - 54_2024.docx
 
ATIVIDADE 1 - CUSTOS DE PRODUÇÃO - 52_2024.docx
ATIVIDADE 1 - CUSTOS DE PRODUÇÃO - 52_2024.docxATIVIDADE 1 - CUSTOS DE PRODUÇÃO - 52_2024.docx
ATIVIDADE 1 - CUSTOS DE PRODUÇÃO - 52_2024.docx
 

Leonardo Zamariola - High Order Functions e Functional Interfaces

  • 1. High Order Functions e Functional Interfaces Devcamp 16/08/2019 1
  • 2. Especialista em desenvolvimento backend. 11 anos em desenvolvimento Java Certi ed Associate Go desde 2016 Sobre 2
  • 4. Foco em simplicidade de soluções Sintaxe simples Uma única (ou poucas) formas de se fazer algo Leitura e escrita homogêneas por todo ecossistema Por que os exemplos em Go? 4
  • 5. Idiomático public class SimpleHashSetExample { public static void main(String[] args) { HashSet hSet = new HashSet(); hSet.add(new Integer("1")); hSet.add(new Integer("2")); hSet.add(new Integer("3")); System.out.println("HashSet contains.." + hSet); } } 5
  • 6. Idiomático class Animal(val name: String) class Zoo(val animals: List<Animal>) { operator fun iterator(): Iterator<Animal> { return animals.iterator() } } fun main() { val zoo = Zoo(listOf(Animal("zebra"), Animal("lion"))) for (animal in zoo) { println("Watch out, it's a ${animal.name}") } } 6
  • 8. Domínio Estrutura das entidades Composição ou herança Estrutura de persistência type Entity struct { name string ... } Regra de negócio Fluxo e manipulação de entidades Regra de negócio Adição ou remoção de etapas de processamento func (e Entity) transformedName() string { return e.name + " with transformation" } ... The right tool for the right job 8
  • 9. Server simples em Go package main import ( "log" "net/http" ) func main() { log.Println(NewServer(":8080")) } func NewServer(address string) error { r := http.NewServeMux() r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("My Web Servern")) }) r.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("{"success":true}")) }) srv := &http.Server{ Addr: address, Handler: r, } return srv.ListenAndServe() }
  • 10. Server simples em Go + Timeout func main() { log.Println(NewServer(":8080", 2*time.Second, 5*time.Second)) } func NewServer(address string, rt, wt time.Duration) error { r := http.NewServeMux() r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("My Web Servern")) }) r.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("{"success":true}")) }) srv := &http.Server{ Addr: address, Handler: r, ReadTimeout: rt, WriteTimeout: wt, } return srv.ListenAndServe() } 10
  • 11. Server simples em Go + Timeout + TLS func main() { log.Println(NewServer(":8080", "cert.pem", "key.pem", 2*time.Second, 5*time.Second)) } func NewServer(address, cert, key string, rt, wt time.Duration) error { r := http.NewServeMux() r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("My Web Servern")) }) r.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("{"success":true}")) }) srv := &http.Server{ Addr: address, Handler: r, ReadTimeout: rt, WriteTimeout: wt, } return srv.ListenAndServeTLS(cert, key) } 11
  • 12. Muitas assinaturas para "mesma" função func NewServer(address string) error {} func NewServer(address string, rt, wt time.Duration) error {} func NewServer(address, cert, key string) error {} func NewServer(address, cert, key string, rt, wt time.Duration) error {} 12
  • 13. Server simples em Go + Con g type Config struct { Address string CertPath string KeyPath string ReadTimeout time.Duration WriteTimeout time.Duration } func main() { config := Config{":8080", "cert.pem", "key.pem", 2 * time.Second, 5 * time.Second} log.Println(NewServer(config)) } 13
  • 14. Server simples em Go + Con g func NewServer(c Config) error { r := http.NewServeMux() r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("My Web Servern")) }) r.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("{"success":true}")) }) srv := &http.Server{ Addr: c.Address, Handler: r, ReadTimeout: c.ReadTimeout, WriteTimeout: c.WriteTimeout, } return srv.ListenAndServeTLS(c.CertPath, c.KeyPath) } 14
  • 15. Con guration structs Vantagens Melhora a documentação e entendimento do código. Permite utilizar "zero values" como regra Crescimento das con gurações sem quebrar assinatura 15
  • 16. Con guration structs Desvantagens Gera diversos possíveis problemas com "zero values", exemplo: porta 0 c := Config{ "cert.pem", "key.pem" } O cenário ideal para "default" value seria aleatoriamente escolher uma porta e não ir direto para a zero. Mas e se quisermos tentar a porta zero? Quais campos são obrigatórios e quais são opcionais? 16
  • 17. Con guration structs Problema da mutabilidade config := Config{ ":8080", "cert.pem", "key.pem", 2 * time.Second, 5 * time.Second } go func() { config.Address = ":9090" }() log.Println(NewServer(config)) Problema da obrigatoridade func main() { //Quero o server mais simples possível!! log.Println(NewServer(????)) } 17
  • 18. High-Order Function Função que faz pelo menos uma das duas: 1. Recebe uma (ou mais) funções como parâmetros 2. Retorna uma função Exemplos: Cálculo: dy/dx (operador de diferencial) que recebe uma função e retorna a sua derivada callbacks em Javascript http.HandlerFunc(pattern, handlerFunc) 18
  • 19. High-Order Function + rst class citizen package main import "fmt" //High-Order: retorna uma função func myFunction() func(int, int) int { return func(a, b int) int { return a + b } } func main() { //first class citizen: atribuir a uma variável f := myFunction() //first class citizen: chamar através da variável soma := f(2, 3) fmt.Println(soma) } 19
  • 20. High-Order Function + Type Alias package main import "fmt" //type alias type SomaFunc func(int, int) int //High-Order: retorna uma função func myFunction() SomaFunc { return func(a, b int) int { return a + b } } func main() { //first class citizen: atribuir a uma variável f := myFunction() //first class citizen: chamar através da variável soma := f(2, 3) fmt.Println(soma) } 20
  • 21. High-Order na Prática package main import "net/http" func main() { //first class citizen: atribuir a uma variável f := handlerFunction() http.HandleFunc("/", f) http.ListenAndServe(":8080", nil) } //High-Order: retorna uma função func handlerFunction() func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Contentn")) } } 21
  • 22. High-order functions como ferramenta 22
  • 23. Relembrar: server deprecado func main() { log.Println(NewServer(":8080", "cert.pem", "key.pem", 2*time.Second, 5*time.Second)) } func NewServer(address, cert, key string, rt, wt time.Duration) error { r := http.NewServeMux() r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("My Web Servern")) }) r.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("{"success":true}")) }) srv := &http.Server{ Addr: address, Handler: r, ReadTimeout: rt, WriteTimeout: wt, } return srv.ListenAndServeTLS(cert, key) 23
  • 24. Functional Server Ajuste na estrutura do server: criando a struct type Server struct { Ltn net.Listener ReadTimeout time.Duration WriteTimeout time.Duration Handler http.Handler } func NewServer(addr string) (*Server, error) { dftLtn, err := net.Listen("tcp", addr) return &Server{ Ltn: dftLtn, ReadTimeout: 3 * time.Second, WriteTimeout: 5 * time.Second, }, err } 24
  • 25. Functional Server Ajuste na estrutura do server: usando a struct func (s *Server) Serve() error { srv := &http.Server{ Handler: s.Handler, ReadTimeout: s.ReadTimeout, WriteTimeout: s.WriteTimeout, } return srv.Serve(s.Ltn) } func main() { sv, err := NewServer(":8080") if err != nil { panic(err) } log.Println(sv.Serve()) } 25
  • 26. Functional Server Com Options Como inserir um read time out no nosso functional server? Opção 1: parametro na criação (muda algo?) func NewServer(addr string, readTimeout time.Duration) (*Server, error) { dftLtn, err := net.Listen("tcp", addr) return &Server{ Ltn: dftLtn, ReadTimeout: readTimeout, WriteTimeout: 5 * time.Second, }, err } 26
  • 27. Functional Server Com Options Opção 2: mutar o server depois de criado func main() { sv, err := NewServer(":8080") if err != nil { panic(err) } sv.ReadTimeout = 3*time.Second log.Println(sv.Serve()) } Imperativo: baixo reaproveitamento Poucas abstrações Clara e distribuída quebra de imutabilidade 27
  • 28. Functional Server Com Options Opção 3: criar um método no server func (s *Server) setTimeout(timeout time.Duration) error { sv.ReadTimeout = timeout } func main() { sv, err := NewServer(":8080") if err != nil { panic(err) } sv.setTimeout(3*time.Second) log.Println(sv.Serve()) } Clara e distribuída quebra de imutabilidade 28
  • 29. Functional Server Com Options Opção 4: criar uma função que altera timeout func WithTimeout(read, write time.Duration) func(*Server) { return func(s *Server) { s.ReadTimeout = read s.WriteTimeout = write } } func main() { sv, err := NewServer(":8080") if err != nil { panic(err) } f := WithTimeout(3*time.Second, 5*time.Second) f(sv) log.Println(sv.Serve()) } Sensação de maior encapsulamento Clara e distribuída quebra de imutabilidade 29
  • 30. Functional Server Com Option Opção 5: criar uma função que altera timeout E recebê-la somente no Serve func WithTimeout(read, write time.Duration) func(*Server) {...} func (s *Server) Serve(option func(*Server)) error { option(s) srv := &http.Server{ Handler: s.Handler, ReadTimeout: s.ReadTimeout, WriteTimeout: s.WriteTimeout, } return srv.Serve(s.Ltn) } func main() { sv, err := NewServer(":8080") if err != nil { panic(err) } log.Println(sv.Serve( WithTimeout(3*time.Second, 5*time.Second) )) } Mutação ainda acontece, mas somente no uso nal
  • 31. Functional Server Com Options (plural) func (s *Server) Serve(options ...func(*Server)) error { for _, opt := range options { opt(s) } srv := &http.Server{ Handler: s.Handler, ReadTimeout: s.ReadTimeout, WriteTimeout: s.WriteTimeout, } return srv.Serve(s.Ltn) } func main() { sv, err := NewServer(":8080") if err != nil { panic(err) } log.Println(sv.Serve( WithTimeout(3*time.Second, 5*time.Second) )) } 31
  • 32. Functional Server Com Options (plural) Inserindo rotas func WithRoutes() func(*Server) { return func(s *Server) { r := http.NewServeMux() r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("My Web Servern")) }) r.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("{"success":true}")) }) s.Handler = r } } 32
  • 33. Functional Server Com Options (plural) Inserindo certi cado func WithCertificate(cert, key string) func(*Server) { return func(s *Server) { cert, err := tls.LoadX509KeyPair(cert, key) if err != nil { panic(err) } config := &tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true} //Close old listener if err := s.Ltn.Close(); err != nil { panic(err) } //Keep old address originalAddr := s.Ltn.Addr().String() ltn, err := tls.Listen("tcp", originalAddr, config) if err != nil { panic(err) } s.Ltn = ltn } } 33
  • 34. Criando o server com Go idiomático 34
  • 35. Functional Server Com Options (plural) Criando o server func WithCertificate(cert, key string) func(*Server) {...} func WithTimeout(read, write time.Duration) func(*Server) {...} func WithRoutes() func(*Server) {...} func main() { sv, err := NewServer(":8080") if err != nil { panic(err) } log.Println(sv.Serve( WithRoutes(), WithTimeout(2*time.Second, 3*time.Second), WithCertificate("cert.pem", "key.pem"), )) } Toda a con guração do server está no uxo de criação do server Permite o criação de uma API uente 35
  • 37. Onde usar? Con guração de serviços, clientes ou structs De nição de strategy pattern Cenários de sincronia -> passagem de comportamento vs passagem de dados 37
  • 38. Onde usar? Con guração de serviços, clientes ou structs De nição de strategy pattern Cenários de sincronia -> passagem de comportamento vs passagem de dados 38
  • 39. Mais simples bank account package main import "fmt" type BankAccount struct { balance float64 } func (b *BankAccount) Deposit(amount float64) { b.balance += amount } func (b *BankAccount) Withdraw(amount float64) { b.balance -= amount } func (b *BankAccount) Balance() float64 { return b.balance } func main() { acc := BankAccount{} acc.Deposit(50) acc.Withdraw(40) fmt.Println(acc.Balance()) } 39
  • 40. Cenário de simples "concorrência" type BankAccount struct{ balance float64 } func (b *BankAccount) Deposit(amount float64) { b.balance += amount } func (b *BankAccount) Withdraw(amount float64) { b.balance -= amount } func (b *BankAccount) Balance() float64 { return b.balance } func main() { var wg sync.WaitGroup acc := BankAccount{} for i := 0; i < 100000; i++ { wg.Add(1) go func(account *BankAccount) { account.Deposit(10) account.Withdraw(account.Balance() / 2) wg.Done() }(&acc) } wg.Wait() fmt.Println(acc.Balance()) } 40
  • 41. Tratamento padrão de concorrência package main import ( "fmt" "sync" ) type BankAccount struct { balance float64 mu sync.Mutex } func (b *BankAccount) Deposit(amount float64) { b.mu.Lock() defer b.mu.Unlock() b.balance += amount } func (b *BankAccount) Withdraw(amount float64) { b.mu.Lock() defer b.mu.Unlock() b.balance -= amount } ... 41
  • 42. Tratamento funcional de concorrência type BankAccount struct { balance float64 operations chan func(float64) float64 } func (b *BankAccount) Deposit(amount float64) { b.operations <- func(oldBalance float64) float64 { return oldBalance + amount } } func (b *BankAccount) Withdraw(amount float64) { b.operations <- func(oldBalance float64) float64 { return oldBalance - amount } } 42
  • 43. Tratamento funcional de concorrência func (b *BankAccount) Loop() { for op := range b.operations { b.balance = op(b.balance) } } func NewBankAccount() *BankAccount { return &BankAccount{ balance: 0, operations: make(chan func(float64) float64), } } func main() { acc := NewBankAccount() ... go func(account *BankAccount) { acc.Loop() }(acc) 43
  • 45. Simple Server Novamente package main import ( "log" "net/http" ) func main() { log.Println(NewServer(":8080")) } func NewServer(address string) error { r := http.NewServeMux() r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("My Web Servern")) }) srv := &http.Server{ Addr: address, Handler: r, } return srv.ListenAndServe() } 45
  • 46. Simple Server com Funções func main() { log.Println(NewServer(":8080")) } func NewServer(address string) error { r := http.NewServeMux() r.HandleFunc("/", GetMainResponse()) srv := &http.Server{ Addr: address, Handler: r, } return srv.ListenAndServe() } func GetMainResponse() func (http.ResponseWriter,*http.Request) { return func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("My Web Servern")) } } 46
  • 47. Simple Server - Assinatura func GetMainResponse() func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("My Web Servern")) } } func(w http.ResponseWriter, r *http.Request) 47
  • 48. Decorated Simple Server func TraceRequest(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { log.Printf("Start request: %s", time.Now()) f(w, r) log.Printf("End request: %s", time.Now()) } } 48
  • 49. Decorated Simple Server func Authenticate(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { auth := r.Header.Get("Authorization") if len(auth) == 0 { //Check token w.WriteHeader(401) } else { f(w, r) } } } 49
  • 50. Decorated Simple Server func NewServer(address string) error { r := http.NewServeMux() r.HandleFunc("/", Authenticate(TraceRequest(GetMainResponse()))) srv := &http.Server{ Addr: address, Handler: r, } return srv.ListenAndServe() } 50
  • 51. Real world examples!!! https://github.com/prometheus/prometheus/blob/master/web/api/v1/api.go type apiFunc func(r *http.Request) apiFuncResult func (api *API) Register(r *route.Router) { wrap := func(f apiFunc) http.HandlerFunc { hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { httputil.SetCORS(w, api.CORSOrigin, r) result := f(r) if result.err != nil { api.respondError(w, result.err, result.data) } else if result.data != nil { api.respond(w, result.data, result.warnings) } else { w.WriteHeader(http.StatusNoContent) } if result.finalizer != nil { result.finalizer() } }) return api.ready(httputil.CompressionHandler{ Handler: hf, }.ServeHTTP) } ...
  • 52. Real world examples!!! https://github.com/prometheus/prometheus/blob/master/web/api/v1/api.go wrap := func(f apiFunc) http.HandlerFunc {} r.Options("/*path", wrap(api.options)) r.Get("/query", wrap(api.query)) r.Post("/query", wrap(api.query)) r.Get("/query_range", wrap(api.queryRange)) 52
  • 53. Real world examples!!! https://github.com/golang/text/blob/master/cases/cases.go#L93 type Option func(o options) options func Fold(opts ...Option) Caser { return Caser{makeFold(getOpts(opts...))} } func getOpts(o ...Option) (res options) { for _, f := range o { res = f(res) } return } 53
  • 54. Real world examples!!! Gorm Database Client Formato com encadeamento de métodos db, _ := gorm.Open(...) var user User err := db.Where("email = ?", "email@host.com"). Where("age >= ?", 18). First(&user). Error Exige a codi cação de uma estrutura var user User err = db.First(&user, Where("email = ?", "jon@calhoun.io"), Where("id = ?", 2), ) 54
  • 55. Vantagens API mais fáceis e compreensíveis no uso Possibilidade de se entregar a closure pronta para uso Facilidade de se estender (novas closures) Valores default já pré-con gurados Criação de uent-API com encadeamento de closures Decorator pattern com baixa complexidade Desvantagens Mutabilidade da estrutura de con guração Maior quantidade de código Maior demanda cognitiva Mudança de paradigma para criação soluções The right tool for the right job 55
  • 56. High-order functions como ferramenta 56
  • 57. Muito obrigado! Conteúdo slides: https://zamariola.com.br/slides/devcamp2019 exemplos: https://github.com/zamariola Referências https://commandcenter.blogspot.com/2014/01/self-referential-functions-and- design.html https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis https://www.youtube.com/watch?v=5IKcPMJXkKs https://dave.cheney.net/2016/11/13/do-not-fear- rst-class-functions https://www.calhoun.io/using-functional-options-instead-of-method-chaining-in-go/ 57