Podcast
Production Haskell
You can also follow our feed. Listen to more episodes in the archives.
Christian Charukiewicz at Foxhound Systems wrote a list of reasons to prefer Haskell for building production systems. Cameron Gera and Taylor Fausak review the list and share their experience at ITProTV.
Episode 34 was published on 2021-01-22.
Links
Transcript
>> Taylor: Hello and welcome to the Haskell weekly podcast. I'm your host, Taylor Fausak. I'm the lead engineer at ITProTV. And with me today is one of the engineers on my team and my co host, Cameron Gera. Thanks for joining me, Cam.
>> Cameron: Hey, thanks for having me. Glad to be here.
>> Always good to have you. So what are we talking about today, Cam?
>> Well, you know, as an organization that uses Haskell in production every day, I figured we should take the chance to review this post by Christian at Foxhound Systems, where he talks about why Haskell is their first choice for building production software systems and coincides a lot with what we do here at ITProTV. So, you know, really going to talk about our experience today and how it relates to some of the really great things that Haskell provides us.
>> Yeah. We were joking earlier today that we could have written this blog post like every point we like. Yep. Yep. We've seen that, too. Same stuff.
>> We like that. Yep. That's great too. Learning curve, kind of tough, but we still love it.
>> Mhm. Yeah, and I guess we can jump right in. So he broke this down into, like, nine big points about why he prefers Haskell and we'll dig in each one of them a little bit. The first one is maybe the least surprising, which is the strong, static type system. I think everybody talks about this when it comes to Haskell, but it's worth remarking like, Yeah, it is good. It does help prevent errors and reduce cognitive load.
>> So you're telling me Haskell isn't the new JavaScript? It's not the wild, Wild West anymore?
>> Well, JavaScript has TypeScript these days, but it's better... The type system in Haskell is better than the one in TypeScript, I think.
>> For sure. Hands down, hands down. Yeah. No, I think it was... You know, after the learning curve, which I feel like a lot of people have as a con of learning, you know, doing Haskell in production. The cognitive load really does get reduced because you're not thinking about Yeah. Is this gonna work? Is, um I'm gonna get a runtime error here. You're going to see it 95% of the time in the compiler. The compiler's gonna say, Hey yeah, That's not the That's not the right thing to do here. You're gonna get some type mismatch.
>> Yeah, and the most basic example is like, Is something null or is it optional or whatever? And this is where, when you compare the languages like Java, you get a huge benefit by using Haskell, because in Java anything could be null. But in Haskell, only stuff that is marked as maybe can be null.
>> Yeah, there's no if this equal null, do this, it's There's no having to check that, which is, super helpful.
>> Yeah, it's amazing to me. So, like in my history, I've did a lot of Ruby reprogramming earlier in my career and, ah, huge portion of the runtime errors that we fixed were nil, which is Ruby's null doesn't you know, have the method whatever we wanted to call it like name or something like that, and it would take forever to track these things down because normally the null came into your system, and then it gets passed around by like, 15 different functions, and finally, something tries to call something on, and it's totally disconnected from where it came from. We just don't have those problems in Haskell. We never run into that stuff.
>> Yeah, in the legacy JavaScript API, Yeah, we definitely had that experience as well. it would be like, Yeah, push this to production And we wrote test cases and we can write the test case in case somebody can put anything in. And there you go, run time exception that's, you know, kind of difficult and dispersed when you're trying to, figure out what's going on. Another great, um, you know, thing that reduced cognitive load the fact that types kind of act as a documentation source like I mean, obviously there's implementations where you can use Swagger's documentation to operate auto, generate API documentation and such. But I don't think he's really talking about that here. He's more just talking about you can read a type and he said, Oh, the type person, Yeah, that's going to be dealing with a person may be Have the name of that age, all these different things and, you know, you read the type. You know what it is or what Well, it will probably do within the system,
>> and there are exceptions to this. So if you have a function that has type like I take three strings and I give you back a string. Good luck figuring out what it actually does. You'll need to read the documentation, but
>> that's why you have types type around those kind of things.
>> Exactly. And, a lot of functions have more specific types in that. So it's still useful. And another place that this is really useful is searching. And, like almost getting to the point of program synthesis, having the program write itself where you're like, I don't know what goes here. So I'll put an underscore and have GHC tell me the things that can go in there where all the types will line up. Or you can do these searches on Hoogle or Stackage or wherever. Um, but it's really powerful to say like, I know we have a function that does this. I can't remember what it's called right now. Compiler: Just tell me what to put in here,
>> right? Yeah. No, that those aren't exactly typed holes, right? Those were just holes in general.
>> No that's typed holes.
>> Yeah, well, typed holes are a godsend. You obviously you have to have a problem. You know the package in that module if you're expecting it to give you something. But overall, it's been hands down a great tool for you know, us. As we're working through just day to day actions,
>> Yeah and for me, it's been a game changer coming from again my previous experience with dynamic languages because you mentioned you have to have the module in scope, But often you do already because you're dealing with its data types. So you're just like, uh, let's see if there's a conversion functional there is. All right, Cool. I'll use it. Yeah, Speaking of moving on with our life, should we go to the next point?
>> I mean, I think so, Yeah. Hey, talks about how Haskell enables writing code that is composable testable and has predictable side effects.
>> Yeah, and this dovetails nicely with what we were just talking about. So as a extension of the powerful type system and the reduced cognitive load, all side effects are typically marked as IO or You know, however you manage effects will just say IO throughout here, but it it makes it really easy to reason about stuff, because when you look at a function. You don't have to wonder. Is this reading some environment variable? Or is it writing some file or doing something that can change? Um, no, it's just depending exactly on the types that are passed in, right?
>> Yeah. And I think that, you know, helps with your composability, testability as well. You can kind of, you know, construct what you expect the data look like. Pass it through some functions and, you know, test the result like it's not hard to do in Haskell because it's not always a ton of boilerplate you have to set up like if you have your type, you construct it and passed to a function and see what happens right like that, because it's kind of there, um, which I think is a really great benefit.
>> Yeah, And in addition to the testing side of this, uh, the purity of the predictable side effects makes it easy to do equation reasoning, which is kind of a consequence of, or a different way of stating referential transparency, where if you have some definition, wherever you use that term, you can replace it with its definition and keep doing that until you can kind of see how things were gonna work. So, uh, typically, you will see examples on blog post of people doing that with, like, a fold where they have the foldr expression, and then they'll, like, go one step and go another step and keep doing that until it's all reduced down to one term. Um, but you could do that to a smaller scale with various functions throughout your code base just to see how they work. It's pretty powerful.
>> Yeah, for sure. Um, keep on trucking here. He kind of points at how Haskell facilitates. rapid development, worry free refactoring and excellent maintainability. I think here it ITProTV were in love with the maintainability we have with our Haskell repo.
>> We would say that it's egg-cellent.
>> We make an internal joke here that we're all eggs. So it's a very good pun there, Taylor.
>> Yeah, we had a typo three years ago, and it's just puns nonstop since then. Forever and ever. Anyway, Yeah, I think that the maintainability of Haskell is one of its biggest selling points. And in fact, after the uh, Haskell survey last year, I wrote a blog post saying that, uh, Haskell killer application is maintainability because, um, it's painless to change stuff. And that makes it really easy to keep iterating on development. And just, like, improving stuff without breaking stuff all the time, right?
>> Yeah. I want to point back to the rapid development. You know, there's he references ghcid which here at ITProTV We use every single day as something that allows us to be quick When were, you know, writing day to day code, you know, plugging those type holes and we talked about and seeing What? What should we plug in there or, you know Oh, this is a compiler. Let's keep moving. So, you know, there's a lot of I mean, I think ghcid right now is for me the top tool we have in our Haskell tool belt, uh, for rapid development.
>> Yeah, and to give a sense of how rapid it is, I don't have the exact numbers, but I think our code bases like under 100,000 lines. But roughly around there and with ghcid. We can build it and build it and run our test suite in, like, under five or 10 seconds, depending on what exactly you change. But yeah, like if you want quick feedback on a typed hole, you could get that within seconds, which is fantastic.
>> Yeah. You know, another benefit of the type system in general allows us to have a lot of worry free refactoring. Obviously, there's chances that you can create some change in a JSON Key or something along those lines which could create run time errors that you don't catch by the compiler. But 95% of the time, if you're using generics and stuff like that, you're gonna be able to keep that pretty maintains as well as having some unit tests and property tests to make sure to go alongside of that too. Just really ensure that you have a very maintained piece of code and refactoring it. Yeah, gets to be a little easier. A little less stressful.
>> Makes code review a lot nicer to because you don't have to wonder. Does this all still type? Check because you know it does. Because the build does it for you.
>> Like green check Mark. Good to exactly Yeah, Awesome. Let's keep going.
>> Yeah, so the next one is talking about performance. Uh, Haskell programs have stellar performance, uh, leading to faster applications and lower hardware costs. So we've seen this to be true. It's been kind of surprising to me that we're running ah, lot of our infrastructure on pretty much the smallest Amazon instances that we can. And it just works like we haven't really done anything special. No profiling, no, like optimized builds or anything like that. I mean, they're optimized, but not especially optimized. Um, and it just works. Um, and again drawing on my history, I used to work with Ruby applications and we would have maybe scores of them running. And you've got, like, a reverse proxy in front of all of them, and they run out of memory all the time, and then you have to kill them and restart them, and we just don't have to deal with any of that.
>> Yeah, no, I think for me this point was kind of like the Oh, wow. Dang, that's cool. Because he did a great comparison with, you know, scripting language like PHP versus You know the Haskell equivalent, right? They run the same code there. Same in point. Same database usage, Same payload on and are saying load of users. And you know, he you know, the cost is like 1/16 of what? The PHP, uh, you know, runs. And he's running four services rather than four instances of the service rather than the two that he was for PHP. So, like that to me was like, Whoa, like, 16 times smaller.
>> Yeah. I think you got the numbers backwards there. So they were running four copies of the PHP server because they needed the additional infrastructure. And I think they're running two of the Haskell one. Oh, no. Did I? Oh, I got that backwards. Sorry. I'm bad at reading tables. You were right. So, yeah, they're running smaller services and more of them.
>> Yeah. And the, you know, the larger PHP instances had, you know, four dedicated CPU cores.
>> Yeah.
>> Where...
>> And they had, like, 16 times as much. RAM right?
>> Yeah, like half gig RAM on that. Yeah. Since it's just bonkers that you know, they're and they're also outperforming the PHP instances like by, you know, you know, milliseconds, but still yeah, its's still pretty substantial when you're dealing with hundreds of thousands of requests per minute. Like that's important.
>> Yeah, he says. Haskell outperforms PHP by at least an order of magnitude. So I think, yeah, that. I mean, we don't have a like-for-like comparison to make their from our experience. Like you've mentioned earlier. We do have a legacy JavaScript, API that we are migrating away from, but we haven't done any like, Okay, let's move this in point from here to there and measure the performance along the way. But, like I mentioned all of our services are running on tiny AWS machines and it's working great.
>> So, yeah, there's not necessarily for us a reason to we'll keep. We have a lot of other projects going on that we can't really sit there and tweak the benchmarking. Yeah, benchmarking for us isn't as important at the moment now as you scale. You wanna keep that in mind? But for us, it hasn't really been a concern, but yeah, let's get Let's keep moving. We've got the next one, which is Haskell's great for domain modeling and preventing errors in domain logic. Right? So this is about kind of being able to create data types that clearly express what you're trying to do give you records that make sense that keep everybody you know, keep everything in order, allows you to give data types to these specific fields on the record, and you can really crack through and know, Okay, this is this is what I'm dealing with every step of the way.
>> Mhm. And for me, once I had Haskell's data types, like as a tool in my tool belt. I started to wonder how I ever did anything before, because so often what I want is a record of data. So, like a you know, person with a bunch of fields on it, and each of those has their own type. And then in addition to that, I want something that lets me select between different things. So, like usually, this would be an enum and other languages and enums can't have data associated. But in Haskell, you can have whatever arbitrary data on there you want. So you can say, like your two tools here are I have one thing with a bunch of named fields on it, or I have a choice between all these other things. And with those two, you can represent basically everything. And it feels great to do it.
>> Yeah, yeah, ADTs where life changer, for sure. I mean, I've even today I didn't do it in Haskell, but I've been doing a lot in Elm. So far as pattern matching is concerned. And I think that was, you know, just incredible that the compiler can catch that as long as you have the warnings enabled. That's, you know, the Catch 22 there. But you know, you have warn all or warn error you're gonna be able to see if you add something to else to the ADT You're gonna get a compiler and says, Hey, check this out. You're missing non exhaustive pattern matching here, and I think that
>> A good example of this from the blog post is like if you have something that's modeling and invoice in a more, like in javascript, you might have a field on the invoice that says, Is it paid or not? And that thing would be a Boolean, and it's true or false. And then, as your system grows, you like crap we need to represent, Uh, this thing can be canceled in addition to either being not paid yet or paid. Um, and so you would either add another field that says canceled. And then you have to worry about Well, what if it's paid, but but also canceled? Does that even make sense? Um, and in Haskell instead, you can have an ADT that says your status is either unpaid, paid or canceled. And when you go and add that canceled one later, the compiler will tell you these are the places where you need to go update your code. So this ties back with that, you know, powerful. Uh, refactoring and rapid development we were talking about earlier. You just add the constructor and have the compiler tell you not literally everywhere, but almost everywhere you're going to go and need to update.
>> Yeah, No, I think I think it's great. Um I think it's been game changer for me, especially coming from JavaScript previously where I had to deal with those kind of situations and I couldn't clearly say, Hey, I have yeah, you can use a case statement, but it's not really the same. Yeah, you have your matching on a string or number like that's just not how you wanna match on. So, like, being able to have these data types that have this pattern matching is great. Yeah. Um, the next thing we're gonna get into is, you know, as far as Haskell compares to other languages maybe a little, you know, less. But still, just as powerful, um is the amount off libraries high quality libraries that are available where you can look at other languages, like JavaScript that has npm with million's of libraries. And you can look at PHP that has all kinds and, you know, like you can look at any language and there's the ba-jillions. Haskell maybe has a smaller set of that, but everything was high quality. You know what? You what you're getting with? Like there's documentation. There's places to search through it, comprehend what's going on, you know? Yes. You're not going to get ah, third party service to, you know, have some SDK for Haskell. That's most likely not gonna happen, but doesn't mean you can't write it and put it out there for the world. You know, it's a great, great place too. Got some good stuff.
>> Yeah, And I again was surprised, though coming from Ruby, which has many times more packages available than Haskell for pretty much everything we do at work, there is a package already available. And like you mentioned for third party services, there may not be one. But it turns out that having a having the ability to define those custom types that we just talked about makes it really easy to write your own because you say Okay, this is the data model that I'm gonna be sending to them. And this is what I expect back. And then you just plug in an HTTP Library typically in between those and you're off to the races.
>> Mhm. Yeah, like for us. You know, we use Recurly, and we've kind of created our own. Recurly library. I don't know if we've published it anywhere at the moment, but, you know, we're
>> not yet.
>> We have some set of, you know, we know the specifications. We've seen their documentation and we wrote out, you know, specs that can be translated. You know, the data types were all written and all that kind of stuff and It's just kind of there. Um, you know, we don't really have a ton of time to maintain an open source library like that, but, you know, it's possible.
>> Yeah. Um and so, yeah, moving on to the next one? Uh, Haskell makes it easy to write concurrent programs. Um, basically, Haskell's runtime lets you have multiple green threads going at the same time. So unlike JavaScript, where everything is single threaded with Haskell, you can have multiple threads. And this makes doing anything with asynchronous stuff way nicer.
>> Oh, yeah, Yeah. Personally, like in my professional experience, have had too much issue with async and not async. Um, but I know you you have with your Ruby situation.
>> So as I keep mentioning, I used to work a lot with Ruby, and, um, the only option there if you wanted to do something asynchronously was to throw it on a job queue. Because otherwise you would hold up the thread that was serving the request, and you wouldn't be able to serve the next request. So if you wanted to, like, send an email to somebody or when somebody logs in, you want to go like update something in your database, but it's not critical that it gets done before they finish logging in. So you can you want to do it in the background, you would have to make a job for that. Whereas in Haskell, you could just say async. Whatever. And it'll go do it
>> nice. Yeah, I think that's great. So go concurrent programs. Ah, but let's keep moving. We've got I've got a my dog here who's keeps butting into the table. So pardon me if you keep hearing random crashes. Uh, that would be a little puppy being a little puppy. Um, anyways, keep moving. We've got Haskell, enables domain specific languages with foster expressiveness and reduce boilerplate. Yeah, sure.
>> So I think these days the canonical example of a domain specific language. Well, maybe maybe not. SQL is one. So if you wanna interact with a relational database, more likely than not, you're gonna be writing SQL and Haskell makes it really easy to use languages like SQL inside of a Haskell program so that you can, um write Your query using language. Is that you know, already mhm and usually the way this is done is with Template Haskell and one of the examples that he calls out to his persistent And this is used to, like, define your data models and how they get stored to the database and how you query them and it comes with a whole slew of benefits. But for me, I am not the world's biggest fan of DSLs I like him. Okay, But I am. I like embedded domain specific language is a little bit more and an eDSL is something that uses the syntax of the like, quote unquote host language. So instead of like having embedded SQL string in your code, you would write like a Haskell expression that then gets turned into SQL. So for other languages, usually this is a like ORM an object relational manager, library, whatever it is where you like, you know, do user dot find, you know, some ID whatever. And it just creates the SQL for you behind
>> the scenes. Yeah, and I mean, I don't have a ton of experience with DSLs I'm sure you know, with time I will. But I'm definitely looking to kind of understand, like you know the example he gives here persistent, like, we're using it more and more, you know, for SQL and for Mongo. So understanding a little bit more about how those work, Um, it's gonna be really beneficial. Um, but yeah, I think that's awesome. I think the last one is my favorite. Personally, you know, I feel like I've probably said these are my favorite like all of them. But this one's my favorite because it's true. And, you know, Haskell Weekly gets a shout out, but
>> you said it's true. The topic here is that it has a large community filled with smart and friendly people. And yeah, I I agree with this one. Um, you know, as part of running Haskell weekly, I keep an eye on lots of different parts of the community, and, uh, you know, by and large, it's really smart and friendly. If you have a question, people are very happy to help you with it and show you how to do things the right way.
>> Yeah, think that's awesome. You get a little puppy love over here, too runs around, and it's getting really feisty right now. Um,
>> but yeah, it's ah that about wraps up the post. And like we said at the top, you know, we, I guess, feel basically the same as these guys at Foxhound Systems that, um, Haskell has enabled us to write very, um, robust, reliable software and maintain it over time without, you know, ripping our hair out, trying to debug null pointer, nil, null pointer exceptions. And that kind of stuff. Um and yeah, like the last one mentioned, the community is super important, and we're happy to be a part of that. Uh, if you want to, you know, figure out what's going on in the community. Please go check out the Haskell Weekly newsletter. You can read more at haskellweekly.news You can catch us on Twitter on reddit GitHub all over the place. Um, yeah,
>> yeah, yeah. In Haskell weekly is brought to you by our employers ITProTV, which is the e-learning platform for IT professionals. We just wanted to Thank you all for listening on and ITProTV would love to extend a promo code to you guys. That is HaskellWeekly30 for 30% off the lifetime of your membership. So please. Your interested go check out itpro.tv Uh, get your access. You can sign up for a free account if you want. Um, yeah, yeah. Any interest in IT? Please, Please, please check it out
>> for sure. Well thanks so much for listening. See you next time.
>> Peace.