 We're here for the thing where we do fun stuff with Elm and Phoenix and music and collaboration then you're in the right room and if you find yourself in the wrong room stay anyway it'll be fun. So before we dig in a little confession, I have a problem. So I have a pretty lengthy history of talking at conferences about other languages than the one at conferences for. So for instance in ancient Saudi Arabia I talked about Elixir, at the first Elixir conference I talked about Java, only a little, at the second Elixir conference I talked about like building your own language and a little bit of Angular which I do not recommend. And so of course this year I'm going to talk about Elm. Not exclusively we'll talk about Elixir and Phoenix too so don't freak out but we'll spend more time on philosophy on the Phoenix front than we will on super interesting code honestly, more about like things to think about. So let's talk about collaboration. The easiest way to describe what collaboration is is like multiple parties are editing and viewing some bit of shared state together. In this case we're doing collaborative music but the fundamentals are the important things so here we've called the shared state in this picture a thing that Alice and Bob interacted with but that thing could be a document or a game simulation or some database tables but I think this one's really silly to think about because the database tables should be an implementation detail right so they shouldn't be collaborating on database tables almost certainly unless it's an application for interacting with the database. Like we're doing other stuff they should be talking to some other abstraction or as is the case today it could be some music. So there's our motivation and let's talk about how we're going to cover it. So we'll kind of have a speed reading discussion of kind of fundamentals of collaboration so we're going to talk about how it's fundamentally just like multiple parties working together on some shared state. So we didn't mention real time there, we didn't mention like the web or web sockets or any of that right. So Phoenix gives us channels and so because of that now it's easy to do collaboration where it was hard earlier right because WebSockets. But you don't need WebSockets for collaboration, you don't need WebSockets for Phoenix channels, you don't need the web to write collaborative software, you don't need real time software if you're writing collaborative software you don't need AJAX before AJAX existed I had some creepy quasi real time collaboration in some apps that I wrote in VB6 no kidding that depended on hidden iframes and like that all just worked fine. So this isn't new honestly and like normal CRUD REST interfaces are collaboration right what you're doing is you're collaborating on some shared data model just not real time-ish and there's a lot of header overhead for HB request but most collaboration doesn't have to happen really quickly so that's why you don't need WebSockets for a lot of stuff but if you want to do stuff and you want to get like notifications quickly about things that changed and you expect to have lots of messages going quickly then it should be nice to avoid all the header traffic around like the HTTP request that's really the only reason to care about WebSockets honestly like there's the bidirectionality and there's that so if you find yourself thinking I can do this thing now because of WebSockets probably you already could do that thing yeah so what's nice though is that Phoenix channels make it easy to do collaboration so like that may be at odds with what I just said but the whole point is they do this by providing a really nice abstraction and this abstraction could have existed way before WebSockets or anything else like that so it's not a massively important point but it's something I felt like I should mention because I've seen a lot of people talk about like now I have WebSockets so I can build all this stuff but like I was building that stuff before I had WebSockets so that's not right and if you think about it that way you probably will make a lot of mistakes that lead to unhappiness down the line so yeah so we could do HTTP streaming as of 1998 when the 1.1 spec was like not finished but kind of mostly finished you can do HTTP streaming and HTTP streaming plus TLS has basically the same unidirectional performance characteristics as WebSockets do you have the same HTTP setup for the upgrade with WebSockets as you do for streaming and then everything else is just messages down the wire so it's basically the same the only difference is like when you're sending messages back up to the server you're doing it through some other channel and there you have some header overhead but the point is like we've had iframes since 1996 we've had HTTP streaming since 1998 we could have been building this stuff that people think like ah cool I can build it now we could have built it for a really long time but people weren't and that was because there weren't good abstractions and there weren't things like the beam right so like we know that to do this actually you want to have a lot of processes out and running and if that means you're writing a thread pool you're probably not going to do it because it's unpleasant anyway so when you're extolling the virtues of Phoenix always I bring this up I think it's better to talk about the abstraction than it is to like jump to WebSockets because otherwise I think it misses the point so now let me give you a dumb story that gives some good insight into what it means to not think properly about the problems around doing some collaborative thing we had a at the time potential customer they did come on board as a customer when I ran a consultancy get in touch with us because a contract that was doing some other work for them they had mentioned a few like little problems they were having and he appreciated the like the corner they painted themselves into and they didn't so he told him to call me because he knew that I would be mean and that it would make their lives better so they said to me we have a small bug has anyone ever said this to you and been right like ever yeah so at any rate they didn't know that their problem was hairy so as they explained what they were doing I kind of started to freak out and I started to point out that they hadn't really likely addressed the concerns inherent in a distributed system to which they reply that I was being a little bit dramatic because this is not a distributed system you're missing it Josh like we just have a couple of people doing stuff together on the internet so ultimately it was like two people that two people it was a distributed system though and it had exactly those problems so they're interacting with some shared state in a customer service like quoting app for this solar thing solar panel installation thing and it worked really really well most of the time but every now and then like the state would get out of sync between what the CSR was seeing and what the customer was seeing and so this is just a little bug to fix right so when I explained that these weren't like little bugs but fundamental misunderstandings and how they built their application and in fact they had to throw it all out they got real sad but eventually they ended up with really solid products so the point is you have to think about these things and just using channels is not having a plan we have to build systems that are designed around the collaboration from the get-go if we want to do it or else we're gonna have the same problems even though we have a lickser right so I wrote a lot about like Leslie Lamport and total ordering and happened to before and Lamport timestamps and vector clocks but a there's not enough time and B I would probably butcher it if I actually said it I'm glad to talk about all that stuff later if you want to talk about it but the point is there are all these things that you should know about if you're building a distributed system or at least you need to know that it's okay to ignore them for very specific reasons and my example we ignore them for very specific reasons which is nice because it makes it easier to give the talk but one way we can sort of see the problem is like in a chat log so the chat log is the 10 I say the chat log a chat is the sort of traditional channels intro right and a chat you can think of it as like this thing where you're talking to each other but really it's collaborating on some state the state that you're collaborating on is the chat log like the stuff that happened historically and so in general almost every phoenix chat that you see the example is not not like the stuff isn't really serialized so like there's not a thing that owns the chat log so much like the database does right it owns the chat log pretty much but generally in all the examples that I've seen when you post a chat like you also show it in your interface right but if somebody else posted a chat and that one made it to the server before you then your interface doesn't reflect the true ordering of events right so you would show your chat here but happening before the other guy but the chat log on the database which is the you know canonical source of truth disagrees and mostly we just kind of hand wave about that and ignore it but the point is to get it right you either have to have something like hard like Paxos or raft or something or you need to have like just this one thing that owns it all and tells everybody what's what anyway so I'm gonna skip all the really confusing or hard to talk about things with collaboration but I'm glad to talk about them in the hallway if you want and you can tell me how I'm wrong about them but we will go on from there we'll talk about an application that I built in Elm and Phoenix it exists as a kind of like introduction to doing real-time collaboration with these two things that are amazing and the reason I wanted to give this talk is because I'm really really happy when I write phoenix and Elm stuff like super happy way happier than I ever have been before writing software so this thing is called a colluder you can get on github it's right there I'm neuter on github because I thought that was really funny when I was 14 and would you go with it so some of the stuff was in a feature branch till like late last night so it's all in master I was hiding it from people because I didn't want people to like jump the gun wasn't really well hidden feature branch but anyway so it's an happen two parts there's like the own piece which is the front end it's the place that my initial data modeling happened which was maybe weird for me because normally I would have like just built something in elixir and then like made the front end do it and then there's the phoenix piece which is an umbrella app so I've been really really happy and with Chris's talk the talk I just saw with Gary a couple of the things where we seem to not be falling into the trap of let's just put all the business logic in our controllers and everything will be good really happy that that's not where the community is going so just wanted to say that makes me super thrilled anyway so the point is this is an umbrella app and I'll sort of talk about that a little bit yeah so I'm on a bit of crusade to bring these two worlds together they're really awesome apart they're doubly awesome together so when I was getting into some depth on this project and actually kind of like the hard parts of this project it inspired a tweet from me that expressed how I felt pretty well so I want to do something I kind of hairy and it just worked and it was how I'd always dreamt programming could or should be so yeah I am absolutely full-on fanboy for both elixir and phoenix and Elm they are freaking awesome and they make me happy but it's because they make my life as a programmer better it's not just because like I don't know I drank some Kool-Aid I don't think because I built substantial stuff in them so if you take nothing else away from the talk like fiddle with integrating Elm of your Phoenix app see how you like it on a mild sales related note I saw content at daily drip showing you how to do that all right so let's demo the app in just a little bit but first I want to talk about Elm so here's a higher level overview of how Elm applications work and so it's a picture and maybe it's squirrely and confusing but we'll talk through it so the thing in the middle is the Elm runtime and you can basically just kind of ignore it for now so the whole system like all of an Elm application works basically strikingly like a gen server so in the white boxes you see there are some types so there's model and message and these are the types that describe your system so like the messages would be like the kinds of casts that could happen in your gen server and the model would be like the state of your gen server yeah so that's all and then there's those green boxes are four functions you create so there's an it which produces your first model like this isn't it from gen server we know it update which is like your handle cast pattern matching all these different messages you have the view which is a pure function from your model to the way your UI should look and then you have subscriptions which is just like stuff outside of your user interactions that you would like to deal with so for instance timers or web sockets or something else I don't know anything else that you didn't initiate that came from the outside world so from there the Elm runtime wires all these things together for you so when a user interacts with the view she might produce a message and so the runtime gets that message and then pushes it and your current model back through your update function and then you give it a new up a new model and then it sort of replaces that under hood and then your view renders so that's that's sort of how it works sorry same thing with the subscription subscriptions so yeah all these things are like strongly isolated the thing that's really interesting is if you look at the model comma command message that's a two-tuple so your update function returns two things completely separately there is this is how I want the state of my application to change and then there is gosh it'd be nice if something happened like this outside in the real world so that's those commands it's like data that says it'd be nice if like an HTTP post happened but you're not doing it because Elm functions are pure so you can't interact with IO that's why the runtime exists honestly you tell the runtime like it be great if somebody would push this to that HTTP endpoint and then it does it and it tells you how that went but you didn't ever do anything in your functions that was impure so that's like really nice and in this whole description I didn't have to say the word monad so that's like one of the primary focuses that Evan puts into to Elm and I think it has I think it pays off a lot anyway so now you totally understand how Elm works from top to bottom so let's have a look at the Elm side of colluder which is the name of this thing so I built this thing so you know it's not like the end of the world so I wanted to build something like that for really long time and it's not like it was hard really like I it's not like I couldn't with existing tools but I was completely unwilling to because JavaScript so I don't know if you know this but JavaScript horrible it's like the worst thing so like I could build it and I built very large JavaScript things and people paid me money and they paid us a lot of money because they paid per hour and we had to deal with JavaScript so it took a long time so that part was good maybe but maybe not so great for the economy and certainly not so great for my sanity so when I like I had this toy and like nobody's paying me to build this thing I just kind of wanted to exist and like I would go to do it some weekend and I would be like yeah let's build this this toy and then I'd open up a JavaScript file and I feel like you know what I can do my taxes instead that's better so it never happened and then with Elm like I didn't have this concern at all like I was excited to do it because it's not JavaScript and it's a it's a good language it's really one of the best languages I've ever seen anyway also there's the collaboration piece so before Phoenix like doing the bit that you haven't seen yet where like multiple people can work on that same music at the same time I guess not a fun thing I could do it with like any of a number of bad wrong ways in in Rails and like they worked and they were fine but they didn't scale like I built actor model based systems in Ruby that had lots of users and they generally were pretty good until I had a spike of traffic in 5000 users and then bad stuff like 5000 current users and then bad stuff happened and I didn't want to do collaborative stuff that fell over in that way unless I took like extraordinary pains to fix it so Phoenix fixes that it's just it just works it's awesome so yeah these two things together made it where instead of being really uncomfortable about building this thing I was excited so let's look at how the Elm app is built and we will get to some some elixir code I promise so all Elm apps tend to look the same at the top level so they look kind of like this so we have some module named main it exposes all its functions and here we're starting a program and we just give it the initial state we give it an update function we give it a view function we give it a list of subscriptions or really we give it a subscription but anyway and that's it and it wires the runtime wires all those together for us so let's talk about model because this is where I start like when I'm doing Elm stuff and this is where I found it interesting because I did model my my problem in Elm instead of elixir whereas historically I definitely would have done it elixir first so okay so I have some types song is a dictionary with integer keys and tracks for values like realistically this probably ought to be an array instead of an integer keyed dictionary there I might can justify this design I'm not sure I was basically future proofing against something that I still haven't run into but I think I would because I haven't yet allowed people to delete tracks yeah anyway not important to go into the point though is this is a really squirrely data structure and it'll probably come up later track it's just a record containing a note so each of those things across on the user interface you just saw was a track and so like there's the note it plays and then there's some slots and the slots are just another integer key dictionary of true false of bullions yeah so that's basically it for what a song is and then we have our model so like there's all the other stuff that goes into building us a thing in the browser so like the top fields there there's a lot of stuff that just helps us figure out if we've successfully initialize an audio context in the browser with web audio and whether or not we can use auger we have to use something else it has just a single field here that's holding the song which is like the core data structure we're working with it's got a few other things like it knows where it like the current note that line that was going across as it played that's all that was it's just saying like here's where we are in the song total notes probably shouldn't be in here it should derive that from the song but it's there paused you know are we playing or not and then the beats per minute like how fast are we playing and then a few other things that don't really matter and then those bottom two are really dumb and we'll talk about those in detail later so when you saw me building like the little dialogues to pick the note for a given track it was doing some stuff that tweaks these fields but that ends up being really stupid but we'll talk about it later so anyway and then like that's the type and here's what the initial model looks like so you can basically as you this is not that surprising right you saw the type you mostly kind of could figure out what this stuff is going to be except for you know what is material that model who cares okay so I pre-populate like the song I give it two tracks they're both this fifth octave a notes and they have 20 false slots it's not on but it's 20 slots long so that's super super easy it's a mutable right I have an empty dictionary I insert a track with key 0 insert a track with key 1 so that's it now we have a model it's important to be able to do stuff to your model right so that's where update comes in so elm is a mutable language you can tell it's a mutable language because if it weren't I wouldn't use it or talk about it or tell people to use it so yeah this is ultimately has the same trick as a gen server for updating state right which is just you loop on yourself so you can think of it as continuously the way that I like to think about it which I did not think about it this way with gen servers really until I got into like more more deeply in the functional programming is like a fold across all the things that happen in your application with some initial state right through some function that modifies that state so however you want to think about it I find that is a fun way to like feels more appropriate for me to think about it rather than like oh like I'm recursively calling this function feels worse anyway but that's not important and so an update takes a message in a model and returns a model the message is just like your handle like your event that you're handling in a cast and your gen server so what kind of things happen in our app a bunch of stuff this is awful and big and flat and it might seem overwhelming so I'm gonna break it out in a few different pieces but in fact it's not that bad to have a giant overwhelming looking flat list like this if you play with elm and you're like aha I will start organizing day one you're gonna be sadder than you would otherwise okay so here's the web audio bits I cribbed this from an existing open-source project they got me like to sound font so the audio is sound font MIDI sound fonts playing via web audio that's that's how it was making noise so this part gets me that and it's basically a few things that lets you talk back and forth to some ports that are happy like in JavaScript land that set up some stuff for you and supports are how you interact with things outside of your system right this is a normal feeling to us in lixar that's what we do we have ports if we want to interact with things outside of our system so one really cool part of ports in elm is that they have a thing called border control so elm is super strongly typed right that's not there's no dynamic typing at all so border control says that like when JavaScript tries to call into one of these ports to send us data if we say we get an integer on that port and someone from the JavaScript side sends us like a string like boogie I don't know they fail on their side like they can't get stuff through border control so we never have to deal with that situation like you never deal with well what if the data isn't what I thought it would be so there's no defensive coding anyway so the whole point though is having plumbed stuff with this little bit of stuff that happens we can make noise in the browser so then we want to talk to phoenix and I'll show you this bit a little bit later but we have a message that tells us to connect to the socket so this is like an event that we say like it should be nice to be connected to the phoenix socket and then that phoenix message bit is how we interact with this elm phoenix socket library that handles all the socket stuff for us so you don't have phoenix sockets work you have the there's like this ref that has to be different for every command that you send because you need to it's asynchronous but you want to combine like when you're on a channel you can reply to a message but it's all async so you have to have some way to tag the reply and so that's what that whole thing is for but it turns out that's like stateful so it has to be a piece that handles it and so this library handles that bit for you so you don't have to think about it and then we have this like receive statement so this is where we get a song back from the server it's a j something coded value and then yeah so this is how we handle that so I built a thing called that supports phoenix presence it's a library I'm still trying to get it merged into elm phoenix socket it's since like two months old now at the full request I don't know why it's not merged yet I'm probably gonna anyway pointed you can do you can do present stuff too but we're not doing it in here so the actual app that you saw doing stuff is basically this bit so we have a tick that happens based on the models beats per minute and that's what moves us on to the next note we can check a slot on a given track so when you click a track that's what happens to do that we have to say what the track ID and the slot ID are and we have to give it a true or false like a Boolean so this is what one of those messages is right has these three values and these are this is like a union type or algebraic data type if you hear those words that's all this thing is and it's really fancy way of saying like there are only certain things that can happen it's not not hard and then like you can add a track you can set the beats per minute you can talk whether or not paused and then those last three bits again are the really dumb thing that we're gonna fix later that handles that kind of wizard view and then that brings the update function so can everybody see this okay we'll look at it piece by piece and I'm gonna go real fast so the first thing is notice that I lied to you earlier I said you got a message in a modeling return to model but really we're returning the to double right the model in the command message because we want to do stuff in the outside world we want to interact with WebSocket so we have to and we also want to interact with JavaScript runtime so we have to have kind of this to double version because otherwise we're completely pure and we can't do anything with the outside of the Elm runtime anyway and so this first basic bit just like initialize an audio context there's some JavaScript that sets up a graph using the Web Audio API make sure we can use all this bit's kind of boring to write it just loads the web fonts for us so we'll skip that bit but you can kind of see what this is right just update our model every time we get one of these events or we send something out so that actually I will point that out so like most of these I can't point but that top one right it updates our model it doesn't send anything out the next one doesn't do anything to our model but it does send something out so a lot of times there's this like segregation where you're not doing you're doing one of the other I find this compelling but you can't always do it without feeling like you're making stuff hard on yourself for no good reason anyway so now we get the UI messages so if somebody clicks the pause or play button we toggle the models pause to feel cool like just not model up pause that's all that looks like when somebody says the BPM we just set the BPM to whatever they sent us and then we have the subscription that's happening in the back end so like every time dot minute times the interval we send a tick message to ourselves and that's what moves along the simulation and so like if we're paused we're just not sending that subscription across so I find I find this interesting anyway and so we get our tick values and when those happen we call out to update notes which is a horribly named function all that it does is literally like some mod math on current note it probably shouldn't be its own function I don't know why I did this and then once we've done that we request some notes we get all the notes like based on where we are in the song we find out hey like are any of the tracks on at this point in time and if they are cool like will you play that note for me that's all this does and that gives us a song playing thing which is cool and then like when a user clicks a slot we have to trigger things so we go do that we update the track with a new slot when they set the note for a track we update that track to play that MIDI note when you add a track we have a new track which generate one with the right size and slap it on the end and this is the wizard bit so like when you click on like the A5 or whatever it sets this editing track and because an editing track is set to something just something rather than nothing as a maybe then it shows that first dialogue and then when you click a thing it sets the note and because that's set it shows the second dialogue but there's not like a connection of these things in the data model which is which means it's possible to do buggy things and we can get around that later anyway and finally once you actually choose your octave we have all the three bits of data that we needed so we send the real message that we cared about which updates the model and then this part's like squirrely and ugly looking right God help us this is big and like I don't like it and this is because of the other stuff I mentioned that we're going to fix later like there's just all this stuff that sucks a little bit about this but what's nice is in Elm every expression sorry every function has a single expression there isn't it's not an imperative thing there's one thing you do and if you wanted to do some other stuff you can't really do it imperatively what you can do is like have a let expression that lets you set up some things to set variables but they're not done in order or anything it's you know it's it's you're not going to be able to do kind of imperative coding in Elm at all which is nice it's all point though is we needed these three values and we had to get them through these other real squirrely places to build this up so this brings us to the Phoenix socket connection bit so when you say hey I'd like to connect to a socket we create this new data structure that represents our socket we get an updated version of it we have a command to send to our runtime that like actually does the connection bit and we tack on basically this callback thing that says look when I get a collusion state back just receive that state and that'll give us a new message and we'll keep moving receive state basically we try to decode it if we can't decode it I'll log it to the console and don't do anything or I don't update my model but if I could decode it then I got a song back so I replace my song so this is the bit where we get to ignore all the hard stuff about synchronization because we're serializing access to this thing and so basically we replace the song entirely every time somebody sends anything and we send it out to everybody so this is dirty this doesn't work for all kinds of things you might want to do so like if you're making a game like quake or something like you can't send the whole state of the world every tick of the game to everybody that's an awful experience but if you're doing the song it's okay so I get to like hand wave the hard parts but you get a good experience when like with this setup I've been able to like think about those hard parts a lot more simply than other times I've done stuff like this outside of Elman Phoenix anyway and then if some other messages come in from the Phoenix integration like a heartbeat or whatever they get tagged by we basically pass them down to this other component that we don't care about that we were given and it does the right stuff then we get to the view and I'll kind of go through this somewhat somewhat quickly so your view as I mentioned is a pure function that translates your model into an HTML tree and the user can produce messages in your application by interacting with it so this is the function that handles like the primary middle part of our view so the bits above are just managing some like header we don't show those and doing some material design wrapper stuff so here we've got some basic styles we're injecting and then you can see the pieces of our application that are rendered as children of this parent div in a list so we'll see those with a screenshot so we view metadata that's that top bit the top controls are the pause and BPM bit the song editor is that piece with the tracks and the ad track and then the connection is that button right and then I kind of don't show the dialogue yet so view metadata super easy I just wanted to show you what the stuff looked like right so this is just generating html it's a div the second argument is like a list of attributes the third thing is a list of children so this just has a text notice child and it shows that stuff that's I don't think this is terribly hard to read the hardest thing would be like syntax little syntax things about on that maybe feel squarely like the fact that space means apply a function so then there's some more UI components right the top controls these might look kind of squirrelly because I'm using material design so like you're like whoa there's like six lines of stuff to make a button why but reasons is why but it's not uncomfortable like this is very pleasant to work with it's way better than like untyped HTML just like I will type some text and then later on I will find out that it was completely invalid according to the W3C but I won't care that's not really a thing for the most part here and then there's like the song editor so I kind of tracked it out we have a table has a row for each track in our song and it has this add track button and so we just fold across all of our tracks to produce the TRs for the table this is what a given track looks like so again we have this metadata bit up front that lets you change the song the note but then we just fold across all the slots to produce the TDs of the row and then this is what a TD is basically so if it is the currently playing note it has this kind of black bar on the right if it's checked it's red and yeah we just apply those those classes to this TD as we produce it and then we have like track metadata this is the button you can click so when you click this it says okay I'm going to set the track that you're editing so we do that and now we have this view dialogue function it says look if there's a track being edited then when somebody views the dialogue they should see this track note chooser and that looks like this and it says well if you already picked the note then we'll show the octave dialogue but if you haven't we'll pick the note dialogue and this is kind of a bunch of like stateful wizard stuff that is not defined strictly this is just like I happen to know that this is what I want to happen but it's you know someone else coming in wouldn't understand necessarily that that's why these things happen so this bad and we'll talk about it like I mentioned later but I just want to just see all this stuff so the note dialogue we make some buttons for each note each one of those going to emit some message the octave dialogue same same sort of deal and then there's this beat that lets you click and it will connect to the back end which gets us to the phoenix channels so that first bit was all me proselytizing for elm really hard and I thought it was worth doing because last year's elixir conference where I really really got sold on elm in the one of the keynotes and if a single person leaves here today thinking they want to give elma try I feel like I did a good thing and they got their money's worth out of the conference but now we can talk about the phoenix application so I think that I mentioned that Chris's keynote was awesome because I think it's what phoenix needed to help people not fall into the rails as my application trap in phoenix so I want to kick this off of the preface I'm pretty dumb I used to think I was smart and it turns out no so I'll show you why that is I'm constantly telling people like beating this drum about rails is not your app phoenix is not your app whatever so I want to start the collaboration part of this application and imagine my dismay when I saw what I had done I typed these lines right here and I made this commit and I felt good about it for about 10 seconds but like look here we want to make it possible to have some music editor that's collaborative so I'll be like clicking around a bunch and so will you and all the stuff will be happening and any updates gonna have to wait for the database to persist if we do this but also I never said I wanted to store this stuff in a database I just kind of did it because I was on autopilot so there's nothing relational about this data it's a big blob that makes up a song so why did I use a relational database to store and the answer is because I'm dumb super dumb and I shouldn't be so I killed this with fire and replace with an umbrella application and so here we have two things I have that top bit which is collusions which is an OTP application that manages a gen server and like some supervisors for doing like song collaboration around a data structure and then we have this OTP app that has no views has no ecto know anything it just has a channel for sending messages into the OTP application so yeah that's nice so here's the same state that we had in the home application but ported to elixir and I'll run through it fairly quickly but this all looks like right so it's got the awful data structure where we have keys that are integers in a map but whatever and then there's this gen server that wraps the state once again everybody can read that right okay so it's a normal gen server like we register it when we start it we so we have a name so when somebody tries to start a song with a given name we started if it didn't exist but if it did exist we say like sure that work guy but we give them the one that was already running I don't know if this is smart but it works for me we get some state out of it so like I'd like to know what tracks there are how many there are and honestly all this stuff is really just so that I can write tests and then you can do all the stuff that you could do with our messages right you can set a slot you can set a note you can add a track and then you can get the state because it would be nice for us to be able to tell people what the song looks like and so I think that the fact that these things map so perfectly to the message that portion of the messages is kind of why there's like the a lot of people in the Elm community are like why are so many elixir people coming in because shouldn't we be using Haskell on the back end and like maybe but not me so I think I know I think this is sort of the reason that elixir people feel so comfortable with Elm because we know gen servers and it's kind of the Elm architecture and so like our server API looks kind of like we'd expect we handle all these things and we do some stuff and it's not terribly important you could sort of figure out how to modify the state I just wanted to show it for completeness a little bit more it's a little lengthy but it represents everything we do to do all of this stuff so we'll recap what we saw before we had an Elm application that didn't need stuff with music we've recreated that data structure and all the individual actions and we made gen servers that can manage the state for one of those things and we made channels that can I haven't done the channels yet that's what's next oh one more thing there are tests I think tests are super important I'm not going to show them now but you should know that I wrote them and I wrote them first because I'm not a monster so now we have the gen server we'd like to be able to modify it when you make changes in your Elm application and so our cast map one to one of the messages in Elm so if we just like send those messages across when we do stuff then it'll work right so again our app is the gen server it's not the phoenix bits but the phoenix bits are what enable us to do this part so the user talking to and hearing from our app over web standards that's what phoenix is for that's what a web framework is for the web bits so we're gonna slap a channel around the gen server so here's the general idea they're just an interface to our gen server they embrace it they mediate access to it but they're not yet so here's a quick channel it has stuff that you would expect when you connect to a channel we start it and you know if it already existed then we act it like we started it when you send us these sort of we basically define a protocol for the messages you can send across the web socket or across the channel and we translate those into the function calls on the gen server and so this is you know I'll show it all for completeness but you can go look at the repo if you'd like to see how it works so let's see this in a demo for Reels I've got it running on ngrok and I'll visit that it's right here you can all hop on it if you want and I guess you're gonna have to get out of my browser here all the second after this and then I have to do this and maybe make you big okay so there it is and we'll just unpause it real quick and you can do stuff right so if somebody wants oh one thing you have to click connect to back end okay so yeah yeah people are doing stuff so now you can go through and you can like change notes and edit this thing and it all just works and it's awesome and in general if you have a really basic data structure this kind of thing works right so play I don't know so like I've wanted to build this for a long time and it was not hard at all and in the past it would have been kind of hard and I would worry about like all the collaboration bits and I didn't have to because like Phoenix and I don't know it's kind of awesome to build this code I think whatever and this is huh there's a rate limit okay we've been rate-limited that's fine so anyway so yeah the point is it's really fun to do and I will now go back to this bit if I can find it so anyway but this is dumb right I'm sending the state every time anybody does anything I'm sending the state to everybody and so this might work with songs that are like 40 or so bullions but what about some complicated state don't you want to just like send a diff or something smart and the answer is like totally yes you do want to do that don't do the dumb thing in general it works for this that's why I'm showing this off but it's not really hard right so you have like this gen server bit and it can know what a given connected client knows about and what it's seen and so you just have some algorithm there that figures out oh like these are the diffs that I need to send you and you could even figure out like well I really need to send you like six messages but I know that that would be more data than sending you the whole state so maybe I just send you the whole state this time so the point is you put that stuff there like in the channel put that sort of algorithm there and it has no relation to the rest of the app right that's just the part for communicating the diffs but the interesting thing is you can do all that because you can think about your application because like it's sort of broken out also quake world so quake world is awesome if you want to do any kind of like collaboration stuff like probably how quake world came to be because it's really neat that's actually what I'll be doing for the next month anyway but the point is this is pretty cool and yeah a few other tiny things I mentioned repeatedly that that wizard was awful so this is something that elm taught me that I hadn't learned before and so this that you can make invalid things impossible to represent so before I could have had like the second step in my wizard set but the first one not set so if somebody forgot to update that correctly then I'd have like an invalid state my wizard and not what I wanted the user to see but it would type check right it'd be correct but buggy so we don't remember this is what that looked like it was a couple of maybes and we kind of inferred from the maybes like this other stuff like this bit right here but why did we have to infer it at all because we're the ones writing the code so instead of those maybes with state that's like intermediate that I don't actually care about I can have this so there's a union type for the note-chooser wizard it can be either pending or that can be a track being edited or they'll be a chosen note and then I just store that on my model so I'm not storing intermediate state I'm storing the state machine right and then it's impossible to set it to an invalid state because there's not an option like those are the only three things that could be and none of those are an invalid state so that's pretty good and so then it kind of like this stuff is still pretty straightforward this this bit gets a little smaller still a little bit wider than I want it to be because of that sort of may be there and I can fix that one of the things that like when we come back here I had a couple of people when I showed this to them go ah yes use monads and it'll fix this but go sorry this is the wrong slide say I use monads and it'll fix this issues like maybe and then or something and that's sort of right but the whole point is it misses the point the point is I can make it impossible to make an invalid state so it's not about making this code easier to write or easier to read it's about making it impossible to do dumb things later down the road and so that's what this whole pattern gives us and I like it so now I can't make some unreasonable state for the UI and I find that interesting but that's really all I have thanks for listening if you get nothing else out of this play with Phoenix and Elm together come talk to me I will proselytize even further so thanks very much I could you talk a little bit more about boards I'm still a little confused how you get an elixir and Elm to talk to each other oh so you break out on Elm so ports for Elm specifically are about talking to I'm gonna say JavaScript because that's really a front-end language right now but so they're about talking to JavaScript so they're about providing this nice boundary where when you want to do something in JavaScript you can have two things in Elm you can have an in bound port or an outbound port so an outbound port is basically I like to send some value out that maybe I can't maybe I don't have a library that I want to do something with in JavaScript in Elm but I do in JavaScript so I send some value out and then I subscribe to that port on the JavaScript side and so anytime a value comes in I call some function of that value so that's what outbound ports look like inbound ports are and the way that it works is when you embed your application in the HTML file you have like some var app equals Elm dot main dot embed or whatever and so now you have an app and it has like app dot ports dot any inbound ports that you can call and any outbound ports that you have a subscribe function on so you can just say I got to subscribe to this port and do stuff with it so does that answer the question okay and then like on the inbound side on the Elm side they actually come in as subscriptions because again they're kind of stuff that happened in the outside world that you didn't initiate and any of that stuff is a subscription any other questions great job when you put up post sorry you put up a slide saying I love Elm and Phoenix and there was something in the middle is that like the library that kind of helps you to bind two together which Elm Phoenix socket that show that oh Elm MDL okay yes or no that is completely unrelated to Elm to Phoenix that's literally material design so I use material design stuff in here so the thing that helps you bind the two together is called Elm Phoenix socket and yeah so like that's that Elm Phoenix socket is this guy up there in that picture but yeah basically it makes it very easy to interact with with the sockets from a pure Elm library and it just works that's good okay I think it's time for luck thank you very much