Slide 1

Slide 1 text

FREESTYLE FREESTYLE A COHESIVE & PRAGMATIC FRAMEWORK OF FP CENTRIC SCALA LIBRARIES 1

Slide 2

Slide 2 text

Getting into typed FP is hard because Getting into typed FP is hard because No previous CT knowledge or math foundations Leaving styles one is used to (i.e. OOP) Rapid changing ecosystem 2

Slide 3

Slide 3 text

Freestyle's Goals Freestyle's Goals Approachable to newcomers Stack-safe Dead simple integrations with Scala's library ecosystem Help you build pure FP apps, libs & micro- services 3

Slide 4

Slide 4 text

In this talk In this talk Freestyle programming style RPC based Microservices gRPC Freestyle RPC 4

Slide 5

Slide 5 text

Freestyle's Workflow Freestyle's Workflow Declare your algebras Compose your programs Provide implicit implementations of each algebra Run your programs at the edge of the world 5

Slide 6

Slide 6 text

Freestyle's Workflow Freestyle's Workflow Declare your algebras @tagless(true) trait ArithmeticService[F[_]] { def add(value1: Int, value2: Int): F[Int] def subtract(value1: Int, value2: Int): F[Int] def multiply(value1: Int, value2: Int): F[Int] def divide(value1: Int, value2: Int): F[Int] } @tagless(true) trait ValidateService[F[_]] { def isPositive(value: Int): F[Boolean] def isZero(value: Int): F[Boolean] } 6

Slide 7

Slide 7 text

Freestyle's Workflow Freestyle's Workflow Declare and compose programs class ArithmeticProgram[F[_] : ArithmeticService : ValidateService]( implicit ME: MonadError[F, Throwable]) { def program(value1: Int, value2: Int, value3: Int): F[Int] = for { result1 <- ArithmeticService[F].subtract(value1, value2) isZero <- ValidateService[F].isZero(result1) result2 <- if (isZero) ME.raiseError(new RuntimeException("Division by zero!")) else ArithmeticService[F].divide(value3, result1) } yield result2 } 7

Slide 8

Slide 8 text

Freestyle's Workflow Freestyle's Workflow Provide implicit evidence of your handlers class ArithmeticServiceHandler[F[_]]( implicit ME: MonadError[F, Throwable]) extends ArithmeticService[F] { override def add(value1: Int, value2: Int): F[Int] = (value1 + value2).pure[F] override def subtract(value1: Int, value2: Int): F[Int] = (value1 - value2).pure[F] override def multiply(value1: Int, value2: Int): F[Int] = (value1 * value2).pure[F] override def divide(value1: Int, value2: Int): F[Int] = (value1 / value2).pure[F] } class ValidateServiceHandler[F[_]]( implicit ME: MonadError[F, Throwable]) extends ValidateService[F] { override def isPositive(value: Int): F[Boolean] = (value > 0).pure[F] override def isZero(value: Int): F[Boolean] = (value == 0).pure[F] } 8

Slide 9

Slide 9 text

