 Welcome everyone. We are really thrilled to have Graham Dixon with us here and he's going to be talking to us about extending railway oriented programming at Elm to make complex user flows simple. So we'll be interested to see what you have to tell us about that the problems that you've been solving Graham over to you take it away. Welcome everyone. I'm looking forward to giving this talk I'm really excited about it. It's going to be about solving some interesting problems for implementing a board game. And it's going to be using some pretty fancy functional programming techniques so I'm just going to get my slides happening. So here's the title of my talk. Extending Railway Oriented Programming and so a little bit about my background is when I was a teenager. I dabbled a bit in C sharp discovered some F sharp and was like oh man functional programming is really cool can solve problems without so much surface area for bugs. I was really excited about it. But I didn't really see how I could make a career of it at that time. So I kind of did other things with my life until about three years ago, when I discovered Elm. And I was like wow Elm sounds like it's really good for complex projects. People are talking about how easy and even fun it is to take a big code base and do refactorings for it add new features make changes. And I was like, wow, I could tactile some really interesting problems with this. And at the same time it was really interested in this board game called codex, developed by David Sirlin, which has a small online community. But as we'll talk about has some issues with how it's being played. So, I thought that this would be a really interesting project to work on. Yeah, so we're going to talk about some specific challenges that I've tackled in implementing this. But just as a little foreshadowing over here is we've, you see these cards over here. And one of the things that happens in a card game like this is that there's lots of side effects. So for example here we've got this double shot archer creature, and whenever it attacks it does extra damage to the opposing base. Which means that it's in this game there's lots of side effects, and I'm sure a lot of you're thinking, wow, functional programming inside effects usually that's like oil and water doesn't mix so well. But in this case, the way side effects are handled in the rules of codex is like it's a very specific way that it has to be handled. So I think it makes a lot of sense to sort of have a managed side effects system that I build an Elm. And then it's when it's all complete it's going to be very consistent. So a little bit about how codex works just so you get a picture of why I care about it is this very inspired by something like starcraft. It's like a real time strategy game where it's not so much about building a deck ahead of time like something like gathering our hearts, hearthstone, where you're just hoping that you're the deck that you built beforehand is good, good enough to beat the enemy deck. But it's about adapting your deck over time just like in Starcraft you would build different technology structures. So that hopefully you can have just the right cards to be able to outwit your opponent. And over here we're saying that some of the art assets look very similar. They're not really hiding their inspiration. Yeah, so we're going to talk about how how the game is currently played online is that there's a small but passionate community that plays the game by forum. So the each turn in the game is complete can be played completely asynchronously. So it works really well in this format. And it's actually pretty neat. One of the things that's really handy is that the features of the forum you've got some hidden information. So when I'm playing against my opponent opponent here charnel mouse. I'm going to click through to see his hand and I'm not going to click through to see what he's thinking about. But you can see, in this case, this is the first turn. And he's written three paragraphs about thinking about how he's going to try to beat me up in this game. So if someone's observing this game that they have a pretty rich experience it's almost like a text based version of like live stream eSports. So that parts that parts pretty good. What's less fun is that the way that we're managing state of our of our turns between the forum postings is with these Google spreadsheets. And, as you can see it's not that pretty. It's pretty hard to see what's going on. It's really easy to make mistakes. So, I think I can do better than this. So a little bit of foreshadowing the main the main topic, the main problem we're going to solve is going to be specifically handling the keywords that happen during attacks. But before I'm going to give some background about railway oriented programming and some other problem I've solved. So, a little bit of a refresher on railway oriented programming is it's really just about how to handle errors in functional programming. So, in Elm we have this result result type to handle errors. And if you're familiar with functional programming and monads and stuff like this. It has an okay value it has an error value and it has all these functions that have these types of function signatures. And if you're familiar with functional programming you can see all this and be like, I can use this. I'm pretty sure I know exactly how this works. But for everyone else really oriented programming is a useful metaphor. So way really oriented programming works is to imagine a function that returns a result is it's sort of like you got a railway and it's got a little switch in it. So, you're taking your initial argument, and it's going along. And if it's on a happy path, it's going to go and say okay. And if it's on the unhappy path, it's going to go. It's going to go on the other path, and it's going to return an error. And then the fancy thing we can do with functional programming is we can use this, and then function, which is similar to a monadic bind in other languages in Elm it's always called and then to combine the switches together to make a series of switches and have a more complicated flow built up over time. And what's really valuable about this metaphor is it's really clear what path of code is going to be executed during the series of switches. So in this example, five is not going to be divided by zero. There's an error. So it goes directly on that unhappy path. And the happy path you can see is not going to be executed. So, the next problem we have to solve is about random. So I was talking about how in this game there's lots of side effects. In this case this is free examples of different things that can happen attacks dies and arrives. It all happened to draw a card and drawing a card could cause a shuffle, which means I have to do randomness and the randomness could happen in any place. So I have to be able to handle this in a way that doesn't give me too many headaches. So, in Elm, it's a pure functional language, but the way that we handle randomness is that we just ask the Elm runtime to say, hey, take this randomness that we need and generate it for me and come back to where we're working. Which works really great when I'm running an Elm application, but if I'm running a test, it's talked to the Elm runtime. So I've got to figure out a different way to be able to handle these potential shuffling issues without dealing with Elm runtime. So what I've done is I've come up with this simple knowledge type. It's very similar to that result type. It just has a known value, or if it's unknown, it's going to have a generator of a value. And it's pretty simple to use in practice. If I have a function that returns knowledge, if it's going to shuffle, it's going to return a generator, and if it didn't shuffle, it's going to be a known value. And then when I'm writing my tests, I can just make sure that I can fake out how my decks are working so I never have to shuffle. And then here's an example of how to use the knowledge in a test. It's a little bit awkward, because I have to unwrap it. You don't actually know if you know what the state is when you're just looking at the fully wrapped knowledge type. So I have to unwrap it something like this. It's a little bit awkward, but at least it works. So now we're getting to the main, the main problem that we're looking at. So we have over here these three different cards that each have keywords that happen during an attack, which is a very basic thing that happens in a game. And each of these things will often require that the user has to make a choice about how it's going to happen. For example, this really cute ocelot with a beret has spark shot, which means if it's attacking a patroller, it has an opportunity to do an extra damage to an adjacent patroller. And obviously if there's multiple adjacent patrollers, the user is going to choose which of those is going to take that extra damage. So how are we going to solve this? We're going to use surprise railway oriented programming to do this. So when I was thinking about how to solve this, I was thinking about that little train that goes on the track for the railway oriented programming pattern. I was like, oh, what I really need is for that train to go somewhere else, ask for the user to figure out what it needs to be able to make that choice. And then to be able to come back in that exact location that it needs to do so I can continue going on the flow of things I need to do during that attack. So that's now a station. So I've kind of got these little stations for all the different choices that the user might have to make during this process. So first step that I did is I took all the different steps that could happen during an attack and I put them in order. And in this case, I'm modeling this as functions that are each going to call the next function in the order when it's done. The reason I did this is it makes it easier to re enter the flow as we'll see later. But I want to be clear that for this pattern to work, this functions calling the next in order is not necessary. It's kind of a style choice. And there's other parts of the code that I just use cues or something like this. But in this case, I was just really paranoid that everything had to be in the right order. So this is how I handled it. To show an example of how each step calls the next in order. We have a start attack, which is the first function in his chain that's going to be called. And what it does is it just calls the first, the first step in the process which is the may obliterate. And during that may obliterate. If it's going on the happy path, it's going to call into this next step after obliterate function, which is just going to call into the next one, and so on. And result of this is that the destination the rich, the result type is always the same. So in this way we're building our the basic tracks of our process. So now we're going to talk about how we make the extension here. So we're going to need several things for this we're going to need the data for how for the user and how to make a choice. We're going to need to know how to re enter the flow at the correct point, and how to present the choice to the user. So I'm going to build these up one after the other. For the data for the choice is just a special kind of error. So it's still sort of fitting into the basic pattern here. So we've got this choice required type of attack error. And in it we're going to have all these different kinds of choice that are going to be required during different kinds of attacks. Each of these choices are going to be oops. It's going to be sort of the location of where it's coming so when you're choosing obliterate targets, because it's that type of choice, that's going to indicate where in the code it's going to re enter. And it's also we've calculated what are the valid choices that we're going to display to the user. And then we're going to talk about re entry points. So when the user makes a choice. It's going to call into the attack in the attack module, these different chosen functions so for example, and obliterate chosen is is called. And it just does the meat of what the obliterate function is supposed to do. And then it does, there's a good example of using the, and then next step pattern that's sort of the core of the structure of what we're working with. You've got five minutes leave Graham. Got five minutes left. Oh no. Right. So, bring this into context. And then we're going to talk about what's there. So, for the kind of modeling what the station looks like is I've got different contexts for each different situation that the game could be in so it could be main phase upkeep phase, in this case, a choice during an attack. The context module is going to generate view models that can be displayed to the user, and it's going to highlight the different elements that the user is going to be able to interact with. And when the user interacts with something it's just going to call in the context I choose creature or choose building or whatever it is function, which is going to handle depending on the context that choice in a different way. So for this example, we're choosing a creature during an attack, and it's going to handle that choice like we've described before. So if you're choosing a creature during the main phase, it's going to be a wrong context, and we're going to send back to the user interface that that wasn't something that's legal. So, in that way, the context is able to keep what is what's available to happen, which is great. The context is telling the UI what to present, and it's telling the game state what to manipulate. And that means that in the game state, the game state doesn't have to worry about, is this the right context for me to do what I'm being asked to do it can just do it. In for the user interface, do I doesn't really have to know what it means for something to be clicked. It just has to say the context is responsible for that operation. You just have to display what's clickable and communicate with maybe some texts to the user how to deal with this. And then, bring it all together. Yeah, so this extending this railway oriented pattern to be able to make choices presented to the user and be able to come back to the same place in the process so you can just continue going along. And I'm going to skip that because we're short on time. And in conclusion, functional programming is awesome. I'm really enjoying working on problems like this I think functional programming techniques are really powerful and allow us to solve more interesting complex problems than we would want to be solving in JavaScript or something like this a lot of the time. Yeah, so over here my, you can see my Twitter and my email. Remember my name Graham has an E at the end of the name it's got a bit of a little bit unique that way. Yeah, and I'm also looking for work. So if if I sound like the kind of person that would be great to work on whatever you're working on, I'd be happy to hear from you. And I think I'm out of time. Thank you so much for coming. You are a dead right you are out of time. We've we've run a little bit over but you've done pretty well. There was one question which I think we will take because I think it's probably quick for you to answer. Kim was asking what is knowledge type. Oh, oh so a knowledge type was something that I created. That is just to say, it's just like a little, a little simple type that's that's saying. This is a function that I might have to shuffle within my code so I might not know what the value of that code is without talking to the Elm runtime. Because if it's if I have to do randomness I have to talk to the Elm runtime. So it's a little way of hiding that I can still use the code, like as if it's the value because I can do mapping over the random generator that's in the unknown. But. But if I'm. If I have to do testing which I don't have access to around runtime, then it lets me write code that could handle the randomness and can also be testable at the same time, as long as in the tests are restricted to things that aren't going to have randomness. So that is the end of the session. Again, thanks Graham for for sharing your insights there your experience creating the game and the problems that you were solving in the process.