Devreal

Play Framework Constructs: Func-tastic ways of Slicing and Dicing Play

Event: Scala by the Bay

SBTB 2014, Hiren Hiranandani: Play Framework Constructs: Func-tastic ways of Slicing and Dicing Play

Recording: SBTB 2014, Hiren Hiranandani: Play Framework Constructs: Func-tastic ways of Slicing and Dicing Play

thank you how's everyone doing so to start my presentation is available on github it's publicly hosted I don't I think I made some edits that haven't been posted yet but i'll post those so if you go to that URL if there's anything you can't see here you can check it out on the web so to start can you read that code at all okay let me try how's that better okay alright so I'm hurrain I started playing with computers when I played quake I got pretty good and then i discovered i want to write code learn how to build some of this awesome code that i see and play with and interact with every day so i started with turbo c++ that's what we used in high school and then I discovered this steaming cup of what I thought was pretty awesome until I got into the professional world and I felt like that you know then somebody showed me Haskell and I learned about Scala and I felt more like the spider so after that I became a scholar guy got really interested in Scala started building almost all of my stuff in Scala there were great libraries and frameworks available for you to use but it was still kind of difficult to get adoption you know people weren't really interested in what I had to say then I started working for bold radius and it's a scholar consultancy and we do typesafe training I'm typesafe certified we also write custom scholar training programs so if you have specific needs we can help serve those needs I do code review mentoring and also development for all of my clients and so now it's more like this so the purpose of this talk is to discuss some interesting constructs that I've discovered along the way that I feel might help you in using play and getting more out of it so quick poll how many of you guys feel like you're a one out of three on functional programming raise your hands how about a two out of three how about a three out of three okay all right so I'll try to keep it not too complicated trust me I'm a two out of three so we're good so I'll try to keep the history lesson as short as possible so back in the day we had web frameworks they were MVC they were all kind of interesting but they had some problems almost all of them had like rails and Django they had no type safety MVC was painful to use and had a lot of boilerplate and then came Scala and scholars a cool language and i discovered lift lift was the first real full stack web framework for scala and it was novel in kind of quite a few ways there was a lot that it could do that was kind of different from the way other web frameworks worked and it embraced functional programming at a very deep level but it had a lot of problems because when you started using it you ended up with a lot of spaghetti code and of course the community support was not fantastic so almost every time you were writing a play application you found yourself building little frameworks in order to make the dirty parts of lift not suck so then play grew up and I found that it was a really nice mix of 00 and FP it took good advantage of some of the lessons that were learned from previous web frameworks high quality templating typesafe you know following the MVC model but also open to being used in different ways there was also a fantastic JSON support with one line of code you can get conversion to JSON incremental compilation and kind of like interactive development cycle and great tools other than that as well and it's also from an architectural perspective asynchronous from the bottom so it's based on futures it uses net under the hood has a lot of really solid underpinnings and that's why you don't deploy it into a container you just run the distributive the distributable that played generates for you so I found in the end that this is one of the first web frameworks that I found uses the Scala features in the right way and that's like peanut butter and jelly right so a quick tour of play to get started you download activator from the typesafe website and activator is kind of the replacement for the play command or even parts of SBT so you add it to your path and then you run this program called activator and you give it the new so this is a little screen cast of me doing this and so I ran play new or I'm sorry activator new chose the place Scala template name to my project the demo and CD into the directory and run my activator run and so at this point I have a fully functioning web server running on my system that's four commands including a CD and you know some inputs so now it's kind of downloading some of the dependencies that are part of the projects and this is with my cash being kind of hot so the first time around it does really download quite a bit of stuff but afterwards you don't really have to pay that cost and so now my server is running tab over to my web browser hit refresh and in a few seconds I should have a fully running web page there we go and so now i can ship what's also nice is you can do live coding so you can work on your code and hit refresh in the browser and everything gets recompiled and works just fine so first let's take a look at the structure of the project you have some shell scripts a bunch of directories that contain the different parts very rails style you have an app directory with assets controllers and views you have a conf directory you have a project directory that's basically your build stuff your application configuration can vary if you like it to you can have different configurations for different environments your routes is basically how you get from a URL to controller so everything here is type safe and I'll kind of go into some more of the details but here I'm going to edit one of the views real quick and change the title of the page to say welcome to the demo and then I'm going to cut over to the browser cut over to the browser and refresh my page and you can see at the top it says welcome to the demo if you can read that so the way this is built is you have so let's use kind of a search component as an example so the way this works is you have a routes file which says when you get this URL with a term included call the search controller and give it the term as a string so this particular line gets compiled by the play tooling and it discovers that you have a search controller which also has a search method that takes a term which is a string so this connection is made in a type safe manner so you calculate the search results and you present them to a view called view dot search results and you give it the results there's a little repetition here but I think you guys get the gist you can also do the same thing with futures since play is built from the ground up with futures when you perform your action you can return it all as a future and play does all of the orchestration for you to get to a fully rendered view and so this is what our view looks like this is just a very very simplistic example this would get put into some bigger template or have lots of classes and ID's on it so out of the box you get a fully configured build you get a functioning Scala project so you can pull in libraries from elsewhere you can use your Java code comes with tests and lots of tests harnesses for you to write your own tests and kind of orchestrate organization-wide standards for testing and things like that comes with great tools SBT is significantly pimped out by play and then you also have activator idea and activator eclipse that will generate your project files for you to interact with your ID and so play equals win so now let's talk a little bit about something called the Monad it's a scary word in the functional programming community at least in Scala and a lot of people find it unapproachable so there's this running commentary about the category theory definition of a monad which I don't consider myself able to understand that however a monad is really a container inside of which when you run computations they take on a very specific semantics so i'll talk about three specific monads here and then we'll get kind of deeper into the talk and i'll introduce some more so the first monad which i think almost all of you are going to be familiar with is the option monad so the way option works is it makes it so that you don't have to check for null all the time so if i have a person and that's successfully gotten i want to ask for the father's mother sister of that person all of those can be null or some value and so the for comprehension here is simply doing that but under the hood the null is being handled for me so if at any point I get an oh I eject from the computation and I yield nothing similarly there's a try my dad the try monad does the same thing but with failure so in this particular example i'm not going to dive into the details you guys are welcome to check out the slides later there are five points at which you can have failure and at each of those points if there is a failure this for comprehension aborts provides a failure and the Combinator the Combinator down here or the or else execute the the thing on the right-hand side and so basically it means if i don't get any good input and i can't divide the two numbers try again similarly we have a future monad which is something that allows us to run computations asynchronously basically anything that you ask the future monad to do happens on a thread pool of your control if you like and so here I'm trying to get a user I need a user to get my cart friends and affiliations and so I can fire off those processes in parallel and put together the results in my response and that is also pretty awesome so now let's talk a little bit about how play can be tweaked a little bit to be more functional and to be more compositional right so the goal of this presentation is to encourage composition and the creation of small pieces such that when the time comes all I have to do is swap out a piece and I can change the way my system works without paying the cost of changing all of this code so by default we have this search method i removed the future stuff for now but if we want to build a composition for this we can build a trait called the functional controller which knows about some default failure semantics and the way that I build my actions for my Play Framework so I can try the logic I can write a method called action that takes logic and the renderer effectively separating the presentation from the business logic taking in the business logic executing that then mapping over that to the renderer my renderer will then either fail either of those steps can fail or succeed and depending on if there's a failure or success I either generate a view or I generate some sort of failure view that maps to the problem that I had and again this there's there's some pseudocode in here just to make things simpler I didn't want to have like explosive code and effectively this is kind of like framework components I guess you're allowed to be a little bit more verbose here so this is what the usage looks like so now I have a search that takes a term which is an action whose logic is the search and whose renderer is the view for the search now what's nice about this is I can take it a step further I can use functional programming tools on my view and take apart my view as I have a core renderer which renders just the component that I care about and then I have a layout which is a function from HTML to HTML which takes that HTML and maybe wraps it or does some parsing or enhancement to it whatever it does and the same semantic applies here try the logic run the run the view over it and if there's a success provide the response otherwise fail in some reasonable way so now you can take that concept a step further let's say I have a really complicated layout I know I kind of took a big leap between the two slides but let's say we have a layout that has all these active components each of those components take time to render so what i can do is render them in parallel so i'll have a map you might want to use like a case class for this or whatever but the map is just to communicate the fact that you have a set of things all of which render HTML and they all have different binds so I can do some transformation to turn that into a map of string and at this point all I do is I map it over my layout function which takes a series of HTML mapped to erm so I string map to HTML and injects those into my UI at the right points and so now i have a function from HTML to HTML again which i can just inject my core view into and assuming that my action now supports futures i can take my widgets pull the layout out that takes the widgets and the default layout and now i can present a function that just takes the layout and wraps the view that I care about and then I can run my search by saying layout over my search result view and so now all the active components get rendered in parallel the search result view gets rendered as well and all of that stuff just happens to that of the future context so you now you get free parallelism and again the specific abstractions i'm using here are not the obstructions you may necessarily want to use but they're just kind of kernels of ideas that you can take forward in the direction that suits your particular effort and that of course makes you want to dance right so service is a function is something that mary has talked about a little bit and this is kind of very much in the same vein so I'll speed through this a little bit more I'm going to use a slightly different terminology but the gist of it is very much the same so you have a service that is into out which means a function from into future about then you have a map which given a pre-existing service and some new type of input I can produce a new type of output so imagine I take in JSON I run a service that works on my business objects and I produce JSON right so think of this as the map then I have a filter which is basically a mapping that does not convert any types so let's define kind of a mental model for this this is a really ghetto image I know but it's really meant to just show you the gist of how to think about this request comes in from the left hand side you have a filter let's say that record some stuff or does some magic then you have some sort of conversion step which is a map then you have another filter then you have some more conversion steps then you have another filter and then you have kind of your business logic at the end and the cycle is and it's performed in Reverse on the way out so think about it in terms of i'm writing a restful service so i take HTTP requests in that turns into json that turns into my business object i run my business logic and the reverse happens on the way out right so you produce those slices as you see fit once and they're usable by everybody so you don't have all this extra boilerplate for JSON conversions or any other unnecessary pain so let's real quick just see how these things compose so there's a way you can take a map or filter and given some inner service produce the outer service so the map takes the new type of input and the old service and produces the new type of output right so simply I can partially apply my map and I get the outer function and the way this works is I can build a filter of almost any kind so the first filter I thought about building is a timer so I record the start time run my service and when my service is complete I go and call some service to record my time and then I provide the result and all of this is done in parallel so the recording of time happens in parallel to whatever else is downstream and passed after my service returns the value out so another good example of a filter this is something I use actively when I build services is the awesome filter now the awesome filter relies on this notion that you can combine filters together and basically generate a service that looks identical to the service that's all the way on the inside but you can do so with a mutable set of filters so I can have this awesome filter wrap a mutable set of filters and whenever I want I can add a new filter or let's say remove even I just have adhered and when I apply my service I just fold over all those filters wrapping the functions one inside of another and then I get a function all the way on the outside that looks like my other service and so the great thing about this is i can write a web UI that given a name of a filter or a name of an awesome filter i can target that and say okay i want to introduce this new shim because i'm writing this code right now i want to be able to see the input and output all the time or i want to add a timer because i'm doing performance testing on this particular slice of the program and that's again a good reason to dance so your application can also be viewed as a function just like your services can be viewed as viewed as a function your application is essentially something that produces a service that then runs inside of the context of your process so your application is a mapping from configuration to some service given a set of dependencies I can go from configuration sorry assuming that we have this concept of dependencies which requires configuration to be built which let's say we have database and a system that provides like the time service and system.out.print service and whatever other various stuff that you might need you have something that takes the current configuration you have something that allows you to build the service from dependencies and of course you already have a way to go from configurations to dependencies so I can take my dependencies build them out of a configuration and then pass the result onto my service builder and build a service so the connection between configuration and services now made so now my service is simply given a configuration I'm going to build my service and so whenever I run my action again this can be mixed in with the other idea that I presented before of partitioning business logic and rendering logic so now my action is simply invoke the service now the service will change depending on the configuration changing and again I can do this using push I can do this using you know pulling the configuration there's lots of ways in which I can do this I can add a caching layer so I don't have to keep regenerating my service and my dependencies all the time so let's revisit the concept of the Monad a little bit and talk a little bit about the reader monad so the reader monad is almost identical or analogous to a function what's nice about it though is it's slightly different in that it's intended for the purpose of defining a common context like configuration or dependencies and using that context of something to build multiple behaviors off of and having ways to compose those behaviors together in reasonable and useful ways and again this combines very nicely with futures which I tried to do a little bit in the presentation but it's not something that's easy to communicate and like this so let's imagine we have some sort of reader like this and you have a map where the output of the reader becomes the input of the mapping function you have a flat map where rather than producing a B you produce a reader of some stuff and B and you also have like a zip with which is similar to a lift to where you can say I take in to readers and I produce a new reader and so this is a great place to do something like dependencies so given a reader of configuration that produces my DB and a reader of configuration that produces my system I can put those two together using a dependency constructor that takes both of those and so now I have a reader of config to dependency right and so you can kind of create these pipelines that interact with one another all of which share a common context at the end so let's kind of rear out rewrite how we built our application and this is kind of the simple part given a configuration and a way to build a service I now use the reader monad to pull my dependency or two to connect configuration to dependency and then I do the same thing to connect the dependency to my service and given a configuration when I run my monad i get a service that i can then we use so this is identical to the function so why do I care well what's cool is you can use this to further partition the logic as we had done before with the action so I can take my servicer which is the business logic and my presenter which is the presentation logic and I can build them both as reader monads and then zip them together so assuming that i have this a little bit of glue that allows me to connect the two services together and again i don't want to get into the nitty-gritty of that code but it basically it says take the output of this and give it to be l1 i can build a service that takes the two and combines them together into a pipeline that i can then later on swap elements out of so if i wanted my presentation logic to no longer be about you know HTML i could make it about restful services and for that you can think the reader monette you can't really do that with a raw function because that abstraction is not really suited to this you can do it but it's not what the abstraction really means and so reader is definitely one of the simplest of all the monads it's just made very complicated because it's not one of the first ones you visit and it also has the environment involved but it's really simple really easy to build all those methods that I showed you in the first slide with the reader monad are all methods that you can build yourself and that's again a reason to dance so in addition to some of the software components that you're able to use to build your actual business code there's lots of useful tools that surround that code that make it possible for you to reduce boilerplate so keep in mind that SBT is a scholar program your SBT build is a scholar program so you can put that concept to work by removing boilerplate through code generation through you know introducing libraries that allow you to connect dots between things so for example a lot of what play does for example the routes compilation the template compilation and the making sure of the type safe reverse routing and there's all all all kinds of excellent tools that are built into play all of which are provided through SBT SBT runs a bunch of stuff for you generates a bunch of metadata and that metadata is used to connect the dots between Model View and controller in addition you have SBT boilerplate so if you're working with pure functions it allows you to connect tuples of different arity two functions of different era te and of course writing an embedded dsl is very easy you can also write your own language using partial Combinator's and that's also pretty easy and of course you have macros so if all else fails you can write a macro for something so the main tenets of the talk are try to simplify as best as you can keep things small and understandable and consider the cognate load that's required to understand the components of your software so rather than making the logic complicated make the glue complicated which this is not actually all that complicated but it allows you to isolate things and create gateways between parts of your software that make sure that what passes through that gateway makes sense also do your best to isolate things right like I talked about the Gateway on the left hand side I have stuff on the right hand side I have stuff each of those things have different and well-defined purposes and try to do exactly one thing in almost every component that you have and think of almost all of your software as an exercise in composition right this functional programming stuff I'm showing you is not just for play it's for everything services a function is something you can use to solve almost all your problems well rephrase functional programming components like this are ways to solve many kinds of problems and try to cut along the dimensions that matter to you so if you're talking about a web service one of the dimensions that matters is the URL if you're talking about you know other dimensions cross-cutting concerns like logging performance metrics reporting tools those are all ways in which you can slice your box of software and create reusable components that can kind of fill an entire layer but only require one person or one attempt at writing that code and try to build a mental model a mental model is an extremely useful way to reason about how you want to partition a lot of your software and if the mental model makes sense to you and to your peers it's something that hopefully can live for a long time and you can write code that you know as Chad Fowler put it isn't called legacy code the way we understand it but it's called legacy code because you actually left behind a good legacy all right that's the end you