 And so our penultimate talk of the day, I love that word, is Daniella Wellich. Thank you. She has a fan club. I met Daniella when we were both working at Pivotal Labs. And she's now at Sheriff's Post, right? And she studied math in college. And she's going to talk to you today about the equivalence theorem between testing and math proofs. Is that random enough for you? Hi, everyone. The title of my talk, Why is a Math Proof Like a Unit Test? I picked it because it reminds me of a quote by the mathematician Charles Dodgson, why is a raven like a writing desk? And if you recognize that one, it's because it's from Alice in Wonderland. And Dodgson is, in fact, Lewis Carroll. So the original mock riddle didn't have an answer. But maybe this question will. First, let me tell you a bit about myself. So my name's Daniella Wellich, as Josh said. And I've only been programming really for about a year and a half. And before that, and since I was very young, I always knew that I wanted to be a mathematician. So here's what I love about math. I'm the girl on the right saying, oh, hey, I didn't see you guys all the way over there. Because mathematicians live in a world that's based on concept and that they build using a defined set of logical principles. So they don't really need to think about the world of science or reality, because they're often their own little world. There's a joke about a mathematician, an engineer, and a physicist who all gets stuck in burning motel rooms. One night, the engineer wakes up, sees that his hotel room's on fire, and notices that there's a bucket and a faucet. So he starts filling buckets with water and pouring him on the fire until the fire goes out. Then he goes back to sleep. The next night, the physicist wakes up, sees that his motel room's on fire, calculates exactly how much water he needs to put on the fire for it to go out. He pours that much water on the fire. The fire goes out, he goes back to sleep. The third night, the mathematician wakes up, sees that his room's on fire, looks at the bucket, looks at the faucet, says, ah, a solution exists, and goes back to sleep. So this demonstrates that mathematicians live in the world of concept, and they don't have to care about the actual solution to a problem rather than the context of a problem. So this is what I love. I love this about math. So I was studying math and loving it until I realized that academia wasn't for me. And so I ran off with my BA and looked around to see what I could do that I enjoyed in quite the same way. That's when I went to a Rails bridge. And I know that most of you probably heard about Rails bridge today or in the past, but it's a day and a half workshop that aims to get underrepresented groups into Rails. And I met mentors there who were agile developers and convinced me to start using TDD immediately. So I started testing from pretty much the ground up. And then I quickly found myself an agile job that I loved. So the fact that this transition happened so quickly made me wonder what it was about TDD that made me so happy and made me love things, love what I was doing the same way that I felt that when I was studying math. So one day I was coding with my pair and we came across one of those nifty recursive problems that's even more fun in Ruby when you have all those loopy methods to draw from, namely turning this hash of hashes into this array of arrays. And after we finished our implementation and finished our story and started running rake, we got to talking. Now my pair hadn't studied any math formally. In fact, team majored in dance. So he was curious if when I studied math, I'd encountered much recursion. Of course I studied recursion. Math is filled with recursion and recursion itself is a mathematical concept that's based on something called induction. Side note for the purposes of this talk, when I say induction, I mean mathematical induction. And when I say integer, I'm only gonna talk about positive integers. So yes, if you're laughing, you probably care about this distinction. And if you're not laughing, then you don't have to worry about it. So let's talk about induction. Induction is a way of proving things about the integers where you first prove a property is true for one and then show that if it is true for some arbitrary integer n, then it's true for n plus one. As you may have noticed from some of the liberties I've taken in my proof, induction is not actually possible in our spec, but I'll get back to that later after we talked about induction a bit more. So when you prove something is true for n plus one, based on being true for n, basically essentially you're saying that if it's true for one, then it's true for two. So if it's true for two, it's true for three. Therefore recursively, it's true for every integer. So there's some methods in my mock proof, or mock test that I haven't defined yet. So let's talk about them for a second. How many of you remember studying or learning summation notation? All right, lots of hands, but some people aren't raising theirs. So sorry, I got mail. Fuck. Oh, I'm really sorry guys, whatever. I'm closing these tabs. Sorry. Let's take this big again and now we're all happy. All right. So I've messed up once, so I'll be fine for the rest of the talk. Summation notation. Sometimes called sigma notation is a mathematical loop where you add up whatever's to the right of the sigma, which is the zigzag Greek letter. You start, you're where you start and the variable you're using in your loop are on the bottom of the sigma and at the top of the sigma you have your upper bound. I put a Ruby implementation there. You might be saying, why are you using recursion instead of inject? But I mentioned recursion, so I'm using recursion. So what are we trying to prove? We're trying to prove that the sum of the first n numbers is n times n plus one over two. This is one of the classic problems of number theory or classic problems of number theory and is one of the first things that students solve when learning induction for the first time. So the first person to ever encounter this probably started by idly adding up numbers and then noticed this property emerge. So he wondered, hey, does this happen for every integer? And you can convince yourself that this works. If you look at two triangles, each of whom has a number of dots equal to the sum of the first seven integers. So if you put the triangles together, you'll end up with a rectangle that has the number of dots equal to equal to twice the number of dots in either triangle. So you get a rectangle with seven columns and eight rows. So the number of dots is seven times eight. So the number of dots in either triangle is half of that. There's a story that goes along with this property about the mathematician Carl Friedrich Gauss. When he was a little boy, he was a really precocious child and annoyed his teacher to no end by constantly getting any problem put towards him immediately and never giving his teacher a moment's peace. So one day in order to try to shut him up for a bit, his teacher asked him to add up the first hundred numbers. And before his teacher could even pause to take a breath, Gauss shouted out, 5050, because he understood intuitively that the sum of the first hundred numbers is 100 times 101 over two. Now that we know what we're trying to prove a bit more, let's look at it using induction. So where do we start? We start by seeing if this holds for the sum of the first one numbers. So the sum of the first one numbers is just one, which is half of two, so that works. So the next step is to look at it, is to assume that it's true for some arbitrary integer n. So assuming that it's true for n, we want to show that it's true for n plus one. That is that the sum of the first n plus one numbers is n plus one times n plus two over two. So let's start by saying, looking at the sum of the first n plus one numbers. And that's really just n plus one plus the sum of the first n numbers. So the expression that represents the sum of the first n numbers has shown up again, so we can just replace that with the assumption we've made about it. And essentially we still have a failing test because even though we have n plus one plus n times n plus one over two, and that looks close enough to where we're trying to go, we don't have a computer here to do all the little in between steps for us. I mean, yeah, there's a computer here, but. So we have to keep going, and we have to iterate until we get green. So then the sum of the first n plus one numbers is if you turn the first argument into a fraction, two times n plus one over two plus then times n plus one over two, and then you can put those together and flip around the order of the addition to get n times n plus one plus two times n plus one all over two, and we're close, but we still need to look at where we're trying to go and say, am I there yet? Have I reached the point that I'm trying to get to? And we haven't yet. So we pull out the n plus two, and then we get n plus two times n plus one over two. So if we flip those around, then we're green. And we've proven this property holds for all integers because it's true in general for sum arbitrary integer, or for n plus one, given that it's true for sum arbitrary integer. So take a little break. Yeah, so, and we've proved this property and there was much rejoicing. So anyway, now that we've proven this, why doesn't this work in our spec? Let's go back to our mock proof. If you notice when you get to that line that says n equals integer dot new, something weird happens. We get a no method error about this method integer dot new because we can't do that. We can't just create an arbitrary integer. So this test doesn't compile and it doesn't work. So in order to get past this line, we have to do something impossible. So why is this impossible? And why do we even need this impossible step in the first place? So let's first look at why is it impossible, or why is it impossible? When you add, if you wanna try to do this in our spec, you can pick specific integers, for instance, you can pick seven and say, well, it works for seven, therefore it works for eight, but that doesn't show that it works for anything. And even if you loop through 20 numbers and do this 20 times, it still doesn't prove it works for an arbitrary context list number. And even if you pick random numbers, a random number doesn't stand in for any number because showing that it works for random numbers only shows that it works for numbers within the bounds that you give it that pop out of your random number generator. So why do we need this context list number in the first place? The programmers concept of an integer and a mathematicians concept of an integer are different. Programmers build the integers one way and for a mathematician, you build up the integers using axioms like small, thank you, small things that, sorry, small things that seem obvious, but you have to assume in order to make your system work. For instance, one of the axioms that you use to build the integers is there exists zero. And so somewhere in the mathematical source code of the integers, there lies the axiom of induction, which says that if you have a set S that has zero in it, and if it has some N in it, then N plus one is also in that set, then that set is essentially in fact the integers. Sorry, I didn't change it to say integers instead of natural numbers, but. So basically mathematicians build the integers this way such that this works. And when you have, when you have the, when you build integers using like your finite amount of RAM, you can't really say I'm gonna have these things that work recursively on forever and because of that I can stub something out that means anything. So you may have, you may remember the phrase, everything in Ruby is an object. And now Alex, please don't tweet. So everything in Ruby is an object, which means everything in Ruby is an instance of something. For instance, seven is a specific instance of integer and it comes with all of this baggage for being an integer because in mathematics we're really kind of looking for platonic ideals and an object is not a platonic ideal. So for instance with seven, like I said, seven comes with all this baggage. For one, it's prime, it's also one more than six and it's one less than eight. Eight's a cube, so who knows what sort of kinky shit seven gets into for being a Mercedin prime. So you can't really let seven represent any number. So where does this get us? The same thing happens if we're writing a spec. I know that you can say, oh, but we have some classes where we can just define initialize so we can say class.new and get an instance of that class that stands in for anything. But that doesn't mean that you don't have special cases or something like that. For instance, this spec, if you have something that, if you have something where your unit testing this eat mushroom method and you test it for a user named Alice, just because it works for Alice and makes Alice bigger doesn't mean that if you make a username Bob, he'd behave the same way. For instance, Bob might get smaller when he eats the mushroom. So basically your test suite isn't a proof that your code works and it's important to understand what function it really provides if it doesn't work. And so unit tests are heuristics rather than proofs. So heuristic, so when you use a heuristic you use it to study the methods and rules of discovery and invention. So there's a mathematician named George Polia who wrote a book called How to Solve It which is an attempt to revive heuristic in a modern and modest form. And so he, sorry. So he talks a lot about things about heuristics that make sense when you think about what we do if we test drive a problem. For instance, something he says in his book is that it is foolish to answer a question you do not understand. It is sad to work for an end you don't desire. So this basically means that before you solve a problem you have to understand it. And every time we do test driven development say for instance you do outside NTDD and start with your integration test. You make sure you know what problem you're trying to solve because you write a test that'll fail if that doesn't work. And another thing that he basically implies but is a quote that's misattributed to him is that if you can't solve a problem then there's an easier problem you can't solve, find it. So this basically means that you have to break problems down into smaller and smaller chunks until you arrive at the simplest problem and the easiest problem to solve. And we do this too. This might look familiar like when we get test failures we use them to tell us what to do next and what we should do next. So heuristics play a valuable role in helping us guide us through our problems. And Polia stressed the fact that heuristics were not proofs and it was dangerous to look on the mass proofs but he still said that we need heuristic reasoning when we construct a strict proof as we need scaffolding when we erect a building because heuristics are important as a guide and understanding the steps it takes to solve a problem is important as a guide. So when I was taking some time off from college I spent some time tutoring math to inner city kids in Los Angeles and the Los Angeles Unified School District is notoriously not awesome. So their teachers didn't necessarily understand what they were teaching the students and it made it really hard for the students to understand what they were trying to learn. But at that point in my life I'd already taken some number three and I'd already taken some algebra so I understood how you build a number system mathematically and how you and therefore I knew like the axioms that you could use in order to prove that you can do things in a certain way and knowing those building blocks made it easier for me to explain to the students in different words and in words they could understand how to approach the problem they were solving when for instance that problem was adding up fractions or something like that. And this knowledge was really valuable and in the same way I think that understanding math and understanding the differences between test suite and proofs is very important because first of all it can help you explain to other people what you're doing when you're test driving things and it'll help you understand the gap between test driving and proving. For instance, you can figure out that you're, you can figure out what you mean when you say full test coverage because you know that full test coverage doesn't mean my test suite is proven. So in conclusion, approaching tasks in small chunks is more logical and mathematical. So you can use this to help you figure out logically what process you're using to prove something and test driven development is a good tool for the mathematically minded. So for instance, if you have a friend who's very mathy and wants to learn to code, I would highly recommend Agile to them and understanding the heuristics behind a subject increases our ability to impart knowledge. So thanks. Sure, does anyone have any questions? What would you describe as the axioms of software development? Interesting, through me for a loop a bit there. I kind of feel like with software development you have a computer at hand and the computers build things using essentially byte code or whatever and they're built within the confines of being a Turing machine. So I think that something you need to understand implicitly when approaching software development is really where your boundaries are and what those boundaries are. I'm sure I could think of more. Sounds like a good conversation for the party tonight. Yeah. Any other questions? Okay, great. Thank you very much, Danielle. Thank you.