Thirteen ways of looking at a Turtle - Scott Wlaschin

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

I'd love to see some new content from Scott. His website is great but I've burned through all the articles and am craving more.

👍︎︎ 2 👤︎︎ u/Kurren123 📅︎︎ Feb 19 2017 🗫︎ replies

that makes it 111% realer for me

👍︎︎ 1 👤︎︎ u/JaimeDean 📅︎︎ Feb 22 2017 🗫︎ replies
Captions
all right well hello everyone this is 13 ways of at a turtle my name is Scott volition I have a website f-sharp fun and profit calm and the slides and the video for this talk will go on the turtle subdirectory at some point I'm going to be using f-sharp to all the code examples but this is really a talk about concepts so most of this stuff will work in other programming languages especially functional programming languages Haskell and Scala and so on all right so most talks are you know on a particular topic and I thought why not take one problem domain and show you lots of different ways of solving the same problem with different techniques so it's like I sort of taste the menu so I'm going to be talking about a lot of functional mostly functional programming techniques partial application functional error handling state monad acts and model cent sourcing dependency injection and so on and so on interpreter capabilities 13 different ways in all and this is a little bit scary because that gives me about four minutes per topic so this is how I feel I've done a similar tool if you actually find this still interesting believe or not I have another talk on functional design patterns same kind of thing lots of lots of stuff very very quickly light I've got I already used up a minute and a half time to get cracking alright so turtle graphics you should be familiar with this with your knots the concert is you have a turtle it's pointing in a particular direction it moves around and as it moves around it draws lines that's basically it so the turtle API that I'm going to work with basically has four functions or four unit operations move a certain distance in a straight line turn some sort of angle left to right put the pen up put the pen down if the pen is down then it's going to draw - the penis off it won't draw and that's basically it so how can we have thirteen different implementations of this particular API let's see let's start with the object or in turtle and I have a little bell here to remind me to keep going fast like object a turtle in an object winter turtle data and the behavior combined into one object of course oo turtle is a tootle and if you didn't know what that is so an early turtle you have a turtle sauce and you have a client that calls it now the turtle needs to keep track of where it is on this canvas it needs to know its position you need to know which angle it's pointing that need to know where the pen is up or down so there's some turtle state associated with this turtle and in the ellow model the turtle state is inside the turtle and it's mutable you can't you don't have access to them as a client so I call the turtle and it updated state I call the turtle again updated state so let's look at the code here is a beginning of a turtle class in F sharp and here's the three different things you need to keep track of the position the angle and the state a couple of things to point out first of all there's a mutable key word so an F sharp things are mutable by default so if you want this to be mutually have to use the mutable key word secondly I'm using this degrees annotation and that's part of the F sharp units of measure and what you can do is you can take a number and annotate it with some sort of measurements like in this case degrees and why did I do that so I didn't get the mixup in radians so you know you want to separate you know kilometres and inches or milliseconds and seconds units and measure ago a of doing that in this case not only does it stop me accidentally passing in radians but it's the documentation so it says you know it's obviously the done passing in degrees they're not radians all right the move method Sotomayor I have a pic of distance I want to move I'm going to log it I'm going to start with the start position I'm going to calculate the new position this distance that this angle started in here that gives me an end position if the pen is take this down I'm going to draw from the start position to the intention and then I'm going to update the state this backward pointing arrow is the assignment operator in F sharp different from equality because the only you only need it when you have mutable because I have to move methods the turn method is very similar I want to turn a vertical angle so I'm going to log it I'm going to calculate a new angle using some sort of formula and then I'm going to update the state with a new angle the pen up things very similar log it's update the state log it's update the state so that's our four methods implemented in an LOC aisle so from the caller's point of view is just really obvious you basically create a turtle you ask you to move a distance you ask it a turn you ask you to move a distance you ask you to turn and so on and so forth and in this case you end up where you started with so you flew on a triangle so let's actually look at some code so this is the F sharp interactive so I'm going to create a canvas for the turtle going to go here's the turtle move a certain distance turn move move again turn move move again and you can see not only is it drawing on the canvas but I'm also outputting the log down here at the bottom so that's just to prove it's the real code it's not just a fake presentation here not like so advantages and disadvantage of our well the advantage really big advantages it's really familiar to most people that's probably the main advantage there's quite a lot of disadvantages to me the biggest disadvantages is its stateful it's a black box it's like I call this thing but I don't get any response it does some stuff but when you know what's doing because I can't see inside it it's hard to test because I have to you know I can't really just like put it in a position I have to like move it to this thing setting up test is hard you can't really compose them if I want to have a - turtle thing I have to create a whole new class which holds two turtles and you know epoxy the methods down and so on and so far in this one we've got some hard-coded dependencies with hard coding the logging technique in the hard coding the canvas now we can get rid of that using dependency injection and I'll talk about that later on ok number two abstract data turtle so this technique goes all the way back to the 70s this is 300 and in this technique the data is separate from the behavior so we have a data structure again it's all the stuff is mutable but the difference is it's a private data structure the only person who only thing that can change this data is the turtle functions so as its annotate from from the coolest one of us and a pig pig of structure and again I have this behavior I have these are now static methods or functions in a module each function now needs the state to be passed in because it's static so this explicit state management and again to use it I create a turtle and I do the same thing as before except each time now I have to pass this turtle in by hands that's the same same idea ok so what are the pros and cons of this technique which is old and low well the advantage is really simple to implement and one of the advantages actually now is that you can't do inheritance so you can't actually use object-oriented techniques so if you think that inheritance is sort of an anti-pattern now and the composition is better than the heritance this technique forces you to use completion so that might be what you want this is I introduced the same as in oh oh it's stateful it's a black box it's hard to set up it started test right next functional turtle so in a functional turtle this state is immutable other than that is very similar to the abstract data turtle um because the state is immutable the client or the caller has to create the state pass the inter function and get a new state back and then get that state pass intersection and get the new state back so the client is now very much involved in managing the state which it wasn't with our methods and the design is very similar we now have an immutable turtle States we don't have to have an immutable keyword anymore and because it's immutable we can make it public it's not a problem if someone accesses these properties because they can't mess them they can't change them the same thing we have these four functions now we pass the state into each function but in addition we return the state so that's the big difference between this one and the one where the state is immutable so this very much is even more explicit now so to use this code we basically start with initial state we'll call it x0 we pass that in and that gives us state 1 sorry state 1 we pass the internet get to state 2 we pass in state 2 and it gives us state 3 and so on and so forth so it's all very explicit it's all very nice but it's kind of ugly you know it's kind of annoying to pass the state around like this is there a way we can make this nicely looking and the answer's yes and that relies on the fact that every in a functional world every turtle every function has one input one output so if we have two functions and we want to chain them together we can take the output of one function and feed it as the input to the next function and that is how composition works and in F sharp we typically use the piping concepts which is their sharpest version of this and this is very similar to UNIX pipes you take the output of command and you feed it as input of the next month so with pipes code would like this start with initial States we pipe it into the MU function we take the output of MU function we pipe it into the turn function set the output the turn function we pipe it into the move function take the out of that and so on and so forth so this vertical bar with angle bracket that is F sharps pipe operator it's not a vertical bar because the political bias is reserved for something else right so what's the pros and cons well because everything is immutable it's a lot easier to reason about I know I know exactly what's going in and what's coming out there's no black box I mean obviously it's doing stuff but I can see what it's doing because I get the state coming out the other end so it's really easy to test this way I can just if I wanted to start in a particular corner I just set the initial state to be in that corner and as we've seen the functions are composable so will it use the glue in the other because they have no global state the downside is that the client has to keep track of the state and again we have these hard-coded dependencies and in a bit I'll talk about how you can do sort of the functional equivalent of a dependency injection next the states monad so what happens if the states if though if the thing is a bit more complicated so let's say we have our turtle and it hits the wall and it can't go any further now we want to return something to the caller that says something went wrong so one way we can do this is just return the actual distance moves as opposed to what you requested you wanted to move 10 units and you actually only moved 5 units so we now need to return for example a pair with a new state and as part of the pair the actual distance moves so here's the usage example we start with initial state we pass that into the move and we get a pair back to the actual distance and then state one if the actual distance is less and what we want is then it fails and we're going to turn the turtle and so on and if the actual distance was correct then the first move succeeded and we try again and we get another actual distance and this is really ugly right I mean it's all very explicit it's all very no clear what's going on but passing the state around is horrible and unfortunately we can't do the piping technique because the output is now this pair it's not the individual state that we can just pass into the next function so how can we keep keep track of the state when we have a situation like this so we've got what we're going to do is we're going to take the turtle function and go through a series of transformations and turn it into something which is more tractable something which is more composable so the total function we have right now has two inputs and two outputs they're one of the inputs is that turtle States and the other input is their runtime input the distance to move or the angles of turn or whatever it is the two outputs one of the outputs is the the new turtle state and the other output is the output of the function the actual distance moved or the actual distance turned or whatever it is so how can we turn this into something we can work with well the first thing is we can turn it into a two step function of the input returns another function so lower than having a two parameter function we have a one parameter function that returns another one parameter function and that's called carrying and that's the fundamental part of functional programming in F sharp you get that for free so in fact the function is automatically like this and if we have this curried model we can actually think of the turtle function as returning a new function so I pass in the distance I want to move and I don't just get a new state I get a new function and so we're going to take this function here like returning another function standard practice that it's kind of ugly we're going to take this function we're going to put a wrapper around it and we're going to call it States all right so the state is really just a wrapper around a function but what we've done now is we have a function with one input and one output and now we can chain these together we can't chain them together directly we can change together using a special technique which are not going to go into if you want to know more about it I have a talk called the monads to talk which is all about the state monad but assuming that we can compose these functions together what we can do is you can create a special thing called a state expression of state computation expression that's this little State thing in in red there and it's kind of like a special block a special code blocks inside the code block the state is been managed behind the scenes so when I write this codes here you know move and then turn move again all that code the state has actually been threaded through that code without me having to do anything so this code looks much nicer it looks like the original code we had looks like imperative code but it's not it's actually stateless immutable code that we had originally made nice-looking by this state expression and we'll see a lot of this in the next couple of slides as well so the state thing fitted to the scenes is a really nice feature now this is a very common technique and most functional programming languages have equivalent of this so Haskell has do notation Scala has for comprehension they're all related to monads the extra up computation expressions are kind of related to monads advantages so it looks like imperative code it looks like is this the state that's actually changing but it isn't it's just immutable behind the scenes but the nice thing is even though it's got this complicated stuff the functions are still composable you can still glue functions together downside much harder to implement kind of and it's tricky to use and practice next no ice our handling so let's say we want to handle errors in a different way let's say when we hit the edge of the wall rather than returning the actual distance we're going to say sorry you made a mistake that's a failure so how can we handle that in a functional way what we want to do is have the function return two different possibilities these are it succeeded or it fails so if it succeeded I get a new turtle state back and if it fails I'm going to return an error message saying you know you went out of bounds or something so how can we model a function that returns two choices so it's not the two values what you know together it's like one or the other one so in F sharp you would model this using a choice type like this and a choice type is kind of like inheritance or the lack of subclassing you basically have two possibilities and they're mutually exclusive it's either a success or its failure if it success there's some information associated with that if it's a failure there's some information such as you've got to and I call these choice types technical word is some types in F sharp they're called discriminated unions they're all pretty much the same thing really really nice feature unfortunately most object language did not have anything like this very very powerful so let's look at how we would implement the move function using this result so we want to move a certain distance so we calculate the new position we draw the line let's do the error handling if the actual distance moves is not what we wanted then we're going to return a failure if it was what we want is we're going to say it's successful and we're going to return the new state the state with the updated the position so again there's two possible choices for the outputs now because there's two possible choices when I actually call this code I have to test and see which one it is so let's look at how that works so there's my initial total state I'm going to move and I'm going to get one of these results so I have to test is it a success or failure and I do that with pattern matching so if it's successful that's great I'm going to try and move again I get another results I'm going to see what's the second result successful failure if it's successful I'm done if it was a failure I've put an error message and then I also need to handle the case where the first one was a failure so again this is all very nice and explicit but it again is kind of ugly to keep track of all these to be testing these special cases all the time can we make it simpler yes so let's avoid some yuckiness and create a new kind of expression this is a result computation expression and again it's a special kind of block which handles all the failure cases so if there's a success it keeps going so like this if the moon was successful it will do this next step and if that was successful it will do the next step and if that successful to do the next up if there is any failures along this line it will basically go to the bottom that kind of bypass all this code and go directly to the you know bottom of the code so very similar to how we do the state the same kind of thing all right there's a result expression so again we've turned something kind of nicely looking into something which is manageable now in this code we still have this states hang we keep passing the state to every single function what we can do is combine we can take the state one and the result one and combine them into a combined expression so we're going to create a result state expression both of them and now when we do this we've got rid of the state as well there's no state in any of this code so this code looks really imperative it looks like just like the object-oriented code really it's like move here move here turn here move here but unlike the objetive object-oriented code there's error handling built in and there's state management built in so there you go that's quite nice so we've got this easily with these computation expressions in F sharp for a very nice way of hiding all this nastiness so what we've got here we've got explicit errors we're not varying exceptions we don't have to look in the documentation to see if it's going to be a failure not for example the pen up and the pen down might not return a failure but the move function we can tell it returns up here because it's going to return this type which is either successful failure but when we write the code it looks like the happy part of code it doesn't look like we've got all this nasty error handling there's nothing about handling exceptions or fly catch or anything it's all it's all handle for me downsize again harder to implement and harder to use I have a whole talk on this topic too which is the railway oriented programming talk which you might have heard of alright next a sink turtle this is like five and a half this is sort of a bonus thing so it's actually thirteen and a half ways of looking at a turtle what happens if the turtle is actually a real low block turtle and you actually are sending you know remote signals to it to get something to happen so the turtle is going to be a sync thing like you're going to have to send a thing and wait for response so how would we handle that well very similar we have an async move now with async equation you do something and then you have to have a callbacks like when it finishes doing what it's that it's going to call you back so it's going to call you back with the new state all right and when it's called me back I'm going to make another move and then when it's finished doing that it's going to call me back with the new States and I'll make another move when it's done we'll call you back for the new state so this is a very common pattern when you have async code when you have another callbacks you get this thing called the Pyramid of doing because it ends up going further and further out how can we make this easier we've got all these nasty callbacks we really don't want to see these are not in our code if we can help it is their way of getting rid of them so this is a tripity tripity yucks callback stuff very nasty yes async expression again we have another computation expression and what this one does is it hides the callbacks behind the scenes so when I write the code I say move async but I don't have to worry there's no callback basically the callback happens automatically and then I move async again and I move away sync again and the ACE again it looks like some normal codes that the async callbacks handle behind the scenes so there's a pattern here we've got the state thing we've got the result things or the async thing they're all the same kind of pattern and that pan is the famous M word like monads so monads is the commonality between these patterns so let's review what we've done so far we're using composition a lot with chaining functions together we haven't created any new objects every time we wanted to do something we've got explicit state management we've got no mutation we've got explicit showing any exceptions all this explicitness is great it makes it really easy to the test it makes it easy to reason about the downside is it looks really ugly but we have techniques to make that easy to work with we can hide these state and the errors and the callbacks behind the scenes using monadic composition these computation expressions alright next okay batch processing now in all examples so far the caller has been managing the state and it's painful basically even even with all these computation expressions it's still painful too many state how can we have it sort of caller avoids managing state altogether well the first technique we'll look at is just a batch processing what we're going to do is create a bunch of commands and send it to a batch processor so from the clients point of view I create a command and I create a whole bunch of lists of kelan's and I send it to the batch runner and the batch runner is going to loop over all the commands and run them in turn each one in turn actually calling the turtle functions and it's part of its loop it's going to be keeping track of the states so the clients no longer have to keep track of the states this batch processor is going to keep track of the state so that's nice from the clients point of view it's much nicer but we have a problem which is these commands our data and our API is not data its functions so how can we turn our API which of these four functions how can we turn this into a data structure that we can send down the wire to the batch process well it's quite simple we use another choice type and basically for each function in the API we create a choice so there's a function called move which has a distance parameter we're going to create a choice case which has a distance thing associated with it the turn is going to have an angle associated with it the pen up doesn't have any data associated with it the pen down doesn't have an inflator associated with it so we now a turtle command which mirrors the the total api except it's pure data this can be serialized and put on the wire so choice pipe to the for the win again so here's the planks and code again here's my list of commands right now these look like function calls that it's actually beta when I say move 100 I'm actually creating a data structure and when I say turn 120 I'm creating a data structure so this is actually a list of data records right I take this list and I send it to the batch processor and it runs more than once so from the clients point of view that's very nice no state anywhere but this it means this thing about being data is really important we'll come back to it later now on the batch runners side it's going to have to execute this data structure and how we're going to do that well very straightforward but each case is going to execute a particular turtle function so for the move case it's going to move the turtle for the angled turn case it's going to turn the turtle and so on and so forth and notice that in the inside it's got this States excusing track of the states all right state is passed in the beginning and it comes out the other end so the the overall implementation for the run is going to say okay start with the initial States for each command in the list of commands you're going to loop through them you're going to execute the command for each one that's going to create a new state and then after you've loop through all the commands you're going to have the final States and that is what you turn back to the caller now this is basically a for loop we'll in these but in f-sharp that you wouldn't actually bother to write this because actually this is built-in function called fold all function languages will have this as part of their library in c-sharp it's the link function link to aggregate very useful I basically would not like your own don't like your own iterations learn to use the collection function switch already built into the library so this is list fold will be seeing fold again shortly all right so what's the advantages and disadvantages of the batch processing well first of all it's completely decoupled because I'm sending data I have absolutely no idea what the implementation is that's really nice that's really decoupled it's a lot easier than working with monads the state is much much easier the downside is spatula entered right I think I'm had to do all the commands at once and the other disadvantage is there's no control flow like if the first command fails I don't I can't choose and say well if it fails I want to do this if it doesn't fail under this it's like here's a bunch of commands it's fire-and-forget and then I just have to take it all or nothing so that's the downside but if you can get away with it that's really nice all right next EXO model so the actor model is quite similar to the batch model except it's sort of like a real-time version of the batch model so in the actor model I have a command exactly the same kind of Kumada years before but this time I'm going to put it on a cue the actor is basically a little message loop that weeds things off the cue processes the commands and then goes back and goes around the loop again so again all the state is kept track of in the actor the client doesn't have to keep track of the state the turtle doesn't keep track of the state the status would have been in between - so let's look at the code so all-access have a loop the link takes the initial turtle state that comes in we also then read a command from the message queue we create a new state how do we create the new state by testing the command if it's a move move move the turtle and so on we run the command the same way we did exactly the same way we did before we get a new state and then the difference is we now take that new state and we feed it back into the top we take the new state and we loop again it's a recursive loop and then that loop will then block waiting for another command on the message queue so the actor model and the batch model are you can share a lot of code between the two models all right so very similar that except you have now this recursive loop which blocks each time two so again from the caller's point of views really easy to use I create a turtle and I post a message now because it's a queue I post the move message opposed to current message I post a move message but unlike the batch model every time I post the message the turtle responds pretty much straight away right so it's not exactly we all find but it's you know it's responsive to what I do I don't have to wait until I've finished all the commands all right so pros and cons of the actor model again very decouples I have no idea what the implementation is I'm just sending it data again simpler than working with a state monad downsides kind of lots of boilerplate associated axes not quite as easy to understand but I think you know if you're managing States as one of my favorite ways of managing state if I have musical state like this next event sourcing rights so events sourcing the diagrams are going to get more more complicated as we go on so we started with with getting past the simple ones on getting more complicated and the eventual thing issue really is how do we persist the states between ones so the accent model is if your program crashes you've just lost everything so we want to persist the states so that if the acts of crashes we can low it we can start off low easy we pick up where we left off or if we want to start up and another server so it goes down we want to run another server we can scale out whether it's nice to persist it so we could just still it straight in a database but one of the things about function program is that you might want to have an immutable database a database that you can't just update you can only append to so if you want to append to something you just it's a different design altogether so what we're going to do is we're going to append to the database to the event store and events and an event is basically he's a diff between before the command and art of command and so I like what changed as a result of running this command so we get a command in from the clan handler and we're going to we have this event still which has a list of previous events we're going to lead the previous events into memory we're going to recreate the state by by applying all these events and now we have the states that it was before the commands we then execute the commands and that actually talks to the turtle and does all the work and then when the command is finished the output of the command is a bunch of a new events and these new events get put back into the event store and so the new events represent what changed between before the commodity model command because again when we get the next command we're going to take these new events and read them up as part that event history to recreate the state so that's basically how events or thing works um so one of the things is what is the difference between a command and an event an event sourcing seems to be a tricky question sometimes but let's actually have a look so here's our turtle command we've got our four different choices here the command is what you want to have happen it might not actually happen I say I want to move here and I want to move the assistance but if I hit the wall it might not work I might not I've actually moved anything I'll you know I might have only moved faster to past as much so just because you want it to happen doesn't mean it actually happens now the event is what actually happens so when I have an event everything's going to be in the past tense I actually moved this distance and I actually turned this angle and I actually move the pen up and down and you can see that the the event is not quite the same as the command I didn't have to be one-to-one correspondence and you can store some extra data here so you know in the command I wanted to move a certain distance but in the moved event I can keep track of what the start position and the end position was as well because that's kind of helpful or I can keep track of not only what the angle I want to discern but what the actual final angle was so this is what actually happened and it's always past tense and again if we compare it with a command we can see it's subtly different so it's the events that we saw in the event stall in the database it's not the commands that's why it's got the event sourcing so there's two important parts of the event sourcing well we've seen how to actually apply a command but let's talk about how do we apply an event we have a historical event we have this particular state and we want to you know that I say the event is sort of a diff between the previous state and the new state so if it's a moved events we say well the state was over here and now the new state is over here if it was a turned events we can say well the original you know the state is now this new final angle and that's one of the reasons we can store this extra data in the state which makes some of this handling much easier notice that we are not calling the turtle okay this is purely an in-memory state changing operation we are not caught there's no i/o it's all pure okay so this is one of the key functions that you need to implement within the bench sourcing model all right no side effects very important nothing happens we're just looping through the things and modifying the state to get back to what it was before the command happens and then to actually handle the command then very simple we load all the events from the event store that gives us our event history we create the state before the command by losing for all the events and applying that apply event thing so that's again with using the list fold codex which is basically the for loop and then now we have the states that it was just before the commands which would have been the same as if it been using actor model something we have the state in memory we apply the command we execute the command that changes the states and it creates some new events and then these new events are then written back into the event stall so again very critical that the when you're rebuilding the state there's no side effects when you're executing them and that's where the side effects happen that's where you actually move move the turtle all right pros and cons of event sourcing again very decouples from implantation stateless what's nice is it supports the replay of events if the business logic changes you have the history of everything that happened to have an audit trail for free many nice features about event sourcing this is why it's sort of trendy right now unfortunately is more complex to manage and when you have like a history you have to kind of keep the integrity of the history so you need to have like versioning of the events the old events might be slightly different from the new events it just becomes a lot trickier than just managing the snapshot of the current state but for many situations it's worth it Mike's next stream processing so steam screen processing is like event sourcing even more but even more so so the diagram is getting even more complicated with the stream processing you basically have these event streams you're going to have a much of event streams coming into you going to pick and choose which events you want to handle some of them are interesting some of them not interesting to you're going to select you're going to do a filter and then once you've got the events that you're interested in you turn them into command you execute the command just like we did and we you know just the same as with the event sourcing thing we've put the data back in the event store and that generates new events right we run the command that generates new events which is manhandled by the next person down the line so this is why it's a stream each little thing is processing a stream events coming in doing some work generating new events and that becomes a stream of events going out for the next person so that's that's the concepts let's look at how it would work with the turtle so one of the things is that you can separate the decision-making process from the state changing process rather than putting everything in the command handler like you would with a basic event sourcing you can say well oh I'm going to do is trigger an event and then you can decide what to do with that event that event might be important to you or I might not be important but I don't get too precise I'll let you decide and that gives you a lot more flexibility so let's say in the turtle situation we're going to have the command Handler and all it does is update the turtle state it just figures out where the turtle is on the canvas but it doesn't actually move the turtle it doesn't log anything how what you do with that information is for the downstream processes to decide so for example we might have an audit processor so every time you do something it's very important that we keep track of every turtle commands because it's a high-security turtle we want to make sure that nobody is messing with it the canvas processor might actually move the turtle around the camera so we might have a physical turtle robot that physically moves the robot let's say we want to keep track of how many miles the turtles moves because we want to keep track of whether the battery's about to run out let's call this a distance processor so three different kinds of business logic all using same event stream as input so let's actually look at some real codes go back to school code here right where are we screen questions okay here's our vent process so the audit processor this is the handler so if it moved we're going to write that message out if it turned we're going to write a message out if it's you know change we're going to wait a message out and then what we're going to do is start with all the other event stream as the input and for each particular event the observable we're just going to call that function so that's our auditing processor give that one out of the way now here's the canvas processor and this one it's only going to draw on the canvas so it doesn't it only needs to care about moves events so I'm going to have a move filter so I'm going to filter out everything other than moved events so again I start with all events but I choose the move events only and then I just handle those by actually drawing on the canvas which is very secure there so let's create one of those and let's do a distance traveled processor so all this one is just going to keep track of how much you want the distances just add it to the total distance so far and then the end is just going to print out the distance traveled so again I'm only interested in moved events so start with all events choose the moved ones only and accumulate the distance and then print it out so let's do that alright so there's our three processes so here's our event stream there's our three screen processes let's open up the canvas let's handle the whoops I need to know what's wrong here I need to cancel this out dragon I think it's wrong there we go so I've moved 100 and then I'm going to turn now notice when I moved 100 I got that audit I also got the distance traveled when I turned I didn't get anything happen except the audit when I move again that I got the audit I got the distance traveled and I also got the canvas changing and I do it again I do it again so now the distance travelled is 300 I've got the audits and I've got the canvas all three going at the same time so there you go it's quite nice and what's what's nice is I'll have a new kind of business logic I can just plug another event processor in downstream I don't have to change the original turtle State processor so it's got decoupling of the business logic which is quite a nice feature so the advantages same as the eventual thing I've got replay history I've got decoupling but the state and the business object can be as separate as you like and you have multiple consumers of the events so this is very micro service friendly basically a lot of people use this kind of architecture of doing micro services this is Vantage's complex it's getting kind of hard to program if you don't need it I wouldn't do this it's just sort of fun toy demo you know use it if you need to use it but I wouldn't do it just because it's trendy okay so what have we got so far we've got conscious decoupling using data types rather than functions we're passing we've got these immutable data stores and we're storing event history rather than the current States next dependency injection right so if we had an object-oriented class we wouldn't want them to use at a particular canvas implementation we want to pass it in we want to pass in the logger so what we do is we create an interface and I canvas and an ilogger and we inject those interfaces into the turtle class in the constructor and then the move method would use the canvas and the logger the turn method would use just the logo and the pen duck would use just the logo and so on that's low dependency injection I'm sure you're all familiar with this again if I wanted to decouple the client from the turtle i would have an i total interface and the client would be injected with the isle and when it wanted to draw a triangle it would use the i turtle rather than the particular implementation so i'm not going to do a demo because we've got enough time so the advantages if people are familiar with this but this design just is quite a few first of all you have these unintentional dependencies so in this model I passed in a canvas but only the moon function the move method need to the canvas return function method didn't need it but it could accidentally access it so there's a potential bug there or just even the potential dependency where you've got this thing depending on something didn't need to depend on and often when you use interfaces they're not fine-grained anyone who's used a you know repository interface or a data access layer kind of thing if you find that you know you've got this customer database thing and it like get a customer update a customer insert a customer delete the customer change the customers password all these kinds of things and typically you know sometimes you end up with things with like 40 methods on it you only need one or two of these methods you only need like fetch for customer so do you really want to be able to delete the customer or change the customers passwords when all you want to do is fetch the custom from the database so it's very easy if it interfaces to glow which is why you have things like the interface segregation principle those various I you know guidelines to help you avoid doing that the other thing is when you have these deeply nested dependencies you often need a hell / lively like a OC container or something to help you manage all the injection logic right so let's look at functional dependency injection so in the functional style there is no class so every single function needs to have its dependencies passed into it so the move function needs to have the login function and the draw function passed in the turn function needs to have the login function passed in and so on so forth now the nice thing about this is that the turn function can't possibly depend on drawing on canvas because it's not one of the parameters so instantly we have this nice kind of decoupling you know you're not going to get accidental use between two different functions but now we have a problem because and so by the way these are functions we're passing and these are not interfaces with every single thing that the thing needs to do is passed in as a separate parameter so now we have a what we had originally was a move function that just you passed in the distance so now we have these extra parameters that we have class in a logging function we have to pass in a drawing function it's kind of awkward I don't want have to pass in a win over every single time but we can go back to the carrying concepts we can say this is actually a two parameter function that returns a new function so what we're going to do is pass in just these first two parameters and not the last one and that gives us a new function and the new function has the the login function and the drawing function sort of baked in to this new function and from the clients point of view it looks like the original function it just has this one parameter where you pass in the distance that I want to move so it's it's kind of like it's kind of like they've been injected that's from that kind of course point of view you know I'm back to where was originally it's quite nice so if we look at the implementation for how moves works we're now passing in the log info and the draw these are now two function parameters so this is now a lot of more parameters similarly if I want to turn I have to pass in the log as a function parameter but when I use it I basically create a new function by passing in the first two routers now here I'm create a new function by passing in just below the parameter so these parameters being passed in this is the partial application technique and what's less now is this function which is just what I need just the basic move function so if I'm using it in actually the client I'm drawing some stuff I can just say take the turtle State you know move 50 and then turn 120 and I don't have to keep passing in the loader and the canvas over and over and over again it's kind of baked into the function so there we go and I'm not going to do a demo because I'm short of time so the nice thing about the functional model is again everything's explicit I pass in a plan to every single dependency has to be passed in as a parameter and all the dependencies are passed in is individual functions not as interfaces so you can't get this thing where you have 40 methods being passed in and so that's a really good counter force to having too many dependencies so you don't need to have a little thing don't have 40 methods on your interface because you're having 40 parameters and that's really ugly you know straight away that something's wrong with your code you're going to be refactoring it straight away when you have 40 parameters so you basically have a natural counter veiling you know downhill the easy the path of least resistance just has fewer parameters so you kind of get the ISP for free interface Federation principle you don't have to like hard code it you know our special code of view the other thing is you don't need a special library you don't need IFC container it's built in this thing of using partial application is a fundamental functional program techniques it's like something just learns very beginning what's the downside I don't think there are any I think it was actually really nice technique I use all the time and I can't think of anything wrong with it so there you go all right next we're down to the last two the interpreter like so we have our turtle api we have our four functions like this and it looks quite nice but there's some coupling going on again example this is the kind of basic API but let's say we want to have the results be you know we don't wanna do the error handling thing so they're going to return results all right so that's without the result and that's with the results and they say well that's nice but now we've decided to make it a sink so now we need to be an async result okay so before and after every time we do this we wake the caller anyone who's calling this code is now broken they had to work with a sinks rather than what they had before now normally that's quite a good thing it's kind of nice to break the caller it's nicely you know you know that when it composite from the work so if it's not compiling it you know it's a nice reminder that you something's changed in the API but it's still kind of annoying is there a way to avoid this and the answer is yes the answer is addy couple using data structures again um we saw this before with the batch processing and the actor model and so on if we can turn this into a data structure we can completely decoupled ourselves from actually what's going on behind the scenes with us a sink or whatever the only problem is that we can't manage control flow as we saw with a batch command there's no control flow this time we want to deal with the control flow so how can we do control flow well if you think about it what we're going to do is we're going to create an interpreter for the data structure so I am going to send a data structure which I'm going to call a program like it's going to say I want you to move the interpreter is going to interpret that some way whether it moves a turtle or just there's something I don't care under my business how it actually works it's going to return the response the move was once like the actual distance moves now I can then make a decision based on that response like what am I going on our turn and we're going to move again either way I'm going to create a new program okay so here's the next step and say it's going to be a turn the interpreters gonna interpret that step it's going to return the response for that thing and based on that response I'm going to make another decision and I'm going to create another data structure which contains the information that I want to send to the interpreter and so on and back and forth so you get this back and forth during the client and the interpreter so how do we write this in code this one's getting a bit more complicated so bear with me again we have four cases one for each function in the API but it's getting ugly so let's let me show you how it works first of all we have the distance which sort of it for the move case we have the input parameter to the interpreter and this is like this is the distance I want you to move ok the interpreter is going to come back with a response which in this case is another distance the distance actually moved okay so that's the output for the interpreter and then I need to make a decision based on that response and I'm going to create a new turtle program which I give back to the interpreter again ok so that's basically the next step for the interpreter so each of these things generates a new program all right so this is series if I want to do a turn it's the same thing I passed in the angle I don't get any response and I create another step and so on so this is the fundamental model of what we're going to do now the problem with this is that each step returns another turtle program and so on ad infinitum so it goes on for infinity right so we're going to have to have another step which I'm going to call stop that's the end of the interpreter so this is a new case needed that wasn't in the original design so let's see how we actually would use it from a science point of view so if I want to do a triangle I'm going to set this data structure now this is not a command this is the data structure and the first side of the data structure is what I'm sending you the second part is a function which is given the response ok I'm going to give you another program so it's almost like a callback so there's a continuation you give me this response I will give you another program another programming on give you is a turn ok you're going to give me a response back and I'm going to give you another program which is a move you're going to give me a sponge back I'm going to give you a turn again and so on and so forth and then finally I'm going to say ok I'm done you can stop now so this is how you would draw a triangle using this approach ugly again all these continuations is their way to get rid of them yes though is yes we can get rid of them how can we get rid of them we use the same thing with it before we create a special expression that computation expression that hides it we've seen this trick many times before so we're going to call a turtle program expression and inside the turtle program we don't have to worry about these continuations that get hand or sores behind the scenes so the program again looks like an imperative kind of program move here turning a movie or turn here but this is data ok this is not moving a turtle this is purely a data structure it's an abstract syntax tree if you think so now I need to interpret this data so I have this set of instructions I've created the turtle program I can have many different interpreters for the same program so let's talk about a normal winter that'll be the turtle interpreter so for each case I need to handle it so if it's a stop case I'm done if it's the move case I'm going to move the turtle I'm going to get the actual distance back that gets fed into the next step and now I have in the next program and I basically call myself again I loop back recursively and call the interpret function again but now with the next step in the program if it's a turn I turn the turtle I get the response I get the next step in the program and then I call myself again recursively with the next steps this is they look thanks we need to understand this very way but you can see it's not that many lines of code like no turbot is not a hard ok so moving the turtle executing next step calling myself recursively if I want to have a distance interpreter same kind of thing except all I care about is moving so if you move I'm just going to accumulate the distance and call myself again and if it's a I dislike no change or so I just call me the next step alright so let me see if I can do a quick demo of this [Music] yeah interpreters distance here we go here's the code for that so here's the draw triangle program when interpret as a turtle there's the initial state I'm going to set up my canvas and now interpret the program so the program says turn move turn move to move the light so that's one interpretation now I can take the same program okay exactly the same program but this time I'm going to interpret the data structure as a distance thingy I need initial distance which is zero and I'm going to interpret the program as a distance changing thing and all it does is print the answer here's the total distance moved was three hundredths so this is really nice I really really decoupled the client from the entropy note from behind the scenes okay the Vantage is completely decoupled nothing but API no implantation you can do some neat tricks with optimization so for example if I have free moves in a row in the in the data structure I can collapse them into one single move so that might save time on network you know thing the disadvantage is really kind of complex and it really only works with a set of limited operations some good examples of this approach this is called the free monad approach as well Twitter's stitch library Facebook's axial library they use this technique all right so I've just got a few minutes left last one all right so I'm just going to go a few minutes over I hope you'll be allowed time capabilities okay so the last one this is a general thing about calling any API if I call an API sometimes it fails okay and I try to call it again and sometimes it fails again and it just can't do that and it's quite annoying if you've got an API and it doesn't really give you any guidance on how to call it you have to know how the API in order to call it especially and that's quite annoying so rather than having a can I tell you what you can't do you call it in a so I can't do that you call it so I can't do that one thing what you can't do why not say what I can do okay so this is what I call the capability based API so the capability is kind of like a key if you have the key you can open the door if you don't have the key you can't open the door all right so I'm going to model capabilities kind of like a key so I make a call to the API and instead of just give me a result the API gives me back a bunch of keys it gives me back a bunch of capabilities and each of those capabilities I can choose which one of those capabilities to use so which dorm are going to open so okay I'm going to pick one of those and I'm going to open the door and it takes me into new room and I get a bunch more capabilities because it's like it's one of like one of those dungeon games you know so in the turtle thing how does this work in the turtle world I make a move so instead of just getting response back I get three capabilities back you can move you can turn you can set the pen down for example all right so let me see I want to move again now this time I've moved to the edges of board and I get to say percentage back I can't move anymore so one of them trying to move and getting a failure I literally do not have the capability to move the turtle that is not one of the functions I can call so this is the key thing about capability based programming now this is the code this is the stress of data structure basically which of the mister functions the move function is optional the turn function the pen up function the pen down function these are all always there so when i make a move i pass in addition should I get back the capabilities when I when I turn I pass in an angle and I get back the capabilities and so on and so forth so from the caller's point of view I start with some capabilities now what I have to do is test do is the move function either there so if the move function is not there it's an error okay but mine we try turning around and see if the move function shows up again if the move function is there then okay I can use it I'm going to move but now I've moved I have to check again and you set of capabilities and the move function might not be in the second set so I ask - the moon flexion again and if it's nothing that I can't do the second move and so on so the client has to do this logical checking whether the capabilities fail or not so let me do a quick demo and then I'll be done in literally a minute so here's the initial table capabilities and you can see there's the state of structure and here's the move function so it's available so let me move and I've moved and now I still have a move function available so let me move again and now I've reached the edge of the canvas I can't move anymore and so the move function is now null it's not available for me to use but if I turn I get a new set of capabilities and this time there is a move function so I can use the loop function again and I can keep doing that so the capability thing is it capable if they have kind of come and go based on whether I can do them a lot so that's kind of nice so what's the pros and cons of this well the big the big advantage to me is the client doesn't have to duplicate the business logic in many situations you find that the client has to know what to do you have to understand what the server is actually doing in this model the client all it does is follow what the server tells you do says you can do this you can't do this and it's not a thing I'll just do that so that gives you some much better security so for example you can't accidentally delete a customer because the delete capability is not given to you you can also do clever things with capabilities can transform them because they're just functions you can if you want to say a business rule you can only use a turtle between nine and five on weekends or something you can just take one of those papers you can wrap it up in another function and that function you know adds that extra constraint that you can only use at a certain time so caper this is great if you're doing complex business rules downsides really complex and the client has to handle this unavailable functionality which really it should be doing anyway all right classic example of this is hypertext as the engine of application state proper restful architecture is exactly this model you get back to a bunch of links and you follow the links and if the links not there you can't do it and if the link is there you can't do it that's a really nice model all right more on this I have a talk on this cat slash camp on my website and that is it so thank you very much say the slides will be at the slash turtle directory if you need f-sharp consulting contact us at eff shot works if you want to know more about F sharp including instructions on how to download and install it go to F sharp org so thank you very much and I'll be available for questions if you want
Info
Channel: NDC Conferences
Views: 25,560
Rating: 4.9449224 out of 5
Keywords: ndc, ndc london, scott wlaschin, functional programming
Id: AG3KuqDbmhM
Channel Id: undefined
Length: 64min 41sec (3881 seconds)
Published: Thu Feb 16 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.