 So, I had a choice this morning, I could either do a presentation or we could live stream April of Giraffe and just, you know, see what happens, but I decided to end the presentation because the Wi-Fi is not up to April. Come on, there you go. Excellent. All right. So, what I want to talk about is letting go of stuff and I'm going to be doing a lot of live coding so you'll have plenty of opportunities to laugh later on. So let me introduce this by just a little bit of history. Our story really starts on the other side of the planet in an island called Vanity, part of the Micronesian chain. And people, the native people living there, Aboriginal people, have very, very little contact with the West. That's just to show you roughly where it is. There's New Guinea, Australia, Japan up there, Vietnam just above it. During the Second World War, it was obviously very strategic. Melanesia was invaded first by the Japanese. It was a scene of some of the toughest fighting of the war and eventually was occupied by the Americans. So first by the Japanese, then by the Americans, the natives got to see the West and what they saw was people would come in and they would build these strips on the ground and put lights on them and build these towers next to them and people would talk on the radios. And when they did that, big things would come out of the sky and those things would contain other things, good things, you know, food and tools and other boxes of things. And so when the war was over and everybody left, they decided that they needed to make these things continue to come. And so they actually constructed their own runways and their own control towers and they actually held effectively religious ceremonies where they would simulate planes coming in to land in the hope that they would remind the gods that, excuse me, we need some of this cargo to come through as well. This is called a cargo cult and it was actually made famous probably by Richard Feynman who in a Caltech talk talked about, I'm going to read this, in the South Seas there's a cargo cult of people during the war they saw airplanes with lots of good materials and they want the same things to happen now. So they've arranged to make things like runways to put fires along the side of the runways, to make wooden hut for a man to sit in with two wooden pieces on his head as headphones and bars of a lamb boot sticking out like antenna. He's the controller and they wait for the airplanes to land. They're doing everything right. The form is perfect. It looks exactly the way it looked before but it doesn't work. So these people making a wooden hut someone sits in with headphones on. Now clearly nowadays all of us are way, way too sophisticated to sit in little wooden huts with headphones on, right? No. We all do it every day. We all sit here and cargo cult. We all do things because it worked for somebody else. In fact the entire basis of process consulting is because people say, oh this worked for me therefore it must work for you. So we cargo cult all the time. And what I'm going to try and do today is just to show you three areas in which I think we need to start breaking away from the cargo culting of the past and they're all to do with code. This may seem a little bit like a commercial for my GitHub repository. It's not really. It's just that I've been playing around with these things for a long time. Since I have more time on my hands after I kind of pulled back from publishing, I've had this little explosion of ideas that I wanted to try out. So first one is QuickSir which is a property testing framework for Elixir. Now the idea here is that I wanted to play around, actually what I really wanted to do was play around with streams and generation. But I also wanted to experiment with property-based testing. I've never done it before. And I actually misunderstood what it was. And this is where the kind of cargo culting comes in. Because we all know that testing is good and some of us actually do it. But the kind of testing we typically do is unit testing with assertions that say, sort of do something, assert this is this. And I think that's a good idea. But I really enjoy testing not because of the testing aspect because it makes me think about my code. It makes me think about my APIs. But that's only part of the thing. When you're doing functional programming, your functions have an implicit set of inputs they can deal with and an implicit set of outputs they can create. This is the domains and the ranges of our functions. So how do we test those? And how do we think about those? And that's where a property test comes in. A property test says, hey, I'm going to call this function 10,000 times. And I am going to give it randomish values. And I'm going to find out what the properties of this function are. So for example, you might decide to test to make sure that addition is that commutative. I can never remember which ones are associated with it. Whatever. I'm going to test that a plus b equals b plus a for all integers. OK, a non-test. But it's still kind of like interesting to do. When you feed that kind of thing into your code, what your testing is, your function is actually a good member of that function's domain and range. You can do property tests like this to say, I want an a and a b, which minimum value is always going to be one greater than whatever value you choose for a. And then I'm going to assert that a is always less than b. Not a big deal. Or I can say that I'm going to test a struct person. And so I'm going to generate random person structs. And inside that random person struct, I'm going to have a name, which is a string that contains only ASCII characters, and an age between 1 and 125. So again, we're just generating values and doing it. And that was, for me, the entire joy of it is this idea of generating streams of values. But having done it, it actually changed my entire perception of testing. And it makes me think a lot more about my functions in terms of their domains and their ranges. And when I started thinking about streams and generating things and factories, I came up with the name Pollution for the actual library. So if you actually ever need a stream of random values from some kind of meet some criteria, Pollution is your friend. Anyway, so that's one thing. Next thing, diet. I wanted to talk about code as a set of transformations or a set of transitions. I've been lucky enough to do a bit of teaching last semester. I taught one of the first elixir classes at a university, which was great fun. Really cool students who hadn't heard about things like version control and testing. But if you do do a computer science course, the chances are pretty good. At some point in the first week, some professor will have drawn a picture on the board that looks something like this. This is how computers work, they will say. We have an input and it goes to the processor and it produces an output. And then maybe we'll actually store some stuff on disk somewhere and then bring it back up the next time you run the program. So that's what our basic processor looks like. So let's tighten it up a bit. Now today, it doesn't look that simple, but we do have something that does look that simple. And that's what we're coding with processors today. We don't call storage storage, we call it state. But it's exactly the same picture that we use. We have a function, we take an input, it uses state and it produces new output. And in fact, typically we have this kind of more ladder-like picture where we have common state and we pass that state between our functions. Now, that state can be passed back and forth to the same function over and over. And that's what we do in our gen servers. Or we can actually have that state that gets passed from one function to the next function to the next function. If you do Phoenix programming, then that's what you're doing with a connection plug. Yeah, you're just passing state between a set of functions. And that's a perfectly great way of programming. So I've started thinking about this. When we do that, we also quite often have different sets of state. So each gen server, for example, will have its own set of state. And each gen server will be independent as it mutates that state. And then if we look at the individual mutators, individual functions like that and look inside one of them, there's nothing to say that that cannot have this same set of mutations built into itself. So every function acts as one of these mutators, a transformer. And it contains nothing but a set of transformers. So I started thinking about that. Can we have transformations all the way down? So the first question I decided to experiment with is can we write non-trivial programs using nothing, but, and I set myself the target of one line transformations. I came to the conclusion that yes, we can. But it's stupid, right? You're unreasonably limiting yourself in what you can do. So I kind of relaxed the constraint of it. Can we write parts of programs as nothing more than one line transformations? And clearly the answer is yes, because if you can do the first, you can do the second. But here it starts to get really exciting. Because I think if you start looking at your code in terms of single line transformations, you will discover hidden patterns that you never knew were there. So I produced a little framework called diet. Diet because it actually consists of, you write a whole bunch of reducers, so ha ha. And all you're doing diet is you define transformers. And a transformer is a function, or just an expression really, that takes a state and creates a new state. So we have basically input going to output. When I said it creates a new state, it actually creates two things. It can potentially update a state. It always produces a value. So there are two forms of a transformer. One where it just takes an input, produces an output. The other one where it updates the state along the way. The input to each transformation is a pattern, potentially with a guard clause if you wanted to have one. And of our pattern matches, it produces an output and then diet immediately looks at an output and says, does this match the input of any other transformation? And if so, it just runs that transformation and it keeps doing that until it can't find a match. And when it can't find a match, that's the value that is returned from the sequence of transformations. So this is where I make a total fool of myself. So let us, let's try writing FizzBuzz, yeah? So thank you, autocorrect. All right, sorry about that. So we're just gonna write a regular ellipse of module. It's gonna be a long morning if I'm gonna type like this all morning. And we're gonna use diet transformations. And now we're gonna define a set of reductions. So let's assume that our input, you could just give the input being a number. I like to give inputs being a bit like a gen server message where you have the function that you want to perform and then any parameters. So let's have the function being FB for FizzBuzz because I'm not gonna type that much at times. And I'm gonna take a number and I wanna produce either a FizzBuzz, a FizzBuzz or the actual number itself. So to do that I need to know whether our number is divisible by three or divisible by five. So what I'm gonna do is recode this as a transformation to a FizzBuzz on our number and then the remainder of our number by three and then the remainder of our number by five, okay? So that's a simple transformation. So now I'm gonna start matching on that output pattern. So if I have an input created by that output that looks like that, well then it means my number is divisible by three and divisible by five. So now I just wanna produce FizzBuzz and a cheat a bit here, okay? If instead my number is divisible by three it's not divisible by five because that would have been tested by the previous clause. So it's gonna be a Fizz. If it's divisible by five, then it's gonna be a buzz. Otherwise it's just the number, okay? So that's the series of transformations that I can write. And to experiment with that we can actually run this code if I remember to save it, all right? So I'll just go into IEX. How do I run this code? Well I have to have something that's gonna step through these transformations. So diet has something called a stepper. So I can say S equals, and I can give it the module and then in this case nothing, I'll come up to what that does in a minute. So that's created for me a stepper. So now I can run that stepper and give it some input. So I'm gonna say the result and a new state we'll get onto that in a second equals diet.stepper.run. I'm gonna run my stepper S and I'm gonna give it a number. So let's give it a number six, okay? Oh, let's just have a look at just the result and not the new state. So I'll just put a R at the end there. So I give it six. It comes back with a number six. If I give it five. Oh, it comes back with five. That's not right. What have I done wrong there? Okay, I will show you a magic trick. If I say diet.debo my state, it doesn't work. Well, this is going well, isn't it? Say what? I need the symbol of FB. Oh, yes, thank you. I'm an idiot. Okay, let's do that again. All right, so we're gonna, we still have our stepper lying around. So I'm just gonna run it again. You're absolutely right. The parameter I passed into it, I should have passed that in. Yeah. FB, FB, FB. Yep. And I also had to pass in the actual original state. There we go. This time it runs and gives me his fizz, which is a multiple of three. Yeah. If I give it a five. I get buzz. If I give it 15, I get a fizz buzz. If I give it 16, I get 16. Thank you for that. I appreciate it. Okay, so that's just the basics, right? Let's do something slightly more complicated. Let's do something like run length encoding. So the run length encoding, what I'm trying to do is if I have an input that looks like one, one, two, two, two, three, four, four, five say, that what I wanna do is to convert that into one and then how many twos have I got? I've got three twos and then a three and then two falls and then a five. Yeah. Totally pointless, but kind of a more interesting. So let's create code for that. So def module RLE. And again, we're gonna use our transformations. So we start off, we have a list. Okay, so we're gonna RLE some kind of list. And we know just some experience that to run anything code a list, we're gonna need an output list as well. So the next first thing we'll do is gonna just basically transform that into an RLE on our list and a result. Okay, now I just stop and just think about how you would write this code in something like a Ruby or a Python or whatever else. All right, and just think about how the code would actually involve with lots of if state and everything else. Here we can just use your Lix or pattern matching. So if I match an empty list and I have a result, then we've actually finished and we just wanna return our result. And that's actually a bug but I'll come back to that in a second. If I'm gonna RLE a list and if that input list has the same element twice at the head and I have a result. So then what I'm gonna have to do is to replace that head with a tuple. So I'm gonna come back and say, okay, so now I wanna do is a RLE on a list that contains a comma two. Rest and a result, yeah. If I have a list that starts with a followed by a number in a tuple then and followed by an a then I'm gonna increase that number by one, okay. And then finally, if none of those things are true, I'm just gonna move the input to the output. So if I have a list that has an a and it's not match the current thing, then my result is simply gonna be what happens if I RLE the rest, okay. Now, you all recognize the pattern we're recrosing through a list. So you all know that that means that our list is gonna be in reverse order when we finish. So just to save myself a bit of hassle, I'm just gonna do it the innum reverse here. Extra square bracket on the last line. You're absolutely right, thank you. Anything else just before I make a total four? Okay, so let's go back and see what we can run that. So I need to create another stepper. So S equals, you know what? You're absolutely right. Yeah, yeah, that's probably, no, I've done an alias. I can't kill it now. See, there we go, thank you. Coding is so much easier when there's a hundred people helping you. Thank you, really appreciate it. So R comma S equals DS dot run. And we'll pass in one, two, three, three, four, four, four, five and just see what happens. I'm sorry, oh yeah, you'll get that. Let's just have a look at the pure result here. So there it is, it's done the RLE. Now, the thing about that is that's the kind of code that's trivial to write using a set of transformations. If instead I wanted to write that in just linear if then else style, right? I can guarantee you I'd get it wrong. And I know it because I've tried, right? I can guarantee you there are edge conditions that I wouldn't think about. So there's another interesting thing here. I'm trying to work out why my debugger is not working. Okay, I'll get back to that. You'll notice here that I'm actually keeping the full history. Of what's happening. I don't have to, but I chose to. And that means I can actually go back and see how I got to where I am. So I can look back to the history and say at a particular step, this was my input, this was my output, this is the action I took. And that's kind of cool. So one last thing I'm gonna show you and I'm not gonna live code it, you'll be very pleased to know. Where am I now, 35? Let's go to roughly 40. Okay, so in my university class we used Hangman as the ongoing example. And in Hangman, we have a model which represents the game. And then we have a set of transformation which are kind of the rules that apply to that game. If this, then that. So if we were to write the Susan transformations we would keep the model pretty much the same. So we just have a regular old elixir class that represented our game. So the word to guess, the number of guests is so far, et cetera, et cetera. And then we would use the transformations. But this time, remember we had that diagram with the model and the transformations and we'd move from one to the next to the next? Well, that's what we're gonna do here. We're gonna tell our diet set of transformations that it's using a particular model. And inside the transformations we're gonna make that model available as a variable called game. So then we can write our actual Hangman game like this. Yeah? The first thing, the kind of entry point is where I say make move and I give it a move. And the first thing I wanna do is to say, have you already guessed that letter? So I'm gonna transform that into a new tuple that actually calls the model to say, has this letter already been used? If it has, then we're gonna issue a new tuple that says make move move true. And so the result's gonna be you already used that letter. Otherwise, we're gonna record the move. And record the move uses this thing called update model which is how you know you've changed the state. So we're gonna update the model and the new state is what happens if I call that model and say I've used this letter. And I'm gonna return maybe match because that's what I wanna do next. I then go in and I ask the model whether or not this matches and if it does I'm gonna do one thing otherwise I'm gonna do another thing. So you can see what I've done here is an entire list of single line transformations that are slowly working out what's happening with this particular move. And the result's gonna come back and say you either already used it, it's a good guess, a bad guess, you've won or you've lost. And again, it's so easy to see, it's just linear code. So we can run that, I hope. No, I'm not gonna run that. So given that code, we can run that exactly the same way that we ran our previous code. So we can run it using our stepper and this time we're gonna feed into it initial state for the model and that's what that last parameter that I always had nil so far, that's the initial state. And that state is actually passed to a build function in the model and the model uses that to actually build its internal representation of that state. So once we've got that, then we can just keep calling our stepper and inside those steps, our state is gonna be passed in in that variable called game and it's available to both the model and also to our transformations. And so when we use that, we can just play Hangman which is cool, right? So here's the interesting thing. There is a lie that we all go along with in functional programming. Okay, sorry, it's not a lie, it's an alternative fact that we have no side effects, right? Functional programmers, we code, we have immutable state, we have no side effects and that's why we're so great, yeah? But it's not true. Think about this piece of code executing. Doesn't matter what it does, just think about how it executes. There's one critical thing that's being overwritten every single time anything executes in that code. Unbelievably important thing that we just take for granted. That's the program counter, right? Every time we write something that executes, we're actually mutating the program counter as it executes. Now if that's not a side effect, I don't know what is. And that's what makes it so difficult to go backwards in our code because our code consists of nothing more than a side effect of moving the program counter forward. But if you were to write code like this, you'll see that you can actually keep all of those histories. So if I was running this game, and as I'm running this game, I keep a track of all of the transformations that I'm actually seeing. And part of the state of that stepper is a history of all the transformations. So I'm making my moves and then suddenly I make a mistake, which I don't like. So can I do anything about that? Yes, I can actually go into my history and just delete the transitions that correspond to that state. Take me back to the clean state at the end of the third guess. And because that is then pure, there is no program counter involved, it doesn't matter, right? I can just then go forward as if the bad guess had never happened. I can fork the histories. I can clone my history into two separate channels. And then by doing that, I can actually run alternative futures and see which ones I like better. Or maybe I'm initializing a server and I have some complex initialization, some time consuming initialization. So I'll do it just once, get the history to that point and then fork off as many processes as I want, each with that shared common initial history. All right, this is a really powerful model. So I think it's worth playing with it. This is simply the idea that I can actually just change history and fork history is fantastic. I also get some other side effects that are nice. I get single line of code reusability. I can be parallel. There's nothing to stop me running each of those things in a separate process. I can actually live reload the flow and not just the code, which is if you think about it, the transitions represent the flow through my program. And of course I get world peace. I'm wondering for time. Yes being, yes is not the answer for how much. Seven minutes. Seven minutes, okay. We're gonna go quickly. All right, my last thing is servers. So outside the world is embracing services, microservices, this is the way to go, right? We're gonna rewrite all our applications as microservices. We've been doing that for 30 years, yeah? And that's not a big deal. Fundamentally a gen server is a microservice. And yet, is that what we do? Is that how we write our code? And the answer is no. Most of us do not think about writing code that way. Why? I think it's because the ceremony of writing a gen server is just too much. So let's look at that a different way. Let's actually start writing some code. So I have a service running right here, right? I have a service that's already running. It is a REST service. Well, no, it's not really, it's just a stupid service. And if I call it, localhost 4,000, if I pass a number, then it's gonna go through an incredibly complicated computation. It takes about three seconds before returning a result. And so in order to make sure it's actually operating, I've added some trace into my main window here. So if I call this like that, you'll see that it actually thinks for three seconds before returning, and that's a bit small. If I give it five, it returns 25, yeah? And if I give it seven, think, think, think, ah, it returns 49, okay? So that's the service that I'm gonna call. So I'm gonna write some code now that's actually gonna invoke that service. So that is just a simple elixir module. It uses poison to go and fetch whatever the parameter is and then just returns the body out of that. So if I go back into IEX, I beg your pardon. Missing do, but even that, failed to check the hex version? Failed to check the hex version? So you wait the record's at three seconds, it comes back to 25. You think to yourself, that is so cool, right? I've got myself a module that does this, but it's a module, it's not a service. And this is something that is so universally useful. I wanna make it available as a service. So I probably wanna turn this into a gen server. Now at this point, you're gonna have to go off and look at the gen server code. If you're an Erlang developer, then you'll probably bring in the standard gen server template, which I've actually checked, is exactly 128 lines long. If instead you're gonna use elixir, then you can look for an elixir template for gen server and the ones I found coincidentally is 32 lines long, which is two orders of magnitude, base two, smaller than the Erlang one, but it's still 30 lines of code, right? Which is ridiculous. So this is what we really should have to be able to do. If we wanna create a gen server, I should be able to say use, okay? I wanna create a named service. And that's it, and here's my name service. So if I come back over here and rerun this, or reload it, sorry, okay? So now I have a gen server, so I need to be able to run it. So the first thing I'm gonna do is say fetcher.run, and now it's run that code as a separate PID, and I say fetcher.get5, and now it's calling on gen server and it comes back. So you may not think there's actually a gen server there. Observer. I would love to know under what definition of alphabetical, this list is alphabetical. Here it is. All right, come on, I found it and then it disappeared. There it is. Elixir.fetcher, and you'll see it's a gen server. Yeah, it actually has no state, but that's okay. So you then say, okay, so I would like this now to be, I would like to run this many, many times. I wanna make use of the parallelism in Elixir. So let's actually just quickly write some code to do that. Well, that was quick, right? So there is code that runs fetcher 10 times and gets the result and reports it back to us, and it does 10 times and each one is in a separate process. So this thing should run really, really fast, right? So let's try that. So I'm gonna run my fetcher, and then I'm gonna run that code called hello because that's what it came through when you create a new application. And uh-oh, even though I have 10 separate processes going through there, I'm actually only, oh, I timed out even, right? There's nothing, it's all taking place serially, right? Because I have a named gen server here, right? There's only one of them. So you can only execute one at a time. What I really wanna do is to have a pool. So okay, I'm gonna have a pool, I'm gonna go get pool boy, and I'm gonna go through all the machinations of creating a pool of these services, yeah? Anybody ever done that? Yeah, well it takes like, I don't know, the first time you do it, it probably takes a couple of hours to get right, and then after that, you're always juggling little things to get it right. Well actually, all you really have to do is to say service.pooled, and we can set the pool parameters. So I'll say min to max three, say, and so that's gonna automatically create for me a pool boy set of processes that I can run. So if I go back to IEX over here, I'm gonna reload Fetcher, and it's, oh, and run it, and now it's running in parallel using a pool. So my point here is nothing to do with this particular code. My point is the process. My point is that we have been told that OTP is sacrosanct, and we have been told that GenService the way to do things, and we have to write our code using that particular style, right? With the handled calls and the tuples and all this kind of stuff. Underneath the covers, that's exactly what this is doing. It's generating all that code for you. But all you have to do is to write an all arrest, and why should you have to write anymore? So I'm saying, let's start throwing away some of these preconceived ideas of how we should do things. See, I've spared you all of that stuff. So it says, we clearly want to learn from the past. As an industry, we fail miserably when it comes to knowing our own history. Everybody here needs to learn a lot more about how things were done because that will stop us reinventing everybody's mistakes yet again, yet again. But let's not worship it. Let's not cargo cult it. Let's not build GenService just because somebody else built GenService and it worked for them, right? Let's think of alternative ways of achieving what it is we need to achieve, right? We have the opportunity here to start something new. Learn from the past, don't worship it. But on way, always remember, have some fun. Thank you.