Freestyle's Workflow Freestyle's Workflow Run your program to your desired target object ArithmeticDemo extends App { type Target[A] = Either[Throwable, A] implicit val arithmeticServiceForTarget: ArithmeticServiceHandler[Target] = new ArithmeticServiceHandler[Target] implicit val validateServiceForTarget: ValidateServiceHandler[Target] = new ValidateServiceHandler[Target] new ArithmeticProgram[Target].program(4, 2, 6) // res0: Either[Throwable, Int] = Right(3) new ArithmeticProgram[Target].program(3, 3, 10) // res1: Either[Throwable, Int] = Left(java.lang.RuntimeException: Division by zero!) } 9

Slide 10

Slide 10 text

RPC based Microservices RPC based Microservices 10

Slide 11

Slide 11 text

What is RPC (Remote Procedure Call) What is RPC (Remote Procedure Call) Allow call methods in a remote app server as local Scala Service Scala client 11

Slide 12

Slide 12 text

gRPC gRPC open source high performance RPC framework Idiomatic client libraries in several languages Bi-directional streaming with http/2 based transport 12

Slide 13

Slide 13 text

gRPC gRPC Main usage scenarios Connecting polyglot services in microservice- based architecture Connecting mobile devices to backend services 13

Slide 14

Slide 14 text

gRPC gRPC Uses protocol buffers by default to: Define IDL: service interfaces and structure of message Serialize/deserialize structure data 14

Slide 15

Slide 15 text

gRPC gRPC Define your proto message message Person { required string name = 1; required int32 id = 2; optional string email = 3; } 15

Slide 16

Slide 16 text

gRPC gRPC Define your gRPC service service Greeter { rpc SayHello (HelloRequest) returns (HelloReply); } message HelloRequest { string name = 1; } message HelloReply { string message = 1; } 16

Slide 17

Slide 17 text

Freestyle RPC Freestyle RPC frees-rpc is a FP layer atop gRPC Messages and services defined in Scala files 17

Slide 18

Slide 18 text

Freestyle RPC Freestyle RPC Define your message @message case class Person(name: String, id: Int, email: String) 18

Slide 19

Slide 19 text

Freestyle RPC Freestyle RPC Expose Algebras as RPC services @message case class HelloRequest(name: String) @message case class HelloReply(message: String) @service trait Greeter[F[_]] { @rpc(Avro) def sayHello(request: HelloRequest): F[HelloReply] } 19

Slide 20

Slide 20 text

Freestyle RPC gives you for free: Freestyle RPC gives you for free: Scala Service Scala client gRPC based server gRPC based client IDL files to interoperate with other langs. 20

Slide 21

Slide 21 text

Frestyle RPC Frestyle RPC IDL generation idlGen: sbt plugin Generation of IDL files from Scala definition Generation of source files from IDL 21

Slide 22

Slide 22 text

Frestyle RPC Frestyle RPC Generation of IDL files from code @message case class HelloRequest(greeting: String) @message case class HelloResponse(reply: String) @service trait Greeter[F[_]] { @rpc(Protobuf) def sayHello(request: HelloRequest): F[HelloResponse] @rpc(Avro) def sayHelloAvro(request: HelloRequest): F[HelloResponse] @rpc(Protobuf) @stream[ResponseStreaming.type] def lotsOfReplies(request: HelloRequest): Observable[HelloResponse] } syntax = "proto3"; option java_multiple_files = true; option java_outer_class_name = "Quickstart"; package quickstart; message HelloRequest { string greeting = 1; } message HelloResponse { string reply = 1; } service Greeter { rpc SayHello (HelloRequest) returns (HelloResponse); rpc LotsOfReplies (HelloRequest) returns (stream HelloResponse); } 22

Slide 23

Slide 23 text

Frestyle RPC Frestyle RPC Generation of IDL files from code @message case class HelloRequest(greeting: String) @message case class HelloResponse(reply: String) @service trait Greeter[F[_]] { @rpc(Protobuf) def sayHello(request: HelloRequest): F[HelloResponse] @rpc(Avro) def sayHelloAvro(request: HelloRequest): F[HelloResponse] @rpc(Protobuf) @stream[ResponseStreaming.type] def lotsOfReplies(request: HelloRequest): Observable[HelloResponse] } { "namespace" : "quickstart", "protocol" : "GreeterService", "types" : [{ "name" : "HelloRequest", "type" : "record", "fields" : [{ "name" : "greeting", "type" : "string" }] }, { "name" : "HelloResponse", "type" : "record", "fields" : [{ "name" : "reply", "type" : "string" }] }], "messages" : { "sayHelloAvro" : { "request" : [{ "name" : "arg", "type" : "HelloRequest" } ], "response" : "HelloResponse" } } } 23

Slide 24

Slide 24 text

Frestyle RPC Frestyle RPC Generation of source files from IDL Currently only Avro is supported Scala code from RPC services defined previously Prevents binary incompatibility 24

Slide 25

Slide 25 text

Frestyle RPC example Frestyle RPC example 25

Slide 26

Slide 26 text

Service definition Service definition @message case class Point(latitude: Int, longitude: Int) @message case class Rectangle(lo: Point, hi: Point) @message case class Feature(name: String, location: Point) @message case class RouteNote(location: Point, message: String) @message case class RouteSummary(points: List[Point], features: List[Feature], distance: Int) @service trait RouteGuideService[F[_]] { @rpc(Protobuf) def getFeature(point: Point): F[Feature] @rpc(Protobuf) @stream[ResponseStreaming.type] def listFeatures(rectangle: Rectangle): Observable[Feature] @rpc(Protobuf) @stream[RequestStreaming.type] def recordRoute(points: Observable[Point]): F[RouteSummary] @rpc(Protobuf) @stream[BidirectionalStreaming.type] def routeChat(routeNotes: Observable[RouteNote]): Observable[RouteNote] } 26

Slide 27

Slide 27 text

Service implementation Service implementation class RouteGuideServiceHandler[F[_] : Async](implicit S: Scheduler) extends RouteGuideService[F] { override def getFeature(point: Point): F[Feature] = featureDatabase.getFeature(point).fold( Async[F].raiseError[Feature](new RuntimeException("Feature not found")))(Async[F].pure) override def listFeatures(rectangle: Rectangle): Observable[Feature] = Observable.fromIterable(featureDatabase.listFeatures(rectangle)) override def recordRoute(points: Observable[Point]): F[RouteSummary] = points.foldLeftL((List.empty[Point], List.empty[Feature])) { case ((visitedPoints, visitedFeatures), point) => val feature = featureDatabase.getFeature(point) (visitedPoints :+ point, visitedFeatures ++ feature.toList) } .map(summaryFromPointsAndFeatures.tupled.apply) .to[F] override def routeChat(routeNotes: Observable[RouteNote]): Observable[RouteNote] = routeNotes .flatMap { note: RouteNote => routeNoteDatabase.insertRouteNote(note) Observable.fromIterable(routeNoteDatabase.listRouteNotes(note.location)) } } 27

Slide 28

Slide 28 text

Building the server Building the server trait CommonRuntime { implicit val S: Scheduler = monix.execution.Scheduler.Implicits.global } object gserver { trait Implicits extends CommonRuntime { implicit val routeGuideServiceHandler: RouteGuideService[IO] = new RouteGuideServiceHandler[IO] val rpcConfig: List[GrpcConfig] = List( AddService(RouteGuideService.bindService[IO]) ) implicit val serverW: ServerW = BuildServerFromConfig[IO]("rpc.server.port", rpcConfig).unsafeRunSync() } object implicits extends Implicits } 28

Slide 29

Slide 29 text

Running the server Running the server object ServerApp extends App { import gserver.implicits._ server[IO].unsafeRunSync() } 29

Slide 30

Slide 30 text

Building the client Building the client object gclient { trait Implicits extends CommonRuntime with ClientConfig { implicit val routeGuideServiceClient: RouteGuideService.Client[Task] = RouteGuideService.client[Task](channelFor) } object implicits extends Implicits } 30

Slide 31

Slide 31 text

Running the client Running the client object ClientApp extends App { import gclient.implicits._ val logger = getLogger def processFeatures(features: Observable[Feature]): Task[Unit] = features .zipWithIndex .map { case (feature, i) => logger.info(s"Result #$i: $feature") } .completedL Await.result( processFeatures( routeGuideServiceClient.listFeatures( Rectangle(Point(400000000, -750000000), Point(420000000, -730000000)))).runAsync, Duration.Inf ) } 31

Slide 32

Slide 32 text

Frestyle RPC Frestyle RPC Other supported features Compression SSL/TLS encryption Metrics reporting 32

Slide 33

Slide 33 text

Inspired by Inspired by Cats Scalaz ΛRROW Eff Fetch Simulacrum 33

Slide 34

Slide 34 text

Brought to you by Brought to you by [colin-passiv](https://github.com/colin-passiv) Adrián Ramírez Fornell <[AdrianRaFo](https://github.com/AdrianRaFo)> Alejandro Gómez <[dialelo](https://github.com/dialelo)> Ana Mª Marquez <[anamariamv](https://github.com/anamariamv)> Andy Scott <[andyscott](https://github.com/andyscott)> Diego Esteban Alonso Blas <[diesalbla](https://github.com/diesalbla)> Domingo Valera <[dominv](https://github.com/dominv)> Fede Fernández <[fedefernandez](https://github.com/fedefernandez)> Francisco Diaz <[franciscodr](https://github.com/franciscodr)> Giovanni Ruggiero <[gruggiero](https://github.com/gruggiero)> Javi Pacheco <[javipacheco](https://github.com/javipacheco)> Javier de Silóniz Sandino <[jdesiloniz](https://github.com/jdesiloniz)> Jisoo Park <[guersam](https://github.com/guersam)> Jorge Galindo <[jorgegalindocruces](https://github.com/jorgegalindocruces)> Juan Pedro Moreno <[juanpedromoreno](https://github.com/juanpedromoreno)> Juan Ramón González <[jrgonzalezg](https://github.com/jrgonzalezg)> Lawrence Lavigne <[L-Lavigne](https://github.com/L-Lavigne)> Maureen Elsberry <[MaureenElsberry](https://github.com/MaureenElsberry)> Peter Neyens <[peterneyens](https://github.com/peterneyens)> Raúl Raja Martínez <[raulraja](https://github.com/raulraja)> Sam Halliday <[fommil](https://github.com/fommil)> Suhas Gaddam <[suhasgaddam](https://github.com/suhasgaddam)> ... and many more contributors 34

Slide 35

Slide 35 text

Thanks! Thanks! http: frees.io https: github.com/frees-io/freestyle- rpc/tree/master/modules/examples 35 @francisco_dr @47deg frees.io