 Welcome to the very last session of RailsConf. When I leave this stage, they are gonna burn it down. I have a couple of items of business before I launch into my presentation proper. The first of which is turning on my clicker. I work for Living Social. We are hiring. If this fact is intriguing to you, please feel free to come and talk to me afterwards. Also, our recruiters brought a ton of little squishy stress balls that are shaped like little brains. As far as I know, this was a coincidence, but I loved the tie-in, so I brought the whole bag. I had them leave it for me. So if you would like an extra brain, please come talk to me after the show. Quick note about accessibility. If you have any trouble seeing my slides, hearing my voice, or following my weird trains of thought, or maybe you just like spoilers, you can get a PDF with both my slides and my script at this URL. It's tinyurl.com cog-shorts-railsconf. I also have it up here on a thumb drive, so if the conference Wi-Fi does what it usually does, please go see Evan Light up in the second row. I'm going to leave this up for a couple more minutes, and I also want to give a shout-out to the Opportunity Scholarship Program here. To go at the RailsConf site, this program is for people who wouldn't usually take part in our community, or who might just want a friendly face during their first time at RailsConf. I'm a huge fan of this program. I think it's a great way to welcome new people and new voices into our community. This is the second year that I volunteered as a guide, and this is the second year I've met somebody with a fascinating story to tell. If you're a seasoned conference veteran, I strongly encourage you to apply next year. Okay, programming is hard. It's not quantum physics, but neither is it falling off a log. And if I had to pick just one word to explain why programming is hard, that word would be abstract. I asked Google to define abstract, and here's what it said. Existing in thought or as an idea, but not having a physical or concrete existence. I usually prefer defining things in terms of what they are, but in this case, I find the negative definition extremely telling. Abstract things are hard for us to think about precisely because they don't have a physical or a concrete existence, and that's what our brains are wired for. I normally prefer the kind of talk where the speaker just launches right in and forces me to keep up, but this is a complex idea, and it's the last talk of the last day, and I'm sure you're all as fried as I am. So here's a little background. I got the idea for this talk when I was listening to the Ruby Rogues podcast episode with Glenn Vanderberg. This is lightly edited for length, but in that episode, Glenn said, the best programmers I know all have some good techniques for conceptualizing or modeling the programs that they work with. And it tends to be sort of a spatial visual model, but not always. And he says, what's going on is our brains are geared towards the physical world and dealing with our senses and integrating that sensory input. But the work we do as programmers is all abstract, and it makes perfect sense that you would want to find techniques to rope the physical sensory parts of your brain into this task of dealing with abstractions. And this is the part that really got my attention. He says, but we don't ever teach anybody how to do that or even that they should do that. When I heard this, I started thinking about the times that I've stumbled across some technique for doing something like this, and I've been really excited to find a way of translating a programming problem into some form that my brain could really get a handle on. And I was like, yeah, yeah, brains are awesome. And we should be teaching people that this is the thing they can do. And I thought about it. And sometime later, I was like, wait a minute, no, oops. Brains are horrible. And teaching people these tricks would be totally irresponsible if we also didn't warn them about cognitive bias. I'll get to that in a little bit. This is a talk in three parts. Part one, brains are awesome. And as Glenn said, you can rope the physical and sensory parts of your brain as well as a few others I'll talk about into helping you deal with abstractions. Part two, brains are horrible and they lie to us all the time. But if you're on the lookout for those kinds of lies that your brain will tell you, in part three, I have an example of the kind of amazing hack that you just might be able to come up with. Our brains are extremely well adapted for dealing with the physical world. Our hind brains, which regulate respiration, temperature and balance, have been around for half a billion years or so. But when I write software, I'm leaning hard on parts of the brain that are relatively new in evolutionary terms and I'm using some relatively expensive resources. So over the years, I've built up a small collection of techniques and shortcuts that engage specialized structures in my brain to help me reason about programming problems. Here's the list. I'm going to start with a category of visual tools that let us leverage our spatial understanding of the world and our spatial reasoning skills to discover relationships between different parts of a model or just to stay oriented when we're trying to reason through a complex problem. I'm just going to list out a few examples of this category quickly because I think most developers are likely to encounter these either in school or on the job and they don't have the same basic shape, their boxes and arrows. There's N and D relationship diagrams which help us understand how our data is modeled. We use diagrams to describe data structures like binary trees, link lists and so on. And for state machines of any complexity, diagrams are often the only way to make any sense of them. I could go on, but like I said, most of us are probably used to using these at least occasionally. There are three things that I like about these tools. First, they lend themselves really well to standing up in front of a whiteboard, possibly with a coworker. And just standing up and moving around a little bit will help get the blood flowing and get your brain perked up. Second, diagrams help us offload some of the work of keeping track of things of different concepts by attaching those concepts to objects into two-dimensional space. And our brains have a lot of hardware support for keeping track of where things are in space. And third, our brains are really good at pattern recognition. So visualizing our designs can give us a chance to spot certain kinds of problems just by looking at their shapes before we ever start typing code in an editor. And I think that's pretty cool. Here's another technique that makes use of our spatial perception skills. And if you saw Sandy's talk yesterday, you'll know this one, it's the squint test. It's very straightforward. You open up some code and you either squint your eyes at it or you decrease the font size. The point is to look past the words and check out the shape of the code. This is a pathological example that I used in a refectoring talk last year. You can use this technique as an aid to navigation as a way of zeroing in on high-risk areas of code or just plain to get oriented in a new code base. There are a few specific patterns that you can look for and you'll find others as you do more of it. Is the left margin ragged as it is here? Are there any ridiculously long lines? There's one towards the bottom. What does your syntax highlighting tell you? Are there groups of colors or colors sort of spread out? There's a lot of information you can glean from this. Incidentally, I've only ever met one blind programmer and we didn't really talk about this stuff. If any of you have found that a physical or a cognitive disability gives you an interesting way of looking at code or understanding code, I suppose, please come talk to me because I'd love to hear your story. Next step, I have a couple of techniques that involve the clever use of language. The first one is deceptively simple but it does require a prop. It doesn't have to be that big. You can totally get away with using the souvenir edition. This is my daughter's duck cow bath toy. What you do is you keep a rubber duck on your desk. When you get stuck, you put the rubber duck, excuse me, on top of your keyboard and you explain your problem out loud to the duck. Really. I mean, it sounds absurd, right? But there's a good chance that in the process of putting your problem into words, you'll discover that there's an incorrect assumption that you've been making or you'll think of some other possible solution. I've also heard of people using teddy bears or other stuffed animals and one of my coworkers told me that she learned this as the pet rock technique. This was a thing in the 70s. And also that she finds it useful to compose an email describing their problem. So for those of you who like me, think better when you're typing or writing than when you're speaking. That can be a nice alternative. The other linguistic hack that I got, I got from Sandy Metz. And in this book, Practical Object-Oriented Design in Ruby, Pooter for short, she describes a technique that she uses to figure out which object a method should belong to. I tried paraphrasing this, but honestly, Sandy did a much better job than I would describing it, so I'm just going to read it verbatim. She says, How can you determine if a gear class contains behavior that belongs somewhere else? One way is to pretend that it's sentient and to interrogate it. If you rephrase every one of its methods as a question, asking the question ought to make sense. For example, please, Mr. Gear, what is your ratio seems perfectly reasonable. Well, please, Mr. Gear, what are your gear inches is on shaky ground and please, Mr. Gear, what is your tire size is just downright ridiculous. This is a great way to evaluate objects in light of the single responsibility principle. I'll come back to that thought in just a minute. But first, I described the rubber duck and please, Mr. Gear as techniques to engage linguistic reasoning. That doesn't quite feel right. Both of these techniques force us to put our questions into words, but words themselves are tools. We use words to communicate our ideas to other people. As primates, we've evolved a set of social skills and behaviors for getting our needs met as part of a community. So while these techniques do involve using language centers of your brain, I think they reach beyond those centers to tap into our social reasoning. The rubber duck technique works because putting your problem into words forces you to organize your understanding of a problem in such a way that you can verbally lead another mind through it. And please, Mr. Gear, let's us anthropomorphize an object and talk to it to discover whether it conforms to the single responsibility principle. To me, the telltale phrase in Sandy's description of this technique is asking the question ought to make sense. Most of us have an intuitive understanding that it might not be appropriate to ask Alice about something that is Bob's responsibility. Interrogating an object as though it were a person helps us use that social knowledge and it gives us an opportunity to notice that a particular question doesn't make sense to ask any of our existing objects, which might prompt us to ask if we should create a new object to fill that role instead. Now, personally, I would have considered pooter to have been a worthwhile purchase if please, Mr. Gear was the only thing I got from it. But in this book, Sandy also made it what I thought was a very compelling case for UML sequence diagrams, where please, Mr. Gear is a good tool for discovering which objects should be responsible for a particular method. A sequence diagram can help you analyze the runtime interaction between several different objects. At first glance, this looks kind of like something in the boxes and eras category of visual and spatial tools. But again, this feels more like it's tapping into that social understanding that we have. This can be a good way to get a sense for when an object is bossy or when performing a task involves a complex sequence of several interactions or if they're just playing too many different things to keep track of. Rather than turn this into a lecture on UML, I'm just going to tell you to go buy Sandy's book. And if for whatever reason you cannot afford it, come talk to me later and we'll work something out. And for the really hand-wavy stuff. MetaForce can be a really useful tool in software. The turtle graphic system in logo is a great metaphor. Has anybody used logo at any point in their life? About half the people, that's really cool. We've probably all played with drawing something on the screen at some point. But most of the rendering systems that I've used are based on a Cartesian coordinate system, a grid. And this metaphor encourages the programmer to imagine themselves as the turtle and to use that understanding to figure out when they get stuck what they should be doing next. One of the original creators of logo called this body-syntonic reasoning and specifically developed it to help children solve problems. But the turtle metaphor, the turtle metaphor works for everybody, not just for kids. Cartesian grids are great for drawing boxes. Mostly great. But it can take some very careful thinking to figure out how to use XY coordinate pairs to draw a spiral or a star or a snowflake or a tree. Choosing a different metaphor can make different kinds of solutions easy where before they seemed like too much trouble to be worth bothering with. James Ladd in 2008 wrote a couple of interesting blog posts about what he called East Oriented Code. Imagine a compass overlaid on top of your screen. In this model, messages that an object sends to itself go south and any data returned from those calls goes north. Communication between objects is the same thing rotated 90 degrees. Messages sent to other objects go east and the return values from those messages flow west. What James Ladd suggests is that in general, code that sends messages to other objects, code where information mostly flows east, is easier to extend and maintain than code that looks at data and then decides what to do with it which is code where information flows west. Really, this is just the design principle, tell, don't ask. But the metaphor of the compass recasts this in a way that helps us use our background spatial awareness to keep this principle in mind at all times. In fact, there are plenty of ways we can use our background level awareness to analyze our code. Isn't this adorable? I love this picture. Code smells are an entire category of metaphors that we use to talk about our work. In fact, the name Code Smell itself is a metaphor for anything about your code that hints at a design problem which I suppose makes it a meta metaphor. Some code smells have names that are extremely literal, duplicated code, long method and so on but some of these are delightfully suggestive, feature envy, refused bequest, primitive obsession. To me, the names on the right have a lot in common with please, Mr. Gear. They're chosen to hook into something in our social awareness to give a name to a pattern of dysfunction and by naming the problem to suggest a possible solution. So these are most of the shortcuts that I've accumulated over the years and I hope that this can be the start of a similar collection for some of you. Now the part where I try to put the fear into you. Evolution has designed our brains to lie to us. Brains are expensive. The human brain accounts for just 2% of body mass but 20% of our caloric intake. That's a huge energy requirement that has to be justified. Evolution as a designer does one thing and one thing only. It selects for traits that allow an organism to stay alive long enough to reproduce. It doesn't care about getting the best solution, only one that's good enough to compete in the current landscape. Evolution will tolerate any hack as long as it meets that one goal. As an example, I want to take a minute to talk about how we see the world around us. The human eye has two different kinds of photoreceptors. There are about 120 million rod cells in each eye. These play little or no role in color vision and they're mostly used for nighttime and peripheral vision. There are also about 6 or 7 million cone cells in each eye and these give us color vision but they require a lot more light to work. And the vast majority of cone cells are packed together in a tight little cluster near the center of the retina. This area is what we use to focus on individual details and it's smaller than you might think. It's only 15 degrees wide. As a result, our vision is extremely directional. We have a very small area of high detail and high color and the rest of our field of vision is more or less monochrome. So when we look at this, our eyes see something like this. In order to turn the image on the left into the image on the right, our brains are doing a lot of work that we're mostly unaware of. We compensate for having such highly directional vision by moving our eyes around a lot. Our brains combine the details from these individual points of interest to construct a persistent mental model of whatever we're looking at. These fast point-to-point movements are called saccades and they're actually the fastest movements that the human body can make. The shorter saccades that you might make when you're reading last for 20 to 40 milliseconds, longer ones that travel through a wider arc might take 200 milliseconds or about a fifth of a second. What I find so fascinating about this is that we don't perceive saccades. During a saccade, the eye is still sending data to the brain, but what it's sending is a smeary blur, so the brain just edits that part out. This process is called saccadic masking. You can see this effect for yourself. Next time you're in front of a mirror, lean in close and look back and forth from the reflection of one eye to the other. You won't see your eyes move. As far as we can tell, our gaze just jumps instantaneously from one reference point to the next. And here's where I have to wait for a moment while everybody stops doing this. When I was preparing for this talk, I found it an absolutely wonderful sense in the Wikipedia entry on saccades. I said, due to saccadic masking, the eye-brain system not only hides the eye movements from the individual, but also hides the evidence that anything has been hidden. Hides the evidence that anything has been hidden. Our brains lie to us. And they lie to us about having lied to us. And this happens to you multiple times a second, every waking hour, every day of your life. Of course, there's a reason for this. Imagine if every time you shifted your gaze around, you got distracted by all the pretty colors. You'd be eaten by lions. But in selecting for this design, evolution made a trade-off. The trade-off is that we are effectively blind every time we move our eyes around, sometimes for up to a fifth of a second. I wanted to talk about this, partly because it's a really fun subject, but also to show that just one of the ways that our brains are doing a massive amount of work to process information from our environment and present us with an abstraction. And as programmers, if we know anything about abstractions, it's that they're hard to get right, which leads me to an interesting question. Does it make sense to use any of the techniques that I talked about in part one to try to corral different parts of our brains into doing our work for us if we don't know what kinds of shortcuts they're going to take? According to the Oxford English Dictionary, the word bias seems to have entered the English language around the 1520s. It was used as a technical term in the game of lawn bowling, and it referred to a ball that was constructed in such a way that it would roll in a curved path instead of in a straight line. And since then, it's picked up a few additional meanings, but they all have that same basic connotation of something that's skewed or off a little bit. Cognitive bias is a term for systematic errors in thinking. These are patterns of thought that diverge in measurable and predictable ways from what the answers that pure rationality might give are. When you have some free time, I suggest that you go have a look at the Wikipedia page called List of Cognitive Biases. There are over 150 of them, and they're a fascinating reading. And this list of cognitive biases has a lot in common with the list of code smells that I showed earlier. A lot of these names are very literal, but there are a few that stand out like cursive knowledge or the Google effect and I kid you not the Ikea effect. But the parallel goes deeper than that. This list gives names to patterns of dysfunction, and once you have a name for a thing, it's a lot easier to recognize it and figure out what to do about it. I do want to call your attention to one particular item on this list. It's called the bias blind spot. This is the tendency to see oneself as less biased than other people, or to be able to identify more cognitive biases in others than in oneself. Sound like anybody you know? Just let that sink in for a minute. Seriously, though. In our field, we like to think of ourselves as more rational than the average person and just isn't true. Yes, as programmers, we have a valuable marketable skill that depends on our ability to reason mathematically, but we do ourselves and others a disservice if we allow ourselves to believe that being good at programming means anything other than we're good at programming, because as humans, we are all biased. It's built into us from our DNA, and pretending that we aren't biased only allows our biases to run free. I don't have a lot of general advice for how to look for bias, but I think an obvious and necessary first step is just to ask the question, how is this biased? Beyond that, I suggest that you learn about as many specific cognitive biases as you can so that your brain can do what it does, which is to look for patterns and make associations and classify things. I think everybody should understand their own biases because only by knowing how you're biased can you then decide how to correct for that bias and the decisions that you make. If you're not checking your work for bias, you can look right past a great solution and you'll never know what was there. So for part three of my talk, I have an example of a solution that is simple, elegant, just about the last thing I ever would have thought of. For the benefit of those of you who have yet to find your first gray hair, Pac-Man was a video game released in 1980 that let people maneuver around a maze eating dots while trying to avoid four ghosts. Playing games is fun, but we're programmers. We want to know how things work, so let's talk about programming Pac-Man. For the purposes of this discussion, we'll focus on just three things, the Pac-Man, the ghosts, and the maze. The Pac-Man is controlled by the player, so that code is basically just responding to hardware events, boring. The maze is there, so that the player has some chance at avoiding the ghosts. But the ghost AI, that's what's going to make the game interesting enough that people keep dropping quarters into a slot. And by the way, video games used to cost a quarter. That was your rage. So to keep things simple, we'll start with one ghost. How do we program its movement? We could choose a random direction and move that way until we hit a wall and then choose another random direction. This is very easy to implement, but not much of a challenge for the player. So we could compute the distance to the Pac-Man in X and Y and pick a direction that makes one of those smaller. But then the ghost is going to get stuck in corners or behind walls because it won't go around to catch the Pac-Man. And again, it's going to be too easy for the player. So how about instead of minimizing linear distance, we focus on topological distance? We can compute all possible paths through the maze, pick the shortest one that gets us to the Pac-Man and then step down it. And when we get to the next place, we'll do it all again. This works fine for one ghost. But if all four ghosts use this algorithm, then they're going to wind up chasing after the player in a tight little bunch instead of fanning out. Okay, so each ghost computes all possible paths of Pac-Man and rejects any path that goes through another ghost. That shouldn't be too hard, right? I don't have a statistically valid sample, but my guess is that when asked to design an AI for the ghosts, most programmers would go through a thought process more or less like what I just walked through. So how is this solution biased? I don't have a name, a good name for how this is biased. So the best way I have to communicate this idea is to walk you through a very different solution. In 2006, I attended UPSLA, this is a conference put on by the ACM, as a student volunteer. And I happened to sit in on a presentation by Alexander Repenning of the University of Colorado. And in his presentation, he walked through the Pac-Man problem more or less the way I just did, and then he presented this idea. What you do is you give the Pac-Man a smell, and then you model the diffusion of that smell throughout the environment. In the real world, smells travel through the air. We certainly don't need to model each individual air molecule. What we can do instead is just divide the environment up into reasonably sized logical chunks and we model those. Coincidentally, we already do have an object that does exactly that for us. It's the tiles of the maze itself. We're not really doing anything else, so we can borrow those as a convenient container for this computation. We program the game as follows. We say that the Pac-Man gives whatever floor tile it's standing on a Pac-Man smell value, say a thousand, the number doesn't really matter. And that tile then passes a smaller value off to each of its neighbors, and they pass a smaller value off to each of their neighbors and so on. Iterate this a few times when you get a diffusion contour that we can visualize as a hill with its peak centered on the Pac-Man. It's a little hard to see here, but the Pac-Man is at the bottom of that big yellow bar on the left. So we've got the Pac-Man. We've got the floor tiles. But in order to make an maze, we also have to have some walls. What we do is we give the walls a Pac-Man smell value of zero. That chops the hill up a bit. And now all our ghost has to do is climb the hill. We program the first ghost to sample each of the floor tiles next to it, pick the one with the biggest number, go that way. It barely seems worthy of being called an AI, does it? But check this out. When we add more ghosts to the maze, we only have to make one change to get them to cooperate. And interestingly, we don't change the ghost's movement behaviors at all. Instead, we have the ghosts tell the floor tile that they're, I guess, floating above that its Pac-Man smell value is zero. This changes the shape of that diffusion contour. Instead of a smooth hill that always slips down away from the Pac-Man, there are now cliffs where the hill drops immediately to zero. In effect, we turn the ghosts into movable walls so that when one ghost cuts off another one, the second one will automatically choose a different route. This lets the ghosts cooperate without needing to be aware of each other. Now, halfway through this conference session that I was sitting in where I saw this, I was like, what just happened? At first, like my first level of surprise was just what an interesting approach. But then I got really completely stunned when I thought about how surprising that solution was. And I hope that looking at the second solution helps you understand the bias in the first solution. In his paper, Professor Repenning wrote, the challenge to find this solution is a psychological, not a technical one. Our first instinct, when we're presented with this problem, is to imagine ourselves as the ghost. This is the body-syntonic reasoning that's built into logo. And in this case, it's a trap because it leads us to solve the pursuit problem by making the pursuer smarter. Once we've started down that road, it's very unlikely that we're going to consider a radically different approach even or perhaps especially if it's a very much simpler one. In other words, body-syntonicity biases us towards modeling objects in the foreground rather than objects in the background. Oops, sorry. Does this mean that you shouldn't use body-syntonic reasoning? Of course not. It's a tool. It's right for some jobs. It's not right for others. I want to take a look at one more technique from part one. What's the bias in, please, Mr. Gear, what is your ratio? Aside from the gendered language, which is trivially easy to address. This technique is explicitly designed to give you an opportunity to discover new objects in your model. But it only works after you've given at least one of those objects a name. Names have gravity. Metaphors can be tar pits. It's very likely that the new objects that you discover are going to be fairly closely related to the ones that you already have. Another way to help see this is to think about how many steps it takes to get from please, Ms. Pac-Man, what is your current position in the maze, to please, Ms. Floor-Tile, how much do you smell like Pac-Man? For a lot of people, the answer to that question is probably infinity. It certainly was for me. My guess is that you don't come up with this technique unless you've already done some work modeling diffusion in another context, which incidentally is why I like to work on diverse teams. The more different backgrounds and perspectives we have access to, the more chances we have to find a novel application of some seemingly unrelated technique because somebody's worked with it before. It can be exhilarating and very empowering to find these techniques that let us take shortcuts in our work by leveraging these specialized structures in our brains. But those structures themselves take shortcuts. And if you're not careful, they can lead you down a primrose path. I want to go back to that quote that got me thinking about all of this in the first place about how we don't ever teach anybody how to do that or even that they should. Ultimately, I think we should use techniques like this despite the biases in them. I think we should share them. And I think to paraphrase Glenn, we should teach people that this is a thing that you can and should do. And I think that we should teach people that looking critically at the answers that these techniques give you is also a thing that you can and should do. We might not always be able to come up with a radically simpler or different approach, but the least we can do is give ourselves the opportunity to do so by asking how is this biased? I want to say thank you real quickly to everybody who helped me with this talk or the ideas in it. And also thank you to Living Social for paying for my trip and also for bringing these wonderful brains. So they're going to start tearing this stage down in a few minutes. Rather than take Q&A up here, I'm going to pack up all my stuff and then I'm going to migrate over there and you can come and bug me, pick up a brain, whatever. Thank you.