Functional Programming

Summarized using AI

Trust, But Verify (Programmatically)

Ben Orenstein • October 12, 2017 • Earth

In the talk titled "Trust, But Verify (Programmatically)" by Ben Orenstein at the Rocky Mountain Ruby 2017 conference, the focus is on the importance of writing correct code for the future of software development. Ben opens the session with engaging crowd participation before delving into key elements surrounding code correctness and innovative programming practices.

Key Points Discussed:

  • Importance of Correct Code: Ben emphasizes that with the rapid development of complex software systems, such as airplanes and cars containing millions of lines of code, writing correct code is crucial to prevent potentially disastrous errors.
  • Inspiration from Chess: He introduces the concept using chess, referencing Garry Kasparov's defeat to the chess computer, Deep Blue. The synergy between strong chess engines and human grandmasters forms the basis for Ben's argument that combining smart programs with human input can lead to better software development outcomes.
  • Use of Advanced Programming Languages: Orenstein shares his positive experiences with Elm, a programming language that compiles to JavaScript. Elm’s powerful type system helps reduce errors significantly compared to other languages like Ruby, showcasing its potential for writing more reliable code.
  • Type Systems and Error Handling: He illustrates how Elm’s type system enables developers to catch many errors at compile time, drastically reducing runtime exceptions. He provides concrete examples where Elm ensures that functions behave as expected, reinforcing the correctness principle in programming.
  • Handling Nil Values: The talk passionately critiques Ruby's handling of nil, suggesting that Elm’s approach using a Maybe type allows better control and error prevention, leading to more robust code without the common pitfalls of nil errors.
  • Property-Based Testing: Ben introduces property-based testing as a superior method for verifying function correctness. By defining properties that should always hold true, developers can test their functions across a broader range of scenarios than traditional unit testing allows.
  • Real-World Application: Orenstein shares anecdotal evidence and success stories of projects that benefited from Elm’s approach, including property-based testing catching subtle bugs in a JSON encoding library.

Conclusions:

Ben concludes with a call to embrace programs and tools that support developers in their quest for correctness. He argues that by leveraging smart programming languages and methodologies, programmers can focus more on creative coding endeavors rather than mundane error checks, ultimately fostering innovation in software development. He encourages the audience to try out Elm and similar tools for their own projects, highlighting their effectiveness in improving code quality and developer experience.

Trust, But Verify (Programmatically)
Ben Orenstein • October 12, 2017 • Earth

Rocky Mountain Ruby 2017 - Trust, But Verify (Programmatically) by Ben Orenstein

Rocky Mountain Ruby 2017

00:00:14.400 Hey everybody, how's it going? For those of you who have seen me speak before, you know that I usually like to start my talks with something a little weird. This will be no exception; you will not be spared.
00:00:26.110 So, I want to first make sure that we're all sort of in sync. I'm going to count to three, and when I say three, everyone can just clap. Ready? One, two, three!
00:00:38.940 Hmm. Turns out sync needs a little work. Let's try again. Ready? One, two, three!
00:00:45.610 That's so much better! Let’s snap this time. One, two, three! Awesome!
00:00:50.920 Okay, so don't do it yet, but this time, when I get to three, everyone who is able to, please crack your knuckles. It's going to be weird! Anyone want to leave the room before this happens? Okay, ready? One, two... yeah, yeah.
00:01:12.509 That was weird. I like to start my talks with a little bit of disgust; that way, everything seems like an uphill climb afterwards.
00:01:25.299 I'm here today to talk to you about the future. It has no Vim today; no live coding, which is good because I have both hands occupied, so I can’t code with my face.
00:01:31.000 Alright, so I want to talk about the future, and I want to discuss the future of writing correct code. I think this is probably pretty important.
00:01:38.710 It's going to matter. I flew over here on an airplane that has apparently about five million lines of code in it. Yeah, and probably some of those awesome errors that Brittany pointed out, if I had to guess.
00:01:52.689 Not all of that code is safety-critical; I assume, but it's likely that we will soon be riding around in cars that have millions of lines of code in them.
00:02:00.700 Drones will fly over our heads, possibly with millions of lines of code. Trains and planes—it's all going to happen, I think. So writing correct code is important. Maybe that's not super relevant to us; I've never written safety-critical code—code that kills people if it's wrong.
00:02:18.400 But it's really important that code would be correct, even if you're writing web applications. To pick a totally hypothetical example, imagine you wrote some sort of web app that accidentally leaked about a hundred and forty-three million social security numbers out as a quasi-governmental agency. Let's just say that would be bad.
00:02:30.100 So I've been thinking a lot about what the future of writing correct code looks like. How are we going to do it? How do we do it today, and how can we do it better? That's what this talk is about. I asked myself early on: what is a good model? Where can we look for possible inspiration and clues about what this means for us?
00:02:54.910 The answer to me surprisingly came in the form of chess. Does anybody know who this guy is? Yeah, Garry Kasparov, a former world chess champion. For a while, he was the best chess entity in the world.
00:03:06.989 He was undeniably the most correct chess player there ever was. Then in 1997, do you know what happened? He got beat by a computer called Deep Blue, financed by IBM. He lost a six-game match, and this computer was so far advanced from what had been seen before that Garry actually accused the Deep Blue team of cheating, because there was a move in the second game that was so good he was convinced that only a human could have thought of it.
00:03:40.510 Turns out computers get better. Garry lost, and at that point, the best chess playing entity in the world, the most correct one, was this computer.
00:03:45.610 But then something was discovered: if you took a really strong chess engine and had it spit out potential moves to a grandmaster, that combination was stronger than just the chess engine alone. And that's actually still true today! So, if you pair a grandmaster with the strongest chess engine, that combination will beat the chess engine.
00:04:11.410 So today, if you want the most correct chess playing, the answer is a human plus a program to help that human. And I think that's where we're going. I don't think we're going to have much success in making dramatically smarter humans, and even if we did, we'd have to make all of us smarter.
00:04:39.070 But if you can make a really good, really smart program, you can help everyone, even if we don't make anybody else smarter. So I think that's the future—we might as well call it AI if you want to impress people—but programs to help us write programs, programs to check our work.
00:04:56.950 I have some bad news: I don't think Ruby is going to be the answer to this. I know we are at Rocky Mountain Ruby, but I don't think these programs are going to be written in Ruby. That's actually good news, though, because Ruby has been around a long time.
00:05:10.030 We would hope that we can do better, right? We would hope that we wouldn't be stuck with the same language forever and that things wouldn't progress. So that's actually good news.
00:05:22.210 I have more good news: the future is now! I've actually spent the last six months writing code with the help of programs to assist me.
00:05:28.000 It has completely changed things for me. I am writing dramatically more correct code, I am refactoring with much more confidence, and I am enjoying the heck out of it.
00:05:41.559 I want to tell you about the first program I used—my first book was Elm. Somebody asked about that over there. This dovetails nicely with Brittany's talk, because Elm solves a lot of these error message issues for us.
00:05:53.049 How many people have heard of Elm? Okay, how many people have run Elm in production? Aha, yes! Elm is an interesting programming language; it compiles into JavaScript. If you want to write some sort of UI for a browser, the browser is the target.
00:06:08.979 You might use React; you might instead use Elm. Elm has a really powerful type system. It's sort of descended from Haskell. If you've written some Haskell or heard of it, you might have heard people say, 'Oh my God, the types of Haskell are amazing!' And they are.
00:06:34.809 It's sort of like the creator of Elm chopped off the most complex parts of Haskell, simplified them a bit, and made a more beautiful language that still compiles into JavaScript. So, we don't have to write JavaScript, and the generated JavaScript can be quite correct.
00:06:52.029 I've been writing a lot of Elm and liking it quite a bit. Notice how we had a lot of people who have heard of Elm, but only a few who have run it in production? I think Elm is about to cross the chasm from something that only a couple of early adopters are using to something that crosses over into mainstream acceptance.
00:07:07.869 Enough people are using it, and enough companies are using it that people can trust that it's going to be good. That's part of my mission; I'm trying to help across the chasm right now. I'm hoping to inspire some of you to try this out.
00:07:18.669 Correctness is a pretty good measure. How many runtime exceptions do you get? Because every runtime exception is like—oh no, you screwed up; there's a thing that you didn't anticipate, something went wrong.
00:07:36.549 If you're running a pretty popular app that gets a decent amount of traffic, you're probably getting lots of these. Like, how many people have seen, like, ten exceptions a day? No? Okay, just me. I feel like if you look in your Honeybadger logs, you will be contradicted!
00:07:53.190 Runtime exceptions are not so good. Here's an example: there is a company that is running a hundred thousand lines of Elm. They're an early adopter and have embraced Elm very hard.
00:08:03.580 They've been running it for about three years in production. How many runtime exceptions do you think they had in those three years? Zero. None. I challenge you to write a hundred lines of JavaScript and run it for three years and get zero runtime exceptions. I don't think you can do it.
00:08:21.370 The reason you get so few runtime exceptions in Elm is because it has a type system. I know you've probably heard of type systems before. You might have experienced some type systems, maybe you wrote some Java and said, 'Yes, type systems are no good; Java is so verbose. I hate it!'
00:08:39.910 Not all type systems are created equal; Elm's type system is amazing. Let's look at some examples of Elm code, and I'll talk about the type system in these examples. So this top line is a type signature. It says the function 'length' has type: it takes a string and returns an integer.
00:09:05.700 Here are examples below: 'length' takes 'hey' and returns 3. Your length function takes an empty string and returns 0. This one line of code, which is simple to type and easy to think about, gives you quite a lot of security and guarantees.
00:09:22.390 So, the Elm type system will look through all calling sites of 'length' and make sure you only ever pass it a string. You cannot compile an Elm program that passes something that’s not a string to your length function. That's a guarantee: if it compiles, you have never done that.
00:09:39.190 Also, Elm will look through the body of the 'length' function, no matter how complex, and make sure it always returns an int. It will walk through all of the branches of your if statements, your case statements. You can't fool it. It knows you always return an int, guaranteed. That one line gives you so much security.
00:10:06.720 Here's another example: 'concat'. This takes a list of strings and returns a string. Here's our example down below. You can see our list and our output, exactly the same: you can never call this function if you're not passing in a list of strings, and it will always return a string. Strong guarantees!
00:10:28.720 Last example: here’s 'repeat'. This is a little bit of a new idea that you haven't seen yet. The 'repeat' function takes an int and some type 'a', returns a list of 'a's. Here’s our examples. We 'repeat' takes a 3, let's say, and an 'irand' (which is a string), and it returns a list of 'iran'.
00:10:48.020 Alright, nice! I wasn't sure if that was going to work. So this 'a' right here just stands for any type. Send me an int and something, and I'll make sure to send you a list of those somethings back. And again, that one-line Elm guarantees that this is true.
00:11:07.420 It's like a contract; it will not compile if this is not true. Furthermore, type signatures also make great documentation. So here we say the 'is admin' function takes a user and returns a boolean. That's pretty clear! It's like executable documentation.
00:11:25.700 I bet you could write that function just given that type signature. Now let’s take a look at 'map' in Ruby. This is some new syntax you haven't seen yet, but this says the type of 'map'. 'map' takes a function from A to B—that's what's in the parentheses—and a list of 'a's, and it returns a list of 'b's.
00:11:40.780 This makes sense if you sort of think about this in Ruby. Imagine you have a function from string to int, and a list of strings. You get back a list of ints. Every time you call 'map', Elm checks to make sure that this is working correctly. This type system makes a big difference.
00:12:02.519 It lets you have some pretty incredible error messages, which I wish Brittany could see. Here we go: the branches of this if produce different types of values! The 'then' branch has type string, but the 'else' branch is number. This needs to match so that no matter which branch we take, we always get back the same type of value. Right? That's a pretty darn good error message!
00:12:18.960 There’s actually a repo of all the possible error messages that an Elm program can generate. People file issues against this repo saying, 'This error could be better,' and they will add hints down at the bottom or links to further documentation.
00:12:36.190 Here’s another example, and this is the kind of thing that trips up newbies. They add an explicit error for this: 'This condition does not evaluate to a boolean value, true or false.' This is a common thing. So if you're a Ruby programmer, you probably assume that you can use this sort of truthiness type.
00:12:55.260 For instance, like the list length is this—you can use it in an if. Elm says, 'You haven't given me a condition with this type, int, but I needed it to be bool.' Hint: Elm does not have truthiness, such that lists and integers are automatically converted to booleans. You must do that conversion explicitly.
00:13:12.470 This kind of friendliness is all throughout the language; it's like having a friend debug your code for you. This is the kind of thing you can get with a type system and a smart compiler. This is a program helping me write programs. This stuff is a big deal!
00:13:32.860 I want to turn now to one of my favorite topics, which is nil. My favorite—I mean least favorite! I tweeted this a while ago.
00:13:49.890 The sad truth: a year! This is funny because it's true; unfortunately, I wish it weren't. Challenge: try this with your co-workers for a few weeks and see how long it takes them to catch on that this is all your doing during code review!
00:14:07.890 ‘Can this be nil?’ What happens when this—Ruby loves to return nil when Ruby doesn't know what's gone wrong? Nil is, 'Oh, no! Something went wrong. What should we do? Return nil! It'll be great.'
00:14:22.790 So, let's go back to those Honeybadger errors, or your whatever error tracker you happen to be using. Whose most common error is 'No method error on nil?' Oh yeah! Everybody? Everybody? Those are classic errors. Go check it if you don’t believe me! If there were a quintessential Ruby error, it would be that one.
00:14:41.490 It would be that you got 'nil' somewhere and you accidentally called something on it, like what's the bug there? You thought you had a thing but you actually had nil, and you tried to call something on that nil.
00:14:58.600 Ruby's answer to this problem of, 'Hey, nil shows up all the time' is: 'Never forget to check for nil!' Just be perfect! You should always assume that something might be nil and you should have tons and tons of guard clauses all over the place.
00:15:14.640 Right? Nobody writes code like this. We read it very directly. We write a very simple unit test that has a perfect real-world scenario, and it passes.
00:15:31.440 Great, everything's good! Move on! And then later somehow that whatever thing is not there, you get a nil and it blows up, and you get an exception at runtime, which is when your users see it.
00:15:46.890 Let's talk about how Elm handles this. Here’s a concrete example. There’s a type called 'person.' A person is like an object and it has two pieces of data: it has a name, which is a string, and an age, which is an int. Then we have this 'can vote' function that takes a person and returns a boolean.
00:16:12.640 So we say, 'If the person's age is over 17, true; otherwise, false.' Okay, so imagine this scenario: we've written this code and we go, 'Oh, actually, you know what? A person might not always have an age. We might not always know the age of somebody. What do we do then?'
00:16:30.520 Well, Elm has an awesome answer! Ruby's answer would be: check for nil everywhere, every single time you use age! Don't forget to check for nil, and you go, 'Right! Definitely, I'm going to do that! I'm going to go do something else instead, and we're going to blow up in production all the time!'
00:16:49.620 Here's what Elm does: Elm has this interesting type called 'Maybe.' It’s like it has this interesting 'Maybe' in it; I kind of like that a lot, actually.
00:17:03.960 What we’ve done here is actually—think of 'Maybe' as a wrapper. We're sort of wrapping up the int that may or may not be there, and everywhere that we want to look at the person's age, we have to explicitly unwrap and say, 'I know this is not an int; it's actually a Maybe int. It's in that Maybe box.'
00:17:19.160 Since the Maybe box may have an int and it may have nothing, I will handle both sides. I'll handle both things, and Elm will not compile if you don't handle both things. You cannot forget to handle both things; it just will not compile!
00:17:36.190 So everywhere you go access that person's age, you have to say what you want to do if it's not there. That sounds a little annoying, but it's actually rigorous; it’s really saying we want our code to be correct.
00:17:56.190 If you're telling me that sometimes age is not there, you’ve got to tell me what I should do when it's not there.
00:18:10.950 Don’t worry about too much of the syntax here; there are some concepts we haven't covered, but here’s our new 'can vote' function when we switch into a Maybe int.
00:18:25.080 It basically just translates. It says let's look at the person's age: case 'person.age'. What's that? We look at their age: if they actually have an age and that age is over 17, then return true. If it's under 17, return false.
00:18:45.390 But if they don't have an age at all, then return false. So Maybe can be just 'Nothing'. It’s not so important that you understand that, but the clear thing here is that there's a line saying: this is what I want you to do when the age is actually there.
00:19:01.160 This kind of thing shows up in Ruby a lot; if 'age' is not present, Maybe you might get that. But basically, Elm won't compile if you eliminate lines of code that say here's what you should do when 'age' is not present.
00:19:19.080 This reduces so many bugs. It might be hard to imagine how this works in practice; I can tell you, once you get used to working with Maybe, looking at Ruby will give you panic attacks!
00:19:35.290 You’re like, 'Is that a Maybe? Isn't that a Maybe? Is that a Maybe?' It's such a difference, such a high level of rigor, and it prevents so many bugs. You'll never ever get a 'No method error on nil' in Elm; it just won't even compile!
00:19:51.420 So, I’m going to make a bold claim now—I’m echoing a bold claim, but I’m adding my emphasis to it. A former coworker of mine, who has written a lot of Elm, and he's written a lot of Ruby, says: 'I would have more confidence in a codebase that was an Elm codebase with no tests than a Ruby codebase with tons of tests.'
00:20:08.430 And that’s pretty huge because my code-to-test ratio is like two to one, ish—maybe one point eight to one. I’m running a lot of test code. I’d love to not write test code, and it turns out if your type system is strong enough, you need to write way fewer tests.
00:20:26.920 So you can go a lot faster, make fewer errors, and do less work because we have programs to help us write programs, and we should be using them.
00:20:41.900 I’ll talk to you about a real-world example—this is some Elm code I wrote. I decided I wanted to make a sort of image Evolver, and so I have a goal image and I want to randomly mutate my way from a set of random polygons into that image.
00:20:59.250 So, say I have a picture of my face and I will throw down a hundred random polygons on a canvas in the browser. I will mutate them, and if that image looks more like my face than it did before, I’ll keep that version and mutate from there. If not, I will throw away that mutation and try again.
00:21:16.380 It’s kind of like a hill climbing, like a naive hill climbing algorithm. I'm just sort of making these random changes, and every so often that change is closer to where I want to go—okay, that becomes my new baseline.
00:21:33.250 So here’s an example: on the left is the goal image, and those are the set of squares. On the right, we have 125 random polygons—random colors, random positions, and random transparency.
00:21:50.530 You’re watching the mutate; the bottom-left number is how many iterations. The bottom right number is our current similarity to the goal image, and you can kind of see we’re getting there.
00:22:07.030 You see how this flickering because it's trying lots of things, it's like, 'Is this better? Is this better?' It just picks, it'll pick like twenty polygons at random and change random things like one of their vertices: the color, the opacity—it just tweaks it and we're starting to get recognizable!
00:22:25.160 So this is a program I wrote because I want to kind of flex my own skills and see what this was like. Here is another example; this one’s just static. Faces are harder. The more detail there is, the harder it is. But you can see we’re getting there.
00:22:41.420 I wrote this program, and in the original version, I used circles instead of polygons on the canvas because it sounded simpler. I was like, 'Well a circle just has a center and a radius and that seems easier than a polygon that has a list of vertices, and I need to keep track of.'
00:22:57.240 I was new to Elm so I was like, 'I’ll just use circles!' So I built the first version and I got it working and I was like, 'Okay, this is going to work a lot better with polygons; I’m going to have to do this refactor.'
00:23:13.750 I made a new branch and was like, 'This is probably going to suck.' Here we go—by way of comparison, imagine you’ve written a Rails app and it’s a to-do app. You can create a to-do, you can rename it, assign it, and complete them.
00:23:34.190 And then someone comes along after a couple of days, and is like, 'Hey, guess what? That to-do app, we're actually going to make it now be an issue tracker for software development teams. So to-dos, we should rename to issues!'
00:23:49.590 And to-dos no longer have a due date, and when you assign it, you might actually assign it to a team of people instead of a single person. You have this change to a very fundamental data structure in your app! That's what I was changing.
00:24:00.670 The circle data structure was in basically every function of my app; it flowed through all the way the Elm map, and I was like, 'Okay, this is going to be pretty terrible.'
00:24:15.120 I made the change; the top-level said, 'Okay, hey, Elm, circles are nothing anymore. Now they're polygons, and they don’t have a center; they have a list of vertices.' A vertex looks like this, and these are the coordinates and all that.
00:24:32.370 And Elm immediately spits out like 15 errors. Oh my gosh, here we go! I guess the first error, and it's pretty simple in Elm, is like, 'Hey, you gave me a circle, and you need to give me a polygon.' I was like, 'Okay, no problem!'
00:24:47.460 It’s like, 'Oh hey, you referenced a radius and that’s not a thing anymore!' Yeah, now it’s a vertex. I very mechanically walked through this list of sixteen or so errors that actually were pretty straightforward.
00:25:03.260 They were well-explained and they're pretty easy, and then I finished and I solved the last one and it compiled. And I was like, 'No way!' I refreshed my browser, and it worked perfectly the first time.
00:25:19.960 I got goosebumps when that happened! It's just, oh my god! There were no tests in this. I was new to this thing; I wasn’t ready for any tests!
00:25:33.600 The type system and the compiler walked me through what would have been a really hairy refactor in any other language. It was simple! I never stressed. As soon as it compiled, it worked perfectly. It's just so mind-blowing!
00:25:50.920 Alright, let's talk about a second program that I've been using to help me write better code: property-based testing. Is anyone familiar with this? Okay, wow, not even at the chasm yet—awesome! This is great; I'm excited for you!
00:26:06.720 Okay, so let's say we want to write a function, and we want to make sure that the function is correct. So we’re like, 'Cool! We’re going to be good programmers!' We’ll write some unit tests. Let's think of an input.
00:26:25.340 Let’s say we have a 'reverse' function; I should pass it a list of three items, and then, when I call 'reverse' on that, it should be reversed. So we hand-write an input and we hand-write an output, and we say those should be the same.
00:26:41.490 And we did it a couple more times, and we're like, 'That seems good!' And we move on with our lives. We often miss a lot of edge cases, and it's because it’s annoying to come up with lots of inputs and think of lots of edge cases.
00:26:54.780 It’s annoying to have all that test code there. If you write 500 lines of tests for a 'reverse' function, you’re like, 'This seems stupid! Why am I spending all this time here?'
00:27:10.230 So property-based testing takes a different approach. It says, 'Hey, you know, thinking up test cases and checking that they’re correct? That sounds like a great job for a program! That's not a great job for a human!'
00:27:29.750 So let's imagine we are testing this reverse function with property-based testing. Instead of coming up with test cases, you come up with properties. Properties are things that are always true for the function you’re testing.
00:27:47.480 Can anyone think of a property that should hold for the reverse function? No matter what input we have, what should be true about the output? Can anyone think of some properties? Yeah, absolutely! That's a great one!
00:28:03.480 No matter what input I throw into reverse, the output of reverse should have the same length as the input, right? That should always be true unless something is horribly wrong! Excellent! Really good!
00:28:23.850 Any other ideas, any other properties? Yeah, it should still be a list! Absolutely, the type should be right, and we should still have a certain number of things.
00:28:32.890 We shouldn't lose elements or gain elements; we shouldn't accidentally duplicate things! Awesome. So just armed with those three properties that we just rattled off, we can then have property-based testing.
00:28:49.850 Elm has a property-based testing framework that generates us lots and lots of inputs and ensures that for every input the properties hold.
00:29:04.429 So, it says okay, here’s an empty list; do the properties hold? Yes! Okay, here is a list with 10,000 items; okay, the properties hold! Here’s a list with 20 Unicode items followed by some integers with a null byte tacked on at the end; okay, the property still holds!
00:29:22.760 It thinks of these lots of nasty edge cases for your code for you and makes sure that they’re right; so unlike a unit test, where you run five examples, you say, 'Okay, those tests pass,' a property-based test just hasn't failed yet.
00:29:37.710 So it will basically run, let’s say, a hundred different inputs through your function, make sure the properties hold, and say, 'You’re good!'
00:29:53.470 Let's move on to the next thing and you throw those in your test suite, and you basically have code testing your code for you.
00:30:09.300 This is a pretty big win! So here’s a question: Does this stuff actually work in practice? Does it actually catch real-world bugs?
00:30:25.640 And the answer is: yes! Here’s a real-world example that a friend of mine ran into. He had written some tests for a JSON encoding and decoding library.
00:30:43.790 When you have an encoding and decoding pair like that, property-based testing really shines because you can say, 'Generate me some input, encode it, decode it, make sure I have the same input back!'
00:31:01.010 You basically round-trip all the way through your program and back, and say, 'I should have that same thing back!' You can generate me a list of things, and I want you to make sure that everything works this way.
00:31:19.950 This is like a really powerful property and a really powerful test, and you can just set it up and say, 'That should be true. Throw examples at this all night. I’ll be back in the morning and run a billion tests through that, testing your encoder and decoder.'
00:31:37.570 He tried this and his tests almost immediately failed. He discovered something: when he encoded something, it had microsecond precision, and when he decoded it, it was down to millisecond precision; it had truncated that precision at the end!
00:31:55.920 Now does that matter? Maybe! For them, it actually matters! If you compare these two times, are they equal? That sounds like an opportunity for a pretty subtle bug where two times look like they should be equal when you encode and decode but they’re off by microseconds.
00:32:06.500 This is the kind of thing: how could you find this in a unit test? Can you imagine catching this in a unit test? Probably not! But this is the kind of thing that property-based testing catches with ease.
00:32:18.710 I'm just about done, and I want to tell you one more thing. Does anybody know who this is? David Allen? Yeah!
00:32:36.490 David Allen came up with a system called 'Getting Things Done,' and one of the core tenets of getting things done is that when you think of a thing you want to do, even if you maybe want to do it, you need to throw it in a system that you trust.
00:32:53.540 You need to get it out of your head because, as he says, 'Brains are for having ideas, not for remembering things.' I think we should take that and apply it to programming.
00:33:10.160 We realize that our brains are for dreaming up programs—programs that are ambitious and change the world and do wonderful things, and they are not for chasing down 'nil' and watching for edge cases and worrying about microseconds!
00:33:26.770 So that’s the talk! If you liked this, this is my newsletter; you will probably like the things I send out. I’m really fired up about Elm these days, so I talk about it a fair amount.
00:33:39.000 I’m also about to launch a course called 'Refactoring Rails' about taking care of aging Rails apps. So, if you have an aging Rails app and you're starting to feel the pain, you might enjoy that too.
00:33:56.850 If you sign up there, I’ll send you information about that course as well. Thanks very much! It’s been a lot of fun!
00:34:09.220 I had to write some things down. Okay, I had some complaints.
00:34:17.320 Yes! Good, good, good! The complaint is open. The first one is that you went through an example of demanding biographical details of a person’s age and name, all anchored around the discussion of `Maybe`, and you passed up the opportunity for phone number leading to obvious 'Call Me Maybe' jokes.
00:34:31.130 Oh, damn! Second strong criticism: more grievous! I was actually about to shout it, but I was like, 'No, I don’t want to blow the punchline!' And it never came! It looks like you were writing a CRUD app!
00:34:44.630 Would you like help with that? With a little Clippy graphic? Okay! Programs, I write programs!
00:34:58.340 Yeah, sure! Sure, sure! I thought that was coming in the intro!
00:35:05.360 Okay, other than that, all sold! I don’t know if anybody else, like—I used to do Java a long time ago, and just like types is a thing I have found myself craving, especially in teaching.
00:35:21.410 Seeing like a precondition, postcondition, or like input type-output type was honestly, I was like, it's like you're going home—it's so beautiful!
00:35:35.000 And like the error message about the type mismatch coming out of that if was like really, really neat!
00:35:42.790 And if you didn’t see those things, if you saw those things, you're like, why would I care? Then just look into those Honeybadger logs! Yeah, exactly!
00:36:04.610 So aside from my private commentary, is it time for a couple of questions?
00:36:17.170 Yeah, is there like comment Ruby contracts? That's called!? So I can actually recommend a gem—if you like the 'Maybe' idea, and you want to try it out in Ruby, it's not going to be as slick as Elm, but if you look at the 'wrapped' gem.
00:36:31.210 Like I said, some former co-workers of mine said like, I miss Maybe; so here’s the concept.
00:36:44.490 And it's not quite as slick, but it'll give you a sense of it. Yeah, yeah!
00:36:55.420 So, if you can't hear, he said he’s calling me out because in the past I have prescribed null objects as an answer to that nil problem.
00:37:07.330 And I don’t think what I said was in conflict with that, which is that nil is the problem and there are various ways to solve it.
00:37:20.610 I have really liked Elm a lot now! I would rather have a Maybe than a null object most of the time!
00:37:29.330 But because it’s enforced by the type system, if a thing expects an int, you can never hand it a Maybe int. It's just like, I'm not interested in that type; you've got to give me an int!
00:37:45.170 And you just can never forget, whereas you can still have runtime errors with a null object, right? You have a null object standing in for a user, like you have a guest, let’s say.
00:37:58.590 Then you call 'last signed in,' and you're like, 'Oh! I didn’t actually define last signed in on that! That object and it blows up! Yes!
00:38:12.190 So the question was: Is there a testing framework for Elm? And there is! Yeah, so that generate, that property-based testing is available in Elm as well.
00:38:27.820 So there's an Elm test library, it has normal unit testing, like you're used to seeing, but also they have called fuzz testing, but it's the same concept.
00:38:42.200 What are the major hurdles around getting Elm in production? That's a good question! I don’t think it’s mostly cultural—honestly, at this point it feels technologically ready.
00:38:57.920 There are fairly easy ways to get it working in like the Rails asset pipeline, for example, as like a Thappa—they are running quite a bit of Elm. It’s happening!
00:39:11.240 I think it’s mostly just like, do people trust it? We’re at that phase where people need to look around and say, 'Are other companies that are sort of conservative like us using it?'
00:39:29.750 Okay, fine—we'll use it! I think that’s where we’re at.
00:39:37.870 That's it. That’s all.
Explore all talks recorded at Rocky Mountain Ruby 2017
+4