diff --git a/slides/README.md b/slides/README.md new file mode 100644 index 0000000..f1ad91f --- /dev/null +++ b/slides/README.md @@ -0,0 +1,247 @@ +# [fit] Protobuf & Code Generation + +### 2016, by Manfred Touron (@moul) + +--- + +# overview + +* go-kit is an amazing framework to develop strong micro services +* but it requires a lot of boilerplate code +* return on experience on go-kit boilerplate code generation + +--- + +# protobuf? + +* limited to exchanges (methods and models) +* extendable with plugins +* contract-based +* universal + +--- + +# code generation? + +* the good old ./generate.sh bash script +* go:generate +* make +* protobuf + [protoc-gen-gotemplate](https://github.com/moul/protoc-gen-gotemplate) + +--- + +# go-kit + +* protobuf-first, rpc-first service framework in Golang +* abstract services, endpoints, transports +* requires a lot of boilerplate code in multiple packages + +--- + +# example: `session.proto` + +```protobuf +syntax = "proto3"; +package session; + +service SessionService { + rpc Login(LoginRequest) returns (LoginResponse) {} +} + +message LoginRequest { + string username = 1; + string password = 2; +} + +message LoginResponse { + string token = 1; + string err_msg = 2; +} +``` + +--- + +# example: `session.go` + +```go +package sessionsvc + +import ( + "fmt" + "golang.org/x/net/context" + pb "github.com/moul/protoc-gen-gotemplate/examples/go-kit/services/session/gen/pb" +) + +type Service struct{} + +func New() pb.SessionServiceServer { + return &Service{} +} + +func (svc *Service) Login(ctx context.Context, in *pb.LoginRequest) (*pb.LoginResponse, error) { + // custon code here + return nil, fmt.Errorf("not implemented") +} +``` + +--- + +##### example: `{{.File.Package}}/gen/transports/http/http.go.tmpl` + +```go +// source: templates/{{.File.Package}}/gen/transports/http/http.go.tmpl +package {{.File.Package}}_httptransport +import ( + gokit_endpoint "github.com/go-kit/kit/endpoint" + httptransport "github.com/go-kit/kit/transport/http" + endpoints "github.com/moul/protoc-gen-gotemplate/examples/go-kit/services/{{.File.Package}}/gen/endpoints" + pb "github.com/moul/protoc-gen-gotemplate/examples/go-kit/services/{{.File.Package}}/gen/pb" +) +``` + +```go +// result: services/user/gen/transports/http/http.go +package user_httptransport +import ( + gokit_endpoint "github.com/go-kit/kit/endpoint" + httptransport "github.com/go-kit/kit/transport/http" + endpoints "github.com/moul/protoc-gen-gotemplate/examples/go-kit/services/user/gen/endpoints" + pb "github.com/moul/protoc-gen-gotemplate/examples/go-kit/services/user/gen/pb" +) +``` + +--- + +##### example: `{{.File.Package}}/gen/transports/http/http.go.tmpl` + +```go +// source: templates/{{.File.Package}}/gen/transports/http/http.go.tmpl +{{range .Service.Method}} +func Make{{.Name}}Handler(ctx context.Context, svc pb.{{$file.Package | title}}ServiceServer, endpoint gokit_endpoint.Endpoint) *httptransport.Server { + return httptransport.NewServer( + ctx, + endpoint, + decode{{.Name}}Request, + encode{{.Name}}Response, + []httptransport.ServerOption{}..., + ) +} +{{end}} +``` + +```go +// result: services/user/gen/transports/http/http.go +func MakeGetUserHandler(ctx context.Context, svc pb.UserServiceServer, endpoint gokit_endpoint.Endpoint) *httptransport.Server { + return httptransport.NewServer( + ctx, + endpoint, + decodeGetUserRequest, + encodeGetUserResponse, + []httptransport.ServerOption{}..., + ) +} +``` + +--- + +##### example: `{{.File.Package}}/gen/transports/http/http.go.tmpl` + +```go +// source: templates/{{.File.Package}}/gen/transports/http/http.go.tmpl +func RegisterHandlers(ctx context.Context, svc pb.{{$file.Package | title}}ServiceServer, mux *http.ServeMux, endpoints endpoints.Endpoints) error { + {{range .Service.Method}} + log.Println("new HTTP endpoint: \"/{{.Name}}\" (service={{$file.Package | title}})") + mux.Handle("/{{.Name}}", Make{{.Name}}Handler(ctx, svc, endpoints.{{.Name}}Endpoint)) + {{end}} + return nil +} +``` + +```go +// result: services/user/gen/transports/http/http.go +func RegisterHandlers(ctx context.Context, svc pb.UserServiceServer, mux *http.ServeMux, endpoints endpoints.Endpoints) error { + + log.Println("new HTTP endpoint: \"/CreateUser\" (service=User)") + mux.Handle("/CreateUser", MakeCreateUserHandler(ctx, svc, endpoints.CreateUserEndpoint)) + + log.Println("new HTTP endpoint: \"/GetUser\" (service=User)") + mux.Handle("/GetUser", MakeGetUserHandler(ctx, svc, endpoints.GetUserEndpoint)) + + return nil +} +``` + +--- + +#### `protoc --gogo_out=plugins=grpc:. ./services/*/*.proto` + +--- + +#### `protoc --gotemplate_out=template_dir=./templates:services ./services/*/*.proto` + +--- + +![fit](assets/session-wc.png) + +--- + +![right fit](assets/wc.png) + +## 3 services +## 6 methods +## 149 custom lines +## 1429 generated lines +## business focus + +--- + +# generation usages + +* go-kit boilerplate (see [examples/go-kit](https://github.com/moul/protoc-gen-gotemplate/tree/master/examples/go-kit)) +* k8s configuration +* Dockerfile +* documentation +* unit-tests +* fun + +--- + +# pros + +* small custom codebase +* templates shipped with code +* hardly typed, no reflects +* genericity +* contrat terms (protobuf) respected +* not limited to a language + +--- + +# cons + +* the author needs to write its own templates +* sometimes difficult to generate valid code +* not enough helpers around the code generation yet + +--- + +# improvement ideas + +* Support protobufs extensions (i.e, annotations.probo) +* Generate one file from multiple services +* Add more helpers around the code generation + +--- + +# conclusion + +* Useful to keep everything standard +* The awesomeness of go-kit without the hassle of writing boilerplate code +* Always up-to-date with the contracts + +--- + +# questions? + +### github.com/moul/protoc-gen-gotemplate +### @moul diff --git a/slides/assets/session-wc.png b/slides/assets/session-wc.png new file mode 100644 index 0000000..f4532d9 Binary files /dev/null and b/slides/assets/session-wc.png differ diff --git a/slides/assets/wc.png b/slides/assets/wc.png new file mode 100644 index 0000000..2b69269 Binary files /dev/null and b/slides/assets/wc.png differ diff --git a/slides/slides.pdf b/slides/slides.pdf new file mode 100644 index 0000000..e629414 Binary files /dev/null and b/slides/slides.pdf differ