 Hi everyone. I am super thrilled to be here. I'm especially thrilled to be talking about Elixir in LA and to in like such a cool venue also. This is probably the coolest venue sitting that I've ever been in. I don't know they've ever given a talk under a disco ball. So thank you first like thank you to all the organizers. I think they've organized like a really great day for us. So yeah, very exciting stuff. But yes, hi I'm Emma as Desmond said. I am based in Los Angeles. I work at a startup, a sports tech startup based in LA at Second Spectrum. It's called Second Spectrum. It's very close to here. It's in little Tokyo just up the street of a few blocks. And so what we do at Second Spectrum is we do a lot of work around both capturing data and then also passing the video capture through machine learning and computer vision layers to be able to derive certain insights from that video capture. We're currently the official optical tracking and analytics provider for the MBA. And in addition to that we build full stack data visualization platforms that bring our advanced analytics data to life for coaches, leagues, and media broadcasters. A lot of the work that we do on the full stack apps team requires our products to have reliable uptime, be able to serve a lot of users, and also be able to process a lot of data. So we've been using Elixir and some of our products for the past couple of years and we really come to love the language for a lot of reasons. A few of those reasons at a high level. So the language features themselves, the tooling that comes with Elixir, and the legacy that it inherits as a descendant of Erlang. And so I should pause here and say that as I was putting together this talk initially I was prepared to just talk about these things in greater detail and kind of give you the pitch of like why Elixir. And I think it's important as a community that we continue to reflect on why we love this language, what the benefits are, so we can share this with other people. And so I think that is a perfectly fine talk, but as I started to think more about some of these things in greater detail, I realized that for both me and the team that I work on, one of the reasons why we've come to love Elixir so much and a common trend across some of the details of these individual details was that the language really reflects the realities of the world we live in, rather than say an idealized version of it. And in particular what I mean is both Elixir and Erlang deliberately provide a language that accepts as a fact that sometimes things will fail. And to live in a world like this means that we have to design systems that can account for these failures without everything kind of like halting to a crash. And so being able to design these kinds of systems will require a language that prioritizes this, that accepts as a fact and does not sort of make us have to think about creating systems or things that cannot accept failure, cannot error. So one example of this that comes to mind that we'll go into like unpack a little bit more, but we'll just kind of discuss as an initial example is the feature of immutability in Elixir. And in my mind immutability is at its core about is about having a particular philosophy on failure, that is that the role of the mutation of data has in introducing error. So that's kind of what we're going to be talking about this morning. I kind of covered at a high level some of the things that I really like about Elixir, but I haven't gone into much detail about that. We will explore some of those details. But really what I'll be talking about this morning is taking us through this journey of what it means to embrace errors as a reality. First considering how this idea sort of sprung up with Erlang and the history of the language. And then considering the additional ways that Elixir is able to build upon this philosophy of embracing error and failure. And then because I couldn't possibly turn up, oh yes, yeah, I can make the slides available after the talk. Yeah. So yeah, so we'll cover some of the additional features and tooling that's available in Elixir. And then because I couldn't possibly turn up an opportunity to plug Elm, which has become quickly my favorite front-end language, I'll talk a little bit about some of the ways that I think Elm also embraces this philosophy of embracing errors and what we can learn from from Elm as well. And then lastly, when I think about some of the implications of what it means more broadly to embrace errors, what we can learn from what these languages are doing in embracing an error-prone world and what we might be able to take away from that into our lives in general. All right. So I'm going to start off with this number that I imagine many people in this room have seen who's seen this number before. Yeah. Okay. So this is the cell for Erlang, right? So this is 99.9999999%. It represents the uptime of the flagship product, the flagship Erlang product, AXD 301. It was built by Ericsson where Erlang was originally developed. And at the time that this was reported, I think in 2007 by Joe Armstrong, one of the people as part of the team that built Erlang, the code base had over 2 million lines of Erlang code, which is pretty impressive. And it had been in operation for 20 years. So let's put 99's reliability into the context, right? So, you know, typically we consider five nines to be pretty good. And that amounts to 5.2 minutes of downtime per year. Seven nines is considered by some to be nearly unachievable, but they got nine. Nine nines. So this is pretty stunning to kind of do the math to sort of see how incredible that is. So over 20 years, 365 days and a quarter. In a year, 24 hours in a day, 60 minutes in an hour, 60 seconds, so on and so forth. That comes out to under a second of downtime over 20 years. And again, like, yeah, I heard a wow. It is incredible, right? With just over a little bit over half a second of downtime over 20 years, this is like fantastic. This is like the way you sell this language, I think. And I remember when someone first told me about this number, I was A, I did not believe them. But yeah, this is incredible, right? So one, I was incredulous, I didn't believe it. But then once I got over my disbelief, the first kind of thought that popped in my head was how could this be? Like how could a system that's been around for 20 years fail so rarely? Or how could I have so few errors? And the more that I learned about Erlang, what I realized was that was really asking the wrong question. What I realized was this number isn't a reflection of a language that prevented or avoided or tried to live in a world that was absent of errors, but one that recognized errors as a matter of fact in the world that we live in. Errors are unavoidable. So how do we build systems that can accept that world? I think this is really telling when you consider the title of Joe Armstrong's 2003 thesis where he describes the background of how Erlang came to be. The title is Making Reliable Distributed Systems in the Presence of Software Errors, not despite not trying to avoid them. It's in the presence of them. We just accept as fact that these errors are going to be there. In the introduction to the thesis, he says, large systems will probably always be delivered containing a number of errors in the software. Nevertheless, such systems are expected to behave in a reasonable manner. This really stuck out to me because a lot of times when we talk about software development, when we talk about software engineering, we talk about what can we do to make sure that our code is error free and we're going to throw tests at it and we're going to throw type safety at it. We're just going to make sure that as much as we can, our code is just nothing wrong ever happens. To realize that the genesis of the language is coming from a place where these systems were so widely distributed, they were used by so many people, and so the engineers just took as fact prima facie that errors are going to happen. They will be introduced sometimes, and what we have to do is ensure that when those things fail, they can fail fast, and other processes can continue to march along. To kind of understand a little bit more about how Erlang does this and what that entails, we have to sort of dive deep into a bit of history. We're going to start in the 1980s, where at Ericsson, the computer science laboratory that Joe Armstrong was a part of, searched for ways to make these processes of developing software result in more of reliable systems that are both easier and less expensive to build and maintain. That takes us to 1986. In 1986, Joe Armstrong starts working on a language that would eventually become Erlang. The interesting thing that I learned from reading his thesis is at the time, the language started as an experiment to add concurrent processes to Prologue, and he actually wasn't even really intending to design a new programming language when he first started working on this. He was interested in working on a program called the plain old telephony service. At the time, the best method for working on this was to use a variant of Prologue that was augmented with parallel processes, which again, people who have used OTP, this should sound somewhat familiar or sort of a hint to what's to come. What was interesting is that back in the day, 30 odd years ago, there were really only two models for approaching concurrency, and the dominant one at the time was the idea of shared-state concurrency. Shared-state concurrency involves this idea of a mutable state where there's literally memory that can be changed. We can mutate it, we can move stuff around. Languages like C, Java, C++, etc., they have this idea where there's this stuff called memory, and we can poke at it, and we can change it, and we can do stuff to it. This is fine, so long as you only have one process doing all the changing. As soon as you have multiple processes sharing and modifying the same memory, this becomes very quickly a recipe for disaster. Things go wrong really, really quickly. The problem is that all of a sudden when we have shared memory, you need to prevent against simultaneous modification of that shared memory. Once that problem is introduced, how do we solve that? The common fix for that is to have some kind of locking mechanism. Depending on the language that you're working with, you may call this a mutex, a synchronized method, but either way, it's a locking mechanism. Now that you have locks, now you have this new problem. That problem emerges when programs crash in some kind of critical region at a time when they're holding the lock, and other programs don't know what to do. They have been waiting, and now all of a sudden everything doesn't know how to lurch forward. How do developers approach fixing these problems? There are some solutions to this. Transaction memories is one way of approaching it, but at this point, if you've been following the narrative, we've kind of continued to inherit these problems because we started off with this assumption of sharing state for concurrency. A different approach to avoid all of these problems altogether is to approach concurrency from the perspective of message passing. This is the idea that they're pursuing when they're starting to think about how to build these reliable systems over at Ericsson. In message passing concurrency, we just completely get rid of the idea of shared state. As a result of that, any computation is going to happen inside of a process, and the only way to exchange data is to be able to pass messages across processes asynchronously. This ends up having some pretty big implications. Now all of a sudden we no longer need to rely on mutable data structures. If we don't have to rely on mutable data structures, well, now we don't need locks anymore. If we don't need locks anymore, then we don't run into that other problem that we had where if a program crashes while something's in a lock, then other things don't know what to do. All of a sudden, all those other problems that we're having, we don't have anymore. What do we do about parallelization? That was why we were committing to all these things in the first place. That turns out to be pretty trivial if you just think about parallelization as a process of your developer breaking up the solution of this problem into a number of parallel processes that can then communicate. The neat thing about this is if you go to the root level of the problem, you eliminate all the problems that you had before. You don't need to pile on additional Cluj fixes on top of one thing after another, after another, until you get to a place where you're like, wait, why are we even here? Why are we trying to solve these problems? This is the idea of concurrency-oriented programming. He found this blog post from 2007 from Joe Armstrong where he boldly makes the claim that objects are out and concurrency is in. 11 years later, I don't know that we're really living up to that, but something that stood out from the post where he made this claim was he's really pushing for this idea that the reason why we might want to commit to this approach towards programming is because if we think about the world that we live in, our world is concurrent. It is parallel. Things happen all over the place at the same time. How does that happen? We pass messages to one another. Let's imagine this room. I have some private memory. You all have some private memory. Right now I have this private memory of all the stuff that I learned about the history of Erlang and Elixir that I want to share with you, named doing it through light waves, sound waves, and then you're going to take that and you're going to update your private memory in some way as well through some kind of update process. It's say the speaker blows out and you can't hear me anymore. You can still do that. You can still process whatever information made it through. You are not going to freak out and just wait. I hope you don't. So this goes back to my idea or the kind of argument that I started off with at the beginning that when we embrace errors as a consequence of being realistic about how the actual world works, instead of turning away from how reality actually is, we can incorporate these things into the design of our language and that in turn can create something really powerful when our languages are reflective of the worlds we actually live in that can give us a lot of expressive power and in the case of Erlang as we saw, a lot of reliability as well. So while we're on the topic of kind of learning from the world and incorporating that into languages, I'm going to digress for a moment and mention an anecdote that reveals in a different way how important it is for languages to be reflective of the world around them. So does anyone recognize these symbols on the screen? Yes, I saw a hand. What is it? Korean characters, yeah. So these are the five base consonants from Hangul, the Korean alphabet, and Hangul was created in the 15th century. So I'm sure at this point you're like, huh, I came for an elixir talk, but now I'm looking at, we talked about Erlang and now we're looking at Korean. What happened? So let me explain a little bit more. And I'm going to give a little bit of like personal exposition also because it'll also maybe explain why I'm really interested in both programming languages and natural languages. So prior to my career as a software engineer, it's been about a decade as a formal semanticist working on natural language linguistic theory. And it's also how I ended up like learning the love functional programming because I was doing a lot of work with the Lambda calculus and then some days someone said to me, oh, you should check out some of these programming languages. They kind of seem to be up your alley. But going back to Korean, over time as in my career as a linguist, how a lot of people come up to me and tell me, oh, you should check out Korean. It's really interesting. It's really easy to learn. And I usually get very skeptical when people tell me things like that because usually like usability of learning is a very subjective thing. It's very dependent on, you know, what language background you've had in the past, what you can have as a context of comparison. But I recently started learning more about the history of Hangul and it turns out it's quite interesting. So at the time in the 15th century, Korea was under Chinese rule. And so the writing system that was being used at the time was the Chinese writing system. So this immediately posed learnability problems because if anyone here is familiar with the Chinese writing system, there's a lot of just like rote memorization. There's some things where like if you learn like 3,000 radicals, you've learned like 80 to 90% of the written words, but still like kind of a lot of just rote memorization. Simultaneously, what made this writing system hard for Koreans was that there were pretty significant language differences across the way Korean and Chinese was being spoken, that it didn't always make sense to have a Chinese writing system for Korean. This led to kind of rampant illiteracy at the time where a lot of Koreans, especially in the lower classes, were just not given access to learn how to read and write. So and I should say I learned all of this initially from a K drama that I'm pretty sure was just like pop propaganda, but I have since confirmed this on both Wikipedia and people at the Korean Cultural Center. So but so what happened was King Sejong at the time recognized that without some kind of language for the people to bring the people together to create for his people like a unified sense of the Korean culture, they would always kind of be stuck relying on something that also wasn't serving the people. So he had his royal court of scientists think about how they could represent the sound shapes of Korean in a way that lended itself to learnability. And so again as a linguist, as a person who has been always interested in both natural language and now programming languages, this idea of centering learnability, centering certain features in your design of the language kind of really peaked my interest. So I started taking Korean last fall and the end of this anecdote is that it is actually that easy to learn. In two hours I and like 50 other of my classmates learned most of the characters of Hangul and here's why it's so easy to learn. So below each of the characters the image is an image of sort of how that character was derived. It's derived from the actual articulatory features that your mouth makes when you're producing a certain sound. So that first on the far left, that first character that looks kind of like a box that corresponds to the sound mmm. And the idea is that when you close your mouth, your mouth kind of forms a little box shape. And the next one mmm that you'll see there's a line in the picture here where the it's sort of showing how the tongue hits the hard palate at the top and then kind of comes back down in an L looking shape and so on and so forth. So this when I first saw this, my mind was blown because if anyone has taken like an introductory linguistics class, these images shouldn't look that foreign to you. You learn these things in phonetics. You see the sagittal section. You learn about you know where your mouth is forming closures for air and things like that. And so what's been really interesting to me about learning Korean is that all of a sudden there's this like really easy mnemonic for learning these letters. And if you've ever like had to help someone learn the Latin alphabet for example, if you've ever had to help someone learn English, there isn't that one to one correlation. It takes a lot of rote memorization to get here. It takes a lot longer than two hours to get someone to learn all the way from A to Z. So my point for bringing this up is that a lot of times I'll hear people saying things about Erlang and Elixir that because there are such significant paradigm shifts away from kind of the standard way of doing things that's functional, that data is immutable, that it privileges concurrency in this way, that's a hard language to learn or adopt. And I bring this up because I think that actually when we consider things like Korean and when we consider things around how when languages create connections between the real world and the representations within the language, it actually creates a foundation of learnability and accessibility that allows learners to draw on their real world experiences rather than have to think about the world that doesn't actually align with the language that you're writing in. And I say this is someone who started off as a functional programmer and then in my first software engineering job, we were using JavaScript and it was mutating state all the time and it was totally foreign to me. I was like, wait, I don't do this in real life all the time. I'm not creating arrays and then pushing stuff to them. In the real world, I'm passing data from myself to others and we're transforming data and state is not this thing that we just get to kind of plug and play or poke at all willy nilly. So my claim here is that I actually think that some of the things that people say about or laying in elixir and in general functional languages is not actually true. It does require a paradigm shift, but I think once you kind of are able to draw those connections between what's happening in the real world and how we think about what happens in the real world, it's actually a much closer representation to what we do outside of programming. All right, that was a digression. We'll come back to elixir. So that's a sort of talking about continuing to build accessible features, I think is a nice segue to talking about elixir, which continues in this tradition that Erlang began. And as we elixir enthusiasts know, there are a lot of additional features and tools that build upon this really strong foundation that Erlang gives us, but makes the language a lot more accessible. There's a great talk by one of your NPEX co-organizers, Hannah, about idea scalability and why Erlang, for all of its awesomeness, is not more widely available. And I think that's also relevant when we ask why we're not using Erlang now. But I think there's also the idea of where people coming from, especially people who are doing the types of development that they're doing with elixir, and why didn't they find Erlang accessible? And I think elixir really was able to capture the spirit of Erlang, but be able to make it more accessible to a wider audience, which has helped with its adoption. So some of those things, and I'm going to start off with like a pretty simple one is pipes. And the reason why I'm starting off with the simple ones, I also want to kind of drive this idea that sometimes the things that we can do to make things more accessible can be really, really simple. It can be as simple as introducing something that elixir didn't invent the notion of pipes, like functional programmers have seen pipes in all kinds of languages, right? But the reason why this is so valuable is that in Erlang with the absence of pipes, with this idea of immutability, now all of a sudden, like, when you're trying to do a lot of stuff to state one thing after another, you very quickly end up with code that is a lot of copy pasta with like a couple of variables changed, or stuff that you really have to read all the way through to follow and see what's going on. So for example, let's say this is kind of a little dummy example, but let's say we have some state and we want to transform it with some functions. So in Erlang without pipes, this is one way you can do it, right? You can assign the transformed state to another variable, then transform that, assign that to another variable and transform that and so on so forth. But in order to kind of see what's going on, you actually have to like read every line and follow everything. Maybe that's not so bad. But what can we do to improve on it? So maybe we inline it. Okay, now we can kind of see at least that we're transforming state, you know, three times over. But now we have like, these friends we have to keep track of and it's not that great, right? So what pipes do is pipes just make this really clear, they make it really simple. And the nice thing about pipes, again, like this is not a new idea. But it makes it so that our code now of now all of a sudden can read more like pros from top to bottom, and we're able to highlight one of the strengths of functional programming, right, that we can treat functions as if they are these data transformers that can combine in various ways to achieve some kind of result. Cool. Yeah. Okay, so, like I said, simple example, but I think it's like little syntactic sugar stuff like this that just kind of makes a world of difference when it comes together. So a few other things. So again, none of these things alone is necessarily a new invention of elixirs. But I think all of these pulled together and then laid on top of that foundation of Erlang is to me what makes Erlang really elixir really powerful, and really a joy to work with. So additional syntax changes. So things like optional friends, things like that, things that again, like individually may not seem like they make a huge impact, but put together, if you think about the joy that you have writing elixir, I think some of that is some of those syntax modifications. Also, the power of metaprogramming, the ability for, say, macros to allow third-party libraries to provide internal DSL. So anyone who's incorporated Ecto under a project knows the power of this, right? In terms of tooling, having something like MIX that allows you to really quickly and simply create processes that can scaffold a project that can help you with dependency management and also is extensible. The formatter, this one is new to 1.6 and I was really excited about it. For me, I work on a large team where we get team members pulled off and onto projects given the pace of other work that's happening on other teams. Being able to have a consistently formatted code base is a huge thing. Again, it seems like such a little thing, but especially when you're building large-scale products that you might end up coming back to six months later and you need to be able to know what's going on without working through someone else's quirky style. Having something like a formatter just built in is really huge. Then, Erlang compatibility. We already mentioned some of the benefits of having that foundation of Erlang, but being able to call Erlang functions if something does it isn't available in Elixir means that we get to benefit from over 30 years of research on this language. I mentioned I was going to give a tiny little plug for Elm. Who here has touched Elm at all? I won't belabor the details, but for those that haven't touched it, here's my quick little plug. Elm is a functional front-end language that was inspired heavily by Haskell. It first appeared in 2012 by Evan Shapliki, and I think the cell that I give when I tell people about Elm is that it boasts virtually no runtime errors, which for front-end programmers, you know, this is huge, right? One of my favorite things about Elm, besides those guarantees, is how much care they put into their error messaging system so that error messages can be embraced instead of being some kind of mysterious thing that you have to decrypt and work through to debug your app. So I'm going to go over some of the things that I think they've done really well in their error messaging, but a caveat, some of the specific types of error handling that you get in Elm is a direct consequence of its type system and the power of type inferencing that it's capable of doing as a result of that type system. So for the purposes of this talk, I'm just going to be focused on really the superficial stuff and not that type stuff. If you care about that type stuff, though, I will talk your ear about it afterwards during a break or something. So one of the things that I think error messaging in Elm does really well is helping you find those relevant bits of code. So I'm sure there are plenty of people in here who remember getting error messages like program.x, colon 54, colon 96, and you have to decipher them and you have to, like, go through your file. You have to, one, find that file. Two, you have to, like, go through, find that line, find that column. You end up spending all this time scanning the code. Whereas in something like Elm, they just tell you upfront and they even take specific visual cues to show you where in that line the error occurred. Another thing that I think is really great about the error messaging in Elm is you get friendly language. So I'm sure some of you can't see this in the back. Sorry. So in this example, there's been a type error. And again, I'm not gonna go into the type stuff, but the error message reads, the first argument to function is over 50 has an unexpected type. Looks like a record is missing the field age. As I infer the type of your values flowing through your program, I see a conflict between these two types. Like, it's so nice to you. It's like a friend who's giving you a suggestion. And I think, again, that goes a long way because if you think about when something goes wrong, when you hit an error in your code, that's not a moment where you want someone to just be like, no. Right? So having something that just is a little bit more empathetic just helps you in that moment where you're like, I just want to get through this. Please tell me what happened. And then finally, this one just seems super, super official that once I saw it happening in Elm, I was mad that it wasn't happening in other languages. But just the use of color and formatting. So those of us who build products for users know that layout and color matter, right? So why is it that so many of our error message systems usually are just like all one color, like fire alarm red, like eh, eh, eh. And then just like this giant, big text dump with no consideration for layout at all. Again, the nice thing in this system is you know immediately what happened where and it's marked with color, it's the lines are like laid out and everything's not just all squished up. So you have to kind of like get in there to see what's going on. It's designed for humans to read this and be able to access it. All right, so that was my plug for Elm. And as a case in point, and this is a bit unfair I realized, but consider this example of an error in JavaScript, right? Like so again, the amount of information that we have about the errors here is gonna be a little bit different because Elm's type inference system gives us a lot more power in terms of what we can pick up. And I kind of stack the deck against JavaScript's favor because this is an error message on like minified Jcry source, but even absent of all of these things, like the considerations around like language, color, and layout could be better taken into place here still I think. Sorry, that is just my moment to crap on JavaScript for a moment. All right, so finishing up, we saw how languages that accept the reality of the world as error prone and that provide features and tools for developers to create fault-tolerant systems are both highly reliable and also maintainable. So in this last part, what I wanna consider is what we can learn in the other direction, what we from the real world might be able to take away from these systems. So I think something that becomes really clear once you've started using a language like Elixir is that it forces us into a paradigm shift in terms of how we think about programs, states, and also how language can shape what we perceive to be possible through what can be expressed. So for me, this is really illuminating when I started working with the Lambda Calculus because it was so expressive, but we can look at a somewhat more concrete example. So I am not going to say the name of the city, but this is the name of a city in Poland that a lot of native English speakers have a problem pronouncing and the reason why is because we don't have this consonant cluster in English. We have other consonant clusters. We have SK, school, ST, stop, but we don't have GEDs. So usually what we do in English when we encounter a consonant cluster that we don't have natively is we'll do a thing called vowel apenthesis and we'll put a vowel in between the two letters. And that's what we do. We say gdansk. Try saying it without the vowel in between. You will find it impossible. But Polish in fact does have this. And I'm gonna play hopefully this place. So this is the actual pronunciation of this city. Let's try and change the sound preferences really quickly. Great. Okay. Gdansk. Ooh, it's so loud, sorry. Gdansk. Okay, that's it, that's it. But you see how in the native pronunciation, there's no vowel there, right? So what I think is interesting about this example is this informs how the language that we use everyday shapes what we think is possible in terms of what we can express. And I think just as natural languages do this, so too do our programming languages. So I'd like to suggest that just like learning about what another language makes possible phonologically might do in terms of opening our minds in terms of what can be pronounced, maybe we can learn something from these programming languages too in terms of how we can embrace error in the world. So what have we learned from languages like these? We've learned that error is a bound in the world that we live in and we can't avoid them. If we avoid them, then just other problems start to pile on really fast. And I think this is a really important part of programming for me. This was one of the things that I found most freeing when I first started programming, the fact that failure wasn't a thing that I had to control, failure was just a thing that I had to learn how to work with. And yet I cite this as something that we need to be mindful of because I think despite living in an error-prone world, not everyone can abide by this rule to fail fast. And I say this because for the past five years I've been working with educators in low income communities of color across Los Angeles to teach computer science to middle school and high school students. And I found really quickly that when it came to the idea of fail fast, I didn't know what to say to these students because for a lot of these students, for a lot of students of color, for a lot of queer students, for a lot of female students, fail fast wasn't an option for them outside of my classroom, right? Fail fast was something that sometimes could mean like violent outcomes. Failure to appear duly submissive with law enforcement, for example, might mean death. Failure to comply with society's ideas around gender and sexuality could also mean death. And failure to correctly respond to unwanted advances from someone who is sexually harassing them could also mean death. And so I think before we ask people to embrace fail fast fully, we also need to think about what we can do to make the world a better place for failure and full of errors. So I'm gonna finish with this, which sadly also you can't see, but I will share the slides after this. This is from John Perry Barlow's 1977, 25 Principles of Adult Behavior. And I've been seeing this image a lot this week because he sadly just passed. And I knew as soon as I saw this that I wanted to incorporate this somehow and I wanted to talk about his legacy and honor his memory a little bit in the final moments of my talk, but I wasn't sure how. So I start, I kept looking at this image, I kept looking at this image and it has like advice like, be patient no matter what. Don't trouble yourself with matters you cannot truly change. Tolerate ambiguity. And as I started reading these items more and thinking about what I was talking about, I was like, oh duh, it's just kind of we end here, right? Because I think it's very fitting that someone who has spent his lifetime working on the connections between technology and policy would also produce something like this list. These principles that we can apply equally to languages that we use to create new things in the world as well as the world that we inhabit when we bring these things to life. That's it. Thank you.