 Good morning, everyone. Welcome to the conference. Welcome to this talk. My name is Michael Soiman, and I am a functional programmer. Today, I want to talk about how, in general, in the software industry, we choose our languages, our libraries, and our frameworks. What I'm going to be saying applies to all three of those. Mostly what you're going to hear me say is going to be focused on languages, just to avoid saying those three things over and over again. The main question is, how can we do it better than we do it today? And I'm going to start this talk off by talking about my history of how I've chosen languages and how I eventually got to where I am today. I've been programming for about 25 years, and I've been doing Haskell for the past 10 years. So how did I get there? The first two languages that I learned, I learned in grade school. There was someone who came into our class and gave us a lesson on LogoWriter. Has anyone here ever heard of LogoWriter? So it's a little bit of a stretch to call that a programming language, but we'll call that my first language. I pestered him relentlessly throughout the course on how to do other things, and he kept telling me, no, you can't do that, you can't do that. And eventually, he relented, and he gave me a book on QBasic, or QuickBasic, towards the end of that course. And I had a DOS computer at home, so I was able to use it. And that was it. It's fair to say that that changed my life, and I became a programmer after that. But you may notice, choosing those first two languages was very, very easy, because I had absolutely no choice. This is exactly what was delivered to me. I had no access to other kind of information. Someone told me, this is what you're gonna do, and that's what I did. Later on, at the local bookstore, I was able to find on sale some book on Visual C++. There was probably some old edition of it. I didn't even have a Visual C++ compiler, but I somehow made it work. And I learned C++, and I did that for a year. And then Java became really popular. Java was gonna take over the world. Everything on the front end was gonna be done in Java. The web browser was gonna be dominated by Java applets. You all remember that, right? Yeah. Of course, that was obviously gonna be the case. Today, we're doing Java everywhere on the front end. So I learned that, because that was what the world told me I needed to learn. And then I did Java for quite a few more years. The language selection process for all four of those is pretty obvious. There was not much of one at all. I did not have access to a lot of learning material. I had very limited access to tooling. I followed whatever the obvious choice at the time was, whether it's because someone gave me the book or the world had decided that this is the programming language that I should be learning. All of that said, it sounds like I'm saying this is a terrible idea, but actually that was pretty decent criteria at the time, given the constraints that I had. However, something happened. We got the internet. We got access to a lot more information and a lot more material became available online. It became easy to get learning material, to get compilers, to download IDEs. All of this stuff was suddenly available. If I had enough time to wait for my 56K or 28K, whatever it was, modem to download the Java SDK or Python or whatever it was that I was gonna be trying out now, I could do it. And suddenly we were in the paradox of choice. Is everyone familiar with the paradox of choice? Have you guys heard this term? Basically, the fact that I had all of these choices available to me made the situation more difficult, not easier. There's still some defaults that remain, even in a world where we have access to a thousand programming languages available to choose from. If you're on a specific platform, you may be pushed in a certain direction. So if you're doing iOS development, you could do it in Haskell. You could do it in Rust. You could do it in a bunch of languages. But odds are, if you're just starting off, you're gonna end up doing Objective C or Swift. These days, if you're doing Android, you're probably gonna use Kotlin, because that's what's recommended. A few years ago, that would have been Java, but that's fine, things change every time. If you're working on an existing code base, if you have been thrown at a project that is a 200,000 line C code base, you're probably not gonna rewrite it in Haskell overnight. You're probably gonna write that in C. And when you get thrown into some soul-sucking corporate job that has a corporate coding standard, you're gonna follow the standard because you wanna keep your job. So there's still some cases where you have a very easy choice. The paradox of choice disappears. What do you do if none of that applies? What if you're in one of these programming domains where you could use legitimately 20, 30, or 100 different languages? How do you choose which one of these you're gonna work with? Well, here's a non-starter approach. Fully evaluate every single one of these languages. You've got a project, I know. I'm gonna take all 100 languages that are available and I am going to implement the full project in that language, in every single one of those languages. This obviously is not going to work. It takes too much time, it costs too much, and I don't just mean the cost to the business or to yourself. I mean your mental health. You are going to go crazy trying to do this. Theoretically, there's some kind of a deadline that you have to meet, so I don't think that's gonna happen. And at the rate that languages come out, this is actually a never-ending task. You will never be done testing every single language that you could be using. This by the way is Sisyphus, so he is constantly pushing the boulder up the hill. We will be doing the same thing with our programming languages. So obviously we need some help. And what I'm gonna describe now is the process more or less that I think most of us use today to determine which language we're gonna be using when we start a new project. We use some kind of evaluation tool. These things are gonna help us make that choice, which up until now seemed very difficult since we've already eliminated all of the easy ways of doing this. And what we wanna be able to do is we wanna be able to prune that set of languages. We want some kind of a system where we're gonna take that 100 languages, 200 languages, whatever it is, and we're gonna get it down to a manageable list. And manageable is probably very short. It's probably in the range of about five languages. And then we wanna be able to sort that in some kind of a priority queue and then start going through these things. The first tool that I think a lot of us use is benchmarks because we programmers love benchmarks. I've seen this personally. If I write a blog post and I spend weeks working on this blog post and I talk about how awesome it is to work in a certain language or I talk about some features or I teach a very deep technical topic, okay. If I throw together a benchmark in five minutes and I claim that something I wrote is 73% faster than the competition, everyone will get excited. That's just the way we are. Unfortunately, benchmarks can be misguided. We think that they are going to apply to what we're doing. Usually we're not testing the same thing that we're doing. We're usually testing something which is not the bottleneck in our program. One of the common examples is HTTP benchmarks and I've worked in that. Usually in most web applications, HTTP processing is not the bottleneck of your application. So as excited as we get when we see that one web server is 90% faster than the competition, you're gonna be lucky if you get a 5% performance difference from that in practice. Do not take this as me saying that no one needs to worry about performance. That is the opposite of what I believe. However, relying on benchmarks isn't the best thing to do. The thing about benchmarks though is that they are objective or at least seemingly objective and everything else we're gonna talk about is not objective. Most things that we end up talking about when deciding on a language are subjective criteria. And this is why I think benchmarks always come up as one of the first things people look at when deciding which language they wanna use. You get a graph, you get numbers. Numbers can't lie, it's impossible. We all know that numbers are absolute truth in all cases and we like that. But benchmarks are deeply flawed. All of that said, they are still valid and they should be part of this evaluation metric. If you have some kind of performance criteria that you must need in your application, looking at a benchmark and seeing whether something has any chance of needing it or not is valid. My only point here is I think we weight the benchmarks a little bit too heavily in this process. And we consider them objective truth even though we know that they can be misleading because as we know people in our industry have gone ahead and created misleading benchmarks and they may not be as relevant as we expect. All right, so that's tool number one. Tool number two is hype. We love to follow what everyone else is doing. If something is popular, it has to be good, right? No one has ever created a programming language which was massively popular but it wasn't actually that good in practice. If everyone is using it, it's gotta be a good thing. We know that this is deeply flawed. We know that this is not a good way of evaluating something but it does provide some signal. If a whole bunch of companies or a whole bunch of individuals are working with some kind of a language, it has to be at least somewhat decent. So I'm not saying you get no information from hype, you get some. Let's change that term and not talk about hype, let's talk about reputation. Reputation doesn't sound quite as loaded and we'll get into why hype is such a loaded term in a sec. Reputation that a language has may be accurate or it may be inaccurate. Therefore, you need to know whom to trust. When you go through this stage of the process, odds are you're not going out to random strangers, you're probably going to your friends, your co-workers, your colleagues, people you trust and asking them for their opinions of these different languages. You can also observe market trends on the assumption that if dollars are going somewhere, if money is being spent in a certain direction, that's also some kind of an indication even if it's not the best. Of course, the best way to choose a language is to just trust Reddit. All right, so why is it that we hate hype so much? It's because of marketing. In our ideal world, how much hype a language has would be directly correlated to how good the language actually is. But we know that's not true. We know that it's possible to game the system. It's possible to make a language look better than it actually is by marketing it. And that's why we have this visceral negative reaction to hype and know that we can't really rely on it. So the solution to this comes down to something in economics, game theory. And I say you have to hate the game, not the player. Don't get upset when someone goes out there and markets their language or markets whatever it is that they're doing. That's the only way to level the playing field. If someone in the marketplace is gonna be doing the marketing, everyone has to do the marketing, otherwise it's unfair competition. We'll get into this a little bit more later. One of the things that I think we are going to need to do in the functional programming community is do a little bit of this kind of marketing. But we have to do it correctly. We can't go out there and make false claims, crazy claims, we have to be accurate and we have to be respectful in what we do. Okay, so I've gone over this process. Where are we now? We know that we have no default or obvious choice to make in this programming language. We've eliminated a few languages that are too slow to use. We've let reputation eliminate some others. We've come up with a list. And now we have a short list of five languages that could reasonably solve our problem, whatever that happens to be, has decent enough performance numbers and there's some subset of the world that you trust that likes this language. Finally, it's time for step three, on rampant. And this is the hard part. This is the point where you take these languages and you try to actually use them. This is hard. This requires getting used to these languages. You have to download tools. You have to figure out tools. You have to go through tutorials. You have to implement Hello World. You're gonna implement some kind of other example. You're gonna start playing around with this. You're gonna get halfway through the first language and you're gonna get fed up and you're gonna move on to the second language. You're gonna get really upset that this language has curly braces or maybe that it doesn't have curly braces. Whatever the case is, you're gonna hate something about the language and you're gonna complain about it. This is a hard process and it takes some real time. But after going through one, two, maybe three of these languages, maybe you'll go through all five, eventually you are gonna figure out that one of these languages is the right language. This is obviously the best and you are gonna go ahead and implement your project in it and now language X is your language. You are a language X developer. You identify that way. And I think this is a process that most people in this room have probably gone through to some extent in the past. Especially if you're at a functional programming conference, you've probably done that soul searching, looking for what the next language is going to be. There are problems with this approach. The process I described can easily take one to two months to make a decision. That is a non-trivial amount of time and a significant amount of work. From a business perspective, it's still costly. And I'm gonna claim that all of that is unavoidable. As much as we would like to jumpstart that process, we can't. Even if I go to someone and say Haskell's good, go use it, they're not gonna just listen to me and they shouldn't. They should do this analysis themselves and figure out what to do. So I'm gonna call these fundamental inherent problems that must exist, but there are two more other fundamental problems that are even worse. The first is the sunk cost policy. And this is another, I think this is my last economics reference, so don't worry. So the sunk cost policy is part of human psyche. When you've invested enough time and energy into something, you wanna defend that choice. You don't wanna admit that you wasted those two months becoming a LanguageX developer. You put in blood, sweat, and tears into learning that language. And you don't wanna admit that that was a mistake. We are biased to defend the choice that we made. We chose LanguageX and no matter how much new information comes to our attention, we will, maybe not intentionally, but at least subconsciously, we will ignore that information to defend the choice that we made previously. This is a real problem. And we see this happen a lot in industry. Sure, many of us can see times in the past. I can, for sure. Sure, many of us can see times in the past where we fall into this. Second problem is really the point of the talk today. That everything I've talked about so far is at best half the story. Benchmarks tell us about performance as flawed as they may be. And that initial evaluation tells us about initial productivity on a project. What I've not talked about at all is long-term maintainability of a piece of software. What's the bug count gonna be when maintaining software like this? How difficult is it gonna be to re-architect? What if requirements change? What if the product owner comes forward and says, no, no, no, we've gotta add a new feature? Are you gonna be able to add that? Are you gonna have to rewrite the entire codebase each time? Are you gonna be able to bring your team up to speed? Are you gonna be able to make a large team productive on this kind of a project? Inevitably, there's going to be technical debt. Are you going to be able to pay it down? All of these are fundamental, important questions to how we write software. And at no point in our analysis did we think about it once. You may think, well, hype is really going to protect us here. There's no way that all of these people out in the world are continuing to hype up the language and talk about it and go on Twitter and write it and say how wonderful it is if they're going through maintenance nightmares all the time. That's not true either. I already told you that there's a sunk cost policy and those same people who are going on Twitter and write it and talking about how wonderful their languages are subject to the exact same problem. Therefore, we have an information hiding problem. This is a functional programming conference. So at some point in here I should talk about functional programming, you would imagine. How is all of this related? Most programmers today start off with either imperative or object-oriented programming. Those are the languages that are taught in schools. Those are the languages that are dominant in industry today. These are languages that usually have very large budgets for making very nice tooling that's easy to get started with. Because there's such a large market for this, there's a lot of educational material either in the schools, in the marketplace, in industry, or Riley, whatever it is, the material is easy to get access to. And these languages also have a lot more money for marketing, generating more of that hype. As a result of all of this, we see that it's very easy to unwrap with these kinds of languages. And so our initial evaluation is gonna be biased against them. I'm gonna claim we're fighting a losing battle. The way that everyone is doing things today, assuming that my assessment of it was correct, is not going to do a fair analysis. I'm gonna claim, and there's no evidence to back this up, this is just my own personal opinion, I'm gonna claim that when it comes to writing the first version of a program, V1, MVP, whatever you wanna call it, a highly trained Python developer and a highly trained Haskell developer can probably implement it in about the same amount of time. Let's say 10 to 20% difference. Nothing significant. That may not be true, but just go with me on this. Let's assume that's the case. There's no doubt in my mind that if you take a non-functional programming experienced developer and you put them down with Python and you put them down with Haskell, it will take them far longer to do it with Haskell. And I'm saying that as someone who likes Haskell. They're not gonna be able to be as productive as quickly as they will be with Python. This initial evaluation hamstrings us. This is a battle that we can't win on these terms. Now there's a silver lining to all of what I'm saying and I'll get into this a little bit more later. Recently, functional programming does have a significant uptake. Lots of languages out there are talking about functional programming. People don't look at you like you're crazy anymore when you mention a fold. So it's not quite as dire a situation and things are better today, but I wanna make them even better than they are. So why does all of this matter? Why am I making such a big deal about maintainability of software? In any kind of successful project, the initial development time is a tiny fraction of the work that you're going to end up doing, especially once you consider how many people end up working on the maintenance phase of a project. If a project took six months with a two or three person team to get to MVP, and then you have 10 people working for the next five to 10 years maintaining it, the amount of time on that initial phase is tiny. We're ignoring that long tail, all of that work that's going on at the end. This applies both to commercial and open source work. I've written a lot of open source libraries and I can tell you, I spend more time maintaining all of them than I ever did writing them in the first place. We know for a fact that requirements are going to change. This is just the nature of our industry. We would love it if the requirements document came down from on high, was handed to us and never changed at any point in the future. It's not reality. We know that we are going to write bugs. As painful as it is to admit it, there will be bugs in our software and we are going to need to fix it. Technical debt is going to accrue. Architecture is going to need to change to respond to things, whether it's changes in the way that in best practices or changes in those requirements. And our standard evaluation practices are not going to touch any aspect of this at all. Our industry needs to improve. We write buggy code. The industry as a whole writes buggy code. Unmaintainable code. It is not uncommon to do full rewrites when it comes to V2 and that's not the way that things should be. So my goal, my encouragement to everyone really comes down to this. I want us to change the conversation. I want us to start talking about maintainability more. I want us to be spending, to be putting it in blog posts and getting it out there in social media. I want to talk about it with our manager. Next time management comes forward and says what language should we be writing this in, the question should be, how difficult is it going to be to maintain this if we write it in language X versus language Y? Sure, we have to talk about how long it's going to take to get to the first version in production. We need to include that talk about maintainability also. And don't pass maintenance off to the junior devs. This happens all too often. It's just maintenance, junior people can do that. It's insulting and it's wrong. And maintenance is not just a junior task. Maintenance is hard work. But even senior developers can have a difficult time with it and claiming that the juniors are just going to take care of it is wrong. My belief, and again this is one of those places where I don't have any data to back it up, is that strongly typed functional programming is great for maintainability. It's not a panacea, it will not solve all ills in the world. You can very easily, and I've done this myself, you can very easily write bad code in a strongly typed functional programming language. You can design your APIs poorly. You can subtly break backwards compatibility with semantic bugs that show up in production. Or you cannot use the type system correctly and not actually take full advantage of what these languages are offering you. But I truly believe if you do things correctly, FP is awesome. You're able to focus, you need to focus on quality and maintainability to make that happen. And you still have to test your code. Do not be one of those people who says, well it compiled so it's gonna work, ship it. No, tests are necessary also. We don't get a free pass. What I'm talking about is the things that we're able to add in addition to what the rest of the world has without typed functional programming. My anecdotal experience is that I've been able to onboard coworkers to massive Haskell code bases very quickly. The fact that we have very little mutable state, we usually use data types and we use data to drive the way that the entire application works. We usually encode a lot of the invariance and a lot of the concepts of what's going on in a program in the data types themselves. Allows the compiler to be your ally instead of your enemy. And then once you have that in place, you can do what we call compiler driven development. You change a line of code, you change a data type, you hit compile and four hours later after you've fixed all of the places where it didn't compile, now you're able to run your tests and if the tests pass then probably things went right. I've been able to refactor and rearchitect code bases in Haskell and seen other people do this as well in ways that I would have been terrified to do in a different kind of a language. The fact that I don't have to worry as much about mutable state getting into weird situations due to immutability. The fact that the types do guide me through what I'm doing. And the fact that I get much faster feedback from the type system than I ever could from unit tests as well as much better coverage of what I'm looking at. Now I think you guys will lynch me if I don't include at least some code in a talk like this. So let's look at a few examples. This is Rust, I'm choosing Rust because Rust is one of those languages that has both an imperative and a functional flavor to it. And I wanna compare those two flavors. Both of these functions do the same thing. And of course this isn't really a function, it's a sub-procedure, but they call it function so I'll go along with that. Both of these functions do the same thing. They add up the numbers from zero to nine. The first one is an imperative approach. It uses mutable variables, it uses loops. The second one is clearly functional in nature. It's using a fold. And I've had conversations about which one of these is easier to work with. And here's how a typical conversation will go. The functional programmers, probably most people in this room say, well the fold is obviously easier. If I go back and I look at it, the fold looks pretty easy to most of us I'm guessing. But the conversation I've had with imperative programmers, at least in the past, and again this is changing as functional programming is becoming more common. But at least in the past, I hear things like, well that's too complex. You have to deal with closures and all this other complexity, it's higher-order functions. That's weird and I have to learn some new stuff. I know that loops always work, so why would I learn this new thing when I don't have to? And there's this weird, there's a concern, not a weird thing, there's a concern in the back of everyone's mind that the fold's gonna be slower. I have absolute control of the loop. And if you'll notice this conversation and you think back to what I said previously, this conversation talks entirely about short-term productivity and performance. For someone who is not familiar with functional programming idioms, the fold is going to take a lot longer to write. The for loop will be easier to write. And performance comes to the discussion. But obviously this discussion ever talks about which one of these versions of the code is gonna be easier to maintain. And keep in mind, everything that I'm showing can fit on a single slide, so maintaining a piece of code like this is kind of silly. But, just use your imaginations and imagine scaling up to something a little bit more complex. So, let's say that we're gonna have one of those weird changing requirements things that never happens in practice. We decide we want to only add up the even numbers. Well, this'll work. You'll notice that in the imperative version, I've added in an if, and I've checked whether things are even before mutating. And in the functional version, I just added in a filter. Who here thinks that it was easier to see the difference in the functional version? Who here thinks that the imperative version is clear? It's okay, you're allowed to disagree on the function. I happen to think that once you get used to the idioms, this one is much easier to follow. It's easier to change the requirements. Let's come up with a more contrived modification. Let's say that you wanna add the number three after you know that it's even. So, you're gonna check if it's even, then you're gonna add three, and then you're gonna sum things up. Which of these is easier to follow? Is it easier to follow the functional version or the imperative version? Functional's starting to get a lot easier to follow. By the way, there's a bug in both versions of the code. Which one can you find faster? Functional, all you have to do is point out that map comes after filter. Well, the requirements clearly said that the map has to come before filter. Well, that was easy. The imperative one, you have to think much more about what's going on. You have to think about the mutable state. When is I getting modified? When is I being tested? Personally, I find that easier in the functional version. And again, this is subjective. Most of what I'm talking about now is subjective. But in my opinion, the functional one clearly allows you to see bugs faster and therefore avoid the bugs or fix the bugs much more quickly. All right, let's talk about types. I've got a Python program and I've got a Haskell program. The Python program defines a person class, a person constructor that takes a name and then provides a method to say hello to that person. And the Haskell program does basically the same thing. We don't have, well, we do have classes. We have type classes. So here we're gonna use a data type because that's the equivalent. We're gonna define a person. We're gonna define this function, greet. And then we're gonna call greet in the main function. And if someone who isn't familiar with Haskell, the Haskell code probably looks pretty irritating. What's going on with this IO thing? Why do I have to put types everywhere? What's that unit doing after the IO? Why am I having to deconstruct a data constructor? What's going on with all of this? It's overkill. And an imperative or an object-oriented programmer probably is not gonna like this too much. It doesn't gonna see much benefit in this. Especially people who love dynamically type programming languages. But again, let's say that the requirements change. And now we have to capture someone's first and last name. So we update the data constructor. Sorry, the class constructor. And we update the greet function. But we forget to update the call to that constructor. Is this gonna fail compile time or run time? Well, there's no compile time, of course, run time. It's gonna fail. The only way that you're gonna be able to stop this from getting shipped to production is if you have a unit test, which is gonna check for this. And you better make sure that your test suite covers everything. Let's see what happens in the Haskell version. So in the Haskell version, I change my data type. And I change my greet function. And now I have the exact same bug. I forgot to update the call. And now the person has a name instead of a person in the last name. What's gonna happen? Compile time failure. The compiler is not your enemy. The compiler is your friend. The compiler is preventing an entire class of bugs from occurring at run time. This is a good thing. Obviously a minimal example like this isn't particularly compelling. If you can see all the code at once, and it's pretty easy to see that there was a bug. But you can imagine. If this was spread out over 100,000 lines of code, it's much easier to let the compiler do the heavy lifting for you than to have to go through all of those places yourself. Just to make it clear that I am making fun of other languages, let's make fun of Haskell a little bit. It is quite possible to write dysfunctional Haskell. There's a saying in the Haskell community that Haskell is the world's finest imperative programming language. This code is not functional in any way. We're using mVars, which are mutexes, and we're doing multi-threaded transfers between these two different mVars. I'm emulating bank accounts, which seems to be the only thing I know how to do when giving an example of concurrency in Haskell. So we create our first account, we create our second account, these are both mutexes, and now we transfer between the two accounts. First in one thread going from one to two, and then in the main thread from two to one. And in the transfer function, we lock the mutex, the first mutex, and then we lock the second mutex. Who can guess what this program is gonna do? This program is going to deadlock. We've locked the first variable in the first thread, the second variable in the second thread, and neither thread is now able to continue and complete its task. If you write code in an imperative style, even in a language like Haskell, which is functional and purely functional, it forces you to think in a functional way. Even in Haskell, you can shoot yourself in the foot. So of course the solution is to use more FP. I think that STM, software transactional memory, is one of the coolest features that we have in Haskell. It's a great demonstration of what functional programming and purity are able to provide. If anyone isn't familiar with that STM and wants to talk with me about it anytime today, I will be more than happy to talk your ears off about why STM is so awesome. So here, instead of a mutex variable, an mbar, I'm gonna create a tbar, a transactional variable. And our transfer function now looks significantly simpler. There's no locking. People who come from a different background, more unfamiliar with STM, are probably thinking that there's a data race condition here because you can be modifying these things simultaneously in two different threads. However, the way that STM works is based entirely off of functional programming, pure functional programming, and the purity of Haskell, the referential transparency. Inside an STM transaction, we know that there are no side effects. And the runtime system is able to handle all of the retry logic to make sure that we have an atomic transaction. That's why the word atomically is sitting there on the screen. This program is not gonna deadlock. This program is not gonna have a race condition. And we got all of that by using functional principles. Again, for an example this small, it's not terribly compelling. You could have made the mbars work. You could have done some kind of ordering of the mbars to make sure that you locked them in the correct order. But when you start getting into large programs with large blocks and a lot of variables, the ability to simply compose things together without thinking too much is very valuable. I'm also gonna throw in a little bit about my other favorite library, which is the Async Library, and this concurrently thing here. The fact that we treat IO as a first class action as opposed to something which implicitly just happens allows us to write imperative, sorry, a concurrent code in a very elegant style. And again, if you want me to tell you all about why I think the Async Library is one of the coolest libraries, I will talk to you about that too. I love those two things. Okay, so what can you do? What can we do? I already said that we've been getting the functional programming ideas into the mainstream much more over the past few years. When I would go to a conference five, 10 years ago and talk about Haskell, people looked at me like I was crazy. People still look at me like I'm crazy, has nothing to do with Haskell at this point. People aren't afraid of holds anymore. FP, in fact, is usually seen as an advantage. You'll see lots of programming languages out there touting the fact that they have functional programming features. JavaScript is a functional programming language. Java, C++, they all have functional features now. That wouldn't have happened 10 years ago. So we're winning that battle. People are acknowledging the fact that functional programming offers something. And as a result of all of that, the learning curve is reduced. When that developer that I was talking about comes to compare Python and Haskell, they're probably still gonna find Python an easier on-ramping experience, but not nearly to the same extent as they would 10 years ago. We need to make it fun, easy, and exciting to learn these functional programming languages. We have to acknowledge the fact that people are still gonna be hitting that on-ramping cost. And we need to give the motivation to push through and continue. And I'll tell you the rest of my story in a bit and you'll see how that ties in. And we need to change the conversation. We're fighting on the wrong grounds. If we continue to only talk about productivity and performance, we're not gonna be able to win. We need to change the conversation and get people to think more about maintainability. We also need to be talking about practical benefits. It's very nice Haskell functional programming, the Lambda calculus. These are elegant, beautiful solutions to problems. But if you talk to most developers and definitely most managers and you tell them about how elegant the solution is, they're gonna nod and they're gonna continue writing Java. We need to make it practical. Tell them the real bugs that are avoided. The real advantages. The real productivity gains. STM that I just mentioned gives real productivity gains when you're writing concurrent code. And we need to be talking to that much more. What I wish is that we actually had some data to back up all the times I'm making. Everything I'm making is just my opinion and my experience, my anecdotes. We don't really have this kind of hard data in our industry. No one is doing the studies to show that functional programming either does not help industry move forward faster. I would love to see these kinds of studies happen. I'm not particularly hopeful that we're gonna see it. Doing those kinds of studies would be very expensive and there doesn't seem to be a lot of interest in doing that. So I work it up to complete and when we talk to companies about programming languages, about tools, about anything, DevOps practices for that matter. We always talk about three different pillars in software. And it's performance, productivity, and maintainability. And you've heard me mention those all in this talk. Performance has to do with the hardware itself. Either how much hardware do you have to throw out the problem? Or how quickly the hardware is able, the same amount of hardware is able to solve the problem. Productivity in business terms is really easy to translate. It's time to market. How long is it gonna take you to get this piece of software out there? Maintainability is the bug rate, evolving a code base, adding features. These are things that business people understand. They understand that users are going to be upset when the program crashes. They're going to be upset when they don't get the new feature in a reasonable amount of time because no one can figure out how to modify the legacy code base. These are things that you can talk about with your managers and get the conversation started. I'm talking about maintainability today because it is the most overlooked, in my opinion, of these three. All three of them are important. We can't write software without considering all three. But let's get maintainability back into the conversation. So I started off by telling you guys how I got to be a Java developer. Let's tell you guys how I stopped being a Java developer. I guess it was 12 years ago, 13 years ago, I decided to do some web development. In Java, of course, because I was a Java developer. It sucked. Maybe the situation's better today. I've been too afraid to look again. But at the time, I just found it way too painful. It was so painful that I was able to overcome my sunk cost policy. I was able to realize, even though I've been programming Java for years, this is not where I want to continue. And so I moved on to PHP, which was a wonderful programming language to follow up from Java. I actually liked it because it was so much more fun to write this code than it was in Java. After a year or two of doing PHP, I eventually realized I'm not gonna be able to maintain this code. It struck me and I realized I'm just not smart enough. It's not something I'm capable of doing. I got lucky and I was able to overcome that sunk cost policy a second time. I then jumped around through a bunch of programming languages. The two that I stuck with the most were probably Perl indeed. And I got to Perl and someone came out with this thing in Perl 6 called PUDS. It was the first implementation. Has anyone here ever heard of PUDS? PUDS was written in Haskell, which is a language I'd never heard of before and I was curious. Why would they write this thing in Haskell as opposed to writing it in Perl? Perl's the greatest language ever created. So I looked into it. I was a math person. I enjoyed math. I actually studied math in school and math in computers. And Haskell was a mathematical programming language. So I thought, hey, why not? Let's have some fun. I didn't like do it for anything real. It was gonna be a hobby. As I started looking into it at the time, things are better now, but at the time documentation sucked. It was all over the place. The tools were terrible. This is before we basically had any kind of command line tools. You had to manually run your setup.hs files and you had to download car balls directly. It was a mess. Compared to what else was out there at the time, Haskell looked like a joke. And I knew there was no way I was ever gonna use Haskell in production or use it as part of my career. It just wasn't a reality, but it was fun. And so I played with it. I overcame that learning curve and I stuck with it because I thought I was going to enjoy the experience. And I did. And I stuck with it long enough when I was a stubborn enough person that I fell in love with the language. And 10 years later, I'm still using it as my primary programming language. And through a lot of luck and perhaps some self-delusion, I found what I believed to be a really great programming language. And even though I didn't have the language 10 years ago to talk about maintainability the way I can today, I ended up finding the language that addressed the concerns that I knew that I had about writing code in a non-functional approach. We can't rely on luck. I got lucky, others may not. It's too easy to give up when things get difficult and just try something else which looks easier, which is a completely rational thing to do. It's far too easy to make an initial guess that takes you in the wrong direction. I did that multiple times. And many other people are doing the same thing. And then it's way too easy to get locked into a bad choice. I believe we have a responsibility to help our industry improve, to get functional programming out there. I think we can make the world, the software world and the world in general, a better place through it. I am gonna encourage everyone here to go listen to the rest of the talks here, learn much more about functional programming, and then take the ideas back out into the rest of the world. Talk about the benefits of functional programming. Talk about how it helps us make better code, more maintainable code. Talk about the performance productivity as well. But don't forget to bring the maintainability into the conversation. Enjoy the conference and learn a lot. Thank you. Thank you, Michael, that was awesome. Time for questions. Yeah, so this is gonna sound weird. The thing is, my question is, what are some bad FP languages? What are some bad FP languages? Yeah, that we shouldn't be learning. I'm not gonna answer that one. Okay, no, I mean, I'll give you my own personal biases. My personal bias is towards strongly typed languages. So I personally prefer things that give you a strong type system and static type system. Functional programming overall, I think, is an improvement. But I personally believe that getting the strong typing gives you much more of the benefits than other things. So you can extrapolate from there which languages I'd like more than others. Hi, Michael, what was your first production Haskell project? And what was the state of Haskell at that time? Okay, so before I left the United States, I was working as an actuary. I was working in the insurance industry and we needed to do some kind of large data conversion. Now, this was large by our standards. We had to do, we were required to do all of our programming in Visual Basic and Excel. So large there meant one gigabyte, which is obviously not a big deal. But we did a little bit of an analysis and the way that Visual Basic was working, whatever, one of my coworkers discovered it was gonna take three weeks to run the program. Yeah, so we decided, well, that sucks, we're not gonna do that. So I did it in Haskell instead. That was the first, and I think maybe the only time where I got really bitten by a space leak and I had to debug one of those. It was one of those programs that was only gonna be run once and then it was gonna disappear. So no one cared that it was written in Haskell. I got away with it. And I actually got very scared when that space leak happened, like, oh my God, I'm never gonna be able to solve it pretty easily. Everything moved on from there. Yeah, and that was it. And then we converted it, and I think it ran in like five seconds instead of three weeks. All right, so first of all, I love this topic and I'm glad you decided to do something like this. The good news is that I think your cynicism about the lack of research out there is unnecessary because I think actually there are some people who have published a few papers on strong typing and the effects on bug counts and bug rates and other productivity metrics out there. And so they're having people who are doing some research like that. But one of the biggest difficulties is not money for this stuff. It's the fact that nobody actually cares. And this is a real problem. So I think actually talks like this are important because people don't want to invest in the HCI of programming language design. And if you look at the big conferences where people are trying to publish research on programming language design, it's almost impossible to get a usability study published in those conferences. And so as a community, I think we need to be pushing strongly, culturally towards honest actual real usability evaluations, which we do have the skills to do those studies. It's just that nobody wants to do that. I think partly because a lot of people are very scared about the results of that kind of research. So firstly, if you can share some of that with me later, I would love to see it. And yeah, I mean, there is the reality. I'm making all these claims, but I think functional programming, I think Haskell is gonna rule the world. It's the best language. We have to accept the fact that we might be wrong. The studies come out and they say that everything we're doing is incorrect. And we could just say the study was done badly, but then we're like the nutrition industry and we are doing horrible things. Yeah, I heard what you're saying. I'd love to see some of that. This is regarding performance, sir. So as it is immutable, let's say I have a big list and I want to do map filter and like 10 operations. So all of them will be kept in memory. I actually think it's easier in functional programming than in imperative programming. In order to do it in imperative programming, you have to shove everything into the same loop. You have to make sure that everything, and you don't get any kind of composition. In functional programming, let's just take the lazy list example, which is the way that we do things in Haskell though, it applies elsewhere also. In Haskell, the way that you would do these things is you would just go ahead and chain a map, a filter, a fold, all of them together. And because it's lazily generated, it always takes up constant memory. So it's gonna generate one value in the list. It's gonna put it through that processing pipeline. It's gonna fold it together and you get constant memory usage. Not in all cases, you can screw it up. But for the most part, you get constant memory usage in these cases. There are even more advanced techniques, like streamfusion, the vector package is very popular in Haskell and it has a streamfusion framework. And with streamfusion, it even takes it another step and is able to completely bypass a whole bunch of heap allocations and do, and if you look at the assembly that it generates, it turns into the exact same thing that you would have written by hand in C. Doesn't always work, but in many common cases that you would end up having, you get high level expressivity and the low level performance that you want. And I'd be happy to show you some examples that there are some great papers on it. The immediate answer is yes, it's a problem. We have to solve it. Let me elaborate a little bit. It's not a functional programming problem. You know, the C language forms are infamous for having this kind of attitude as well. So there is an elitist attitude in some places. And I'm not saying, my point is it's not limited to functional programming. It's all over the place and anywhere we see it in the programming world, I'd like to get rid of it. I do think we need to take some active steps towards addressing it as much as we can. Just two days ago, I actually wrote a published a blog post called New User Empathy. And it was based, yeah, and yeah, no, I absolutely, it was, it was not completely unintentional that I published it before coming here. I had all these thoughts in mind as I was preparing this talk. Yeah, I absolutely believe that's the kind of thing that we need to do a better job with as a community. Figure out ways to improve the tone that we use when we're welcoming new people in. And I don't have a complete answer on how we're going to do it. But yeah, I want to solve the problem. I'm sorry, could you say it again? Oh, introspecting at the run. Oh, like getting runtime statistics and things like that. Right, so we don't have tools that may be as good as the JVM. This is one, you know, some things out there are better still. We have some really nice profiling tools built into the Haskell, into GHC. And you're able to get great, like, heat profiles and things like that right out of the box. We have statistics, garbage collection statistics. At the workshop that I did two days ago, we actually used the statistics quite a bit to be able to analyze memory usage and figure out ways to improve things. I'm not gonna claim that the tooling is as good as other languages. We definitely have room to improve. Hopefully, you know, this is one of those chicken and egg problems. Hopefully, industry becomes so massive around Haskells, you know, everyone's using Haskell tomorrow. Google adopts it, they drop go, they're using it, and then they, you know, they put a team of 10 people working full-time on making Haskell performance analysis tools.