 Hi everyone, my name's Tom. Thank you very much for choosing to watch this talk. I'm very grateful for your time and attention. This is gonna be about 40 minutes of your life that you'll never get back, so I'm gonna do my best to make it worthwhile. I'm here to talk to you about a particular problem that I see a lot. For most of the last decade, I've made a living as a consultant, helping people to make better software, and that's been working with lots of different companies, I employed lots of different developers, and this was by far the most common problem that I had to help people with. In almost every case, it was the root cause of a lot of secondary problems, and it usually ended up costing a lot of time and money and emotional stress. A year ago, I was fortunate enough to join an online learning company called FutureLearn as their CTO, which means I'm now responsible for a whole team of brilliant developers, and they're all fantastic at their jobs, but I still see them wrestle with this problem from time to time. And that's really because the problem affects everyone at all levels of experience. It certainly affects me whenever I sit down to write code, and it's not even a programmer-specific problem, but I'm talking to an audience of programmers right now, so I'm gonna discuss the problem from a programmer's perspective. I want to talk about it because, although it's a serious problem with serious consequences, it's one that you can actually fix, partly just by being aware of it, which is half the battle with any problem, but also by learning some tools and coping strategies that can make it much less likely to affect you. I'm gonna talk about some of those tools and strategies in a bit. Actually, here's the overall plan for what I'll be telling you. I'm gonna start by describing the problem and then tell you about some of its symptoms and causes. I'll suggest a few example remedies to the problem based on my own experiences, and then I'll wrap up by explaining why I think this is an important thing to talk about in the first place. So first, here's the actual problem. Trying to do a big thing all at once, all in one go. And that might not sound like a big deal, but as I said, it's a surprisingly destructive tendency that leads to all sorts of other problems. I'm sure you recognize the situation. You have a large task to do, like adding a feature to some software or investigating a difficult bug or doing a major upgrade or making a big change from one library or framework or design pattern to another one. To make progress on it, you need to think about all the large and small details, all the moving parts, all of the interdependent problems and all of the steps you're gonna have to take to get it done. And you need to keep all those things in your head so that you can think about all of them at all levels of detail while you do the actual work. Now doing work on this big monolithic task can feel like a long and precarious walk across a tightrope. You start out standing on safe ground before you begin, but once you step out and begin the work, you won't be safe again until you complete it and reach the other end, which could be way off in the distance. And every step you take has got increasingly high stakes. If you fall off, you'll have to tear everything up and start again. You'll lose your context, your flow will be ruined, you'll forget what you were doing, you'll have to go all the way back to safety and give it another try from the beginning. So here are some symptoms of this problem. When you're experiencing this problem, the big thing that you're doing feels constantly stressful. It feels difficult to get things right because so much is resting on it. You're constantly aware of the risk of falling off and having to start all over again. Because you're expecting the problem to be kind of large and messy, it can be hard to see where the edges of the problem are. And that makes it very easy to accidentally get stuck investigating some buggy third-party library or unpicking some questionable design decisions from three years ago. And before you know it, you've spent days down a rabbit hole chasing some dead-end issue that wasn't even part of the job that you were originally trying to do. And once you get past the halfway point, your energy kind of starts to wane and you just kind of want the whole thing to be over with. And that makes you less and less likely to be willing to revisit your original assumptions or question your earlier decisions, like when new information comes to light. It's almost certain that you're gonna discover more information as you do the work. That information is very valuable and it might make you realize that some of your earlier decisions were wrong. But if you're desperate to just get this big project over with, you're less likely to want to go back and revisit those decisions and then those mistakes get baked in forever. Because of the stress and the sensation of your brain being full of connections and priorities and things to remember, your hate being interrupted or distracted because it blows that meticulously constructed mental context that you've built up. And as an aside, there's a particular strain of tech industry culture that reinforces that view by saying that programmers shouldn't be interrupted because of how complicated and difficult and intellectual our work is. Here's a popular comic about what happens when a programmer gets interrupted by some kind of tie-wearing coffee drinker and all of their hard mental work just sort of disappears into a black hole. Now, I'm a programmer, but I'm also a manager at the moment and I do like drinking coffee, so maybe it's me who's the problem in this situation and you need to take everything I'm saying here with a giant grain of salt. You might have seen this image doing the rounds on Twitter. The accompanying caption to this was anyone who ever schedules meetings with developers, please burn this image into your brain. So you need 45 minutes of downtime to kind of psychologically prepare yourself for a 30-minute meeting and then you need another 45 minutes to ramp up again afterwards. And similarly, you might have seen this graph of how so-called geek productivity works. If you're interrupted for five minutes, then a non-geek might think that your productivity recovers immediately, but in practice, it might actually take an hour or more. And so over the course of the day, these sort of constant small interruptions might mean that you're hardly ever actually being productive. Images like this one reinforce our cultural belief that interruptions and distractions are kind of objectively the enemy of productive and useful work. Another symptom is that it takes a long time to pick up your thread again when you get back to work. If you're always in the middle of something massive, then even if nobody interrupts you, it'll still take you ages to pick up your thread again, for example, the next day or after lunch or when you come back to work after the weekend. So if when you get to work in the morning or get back from lunch, it takes you a really long time to ramp up and understand what you were working on, then you might be suffering from this problem. Here are a few other symptoms that I'm not gonna talk about in any detail, but you might feel irritable about questions and meetings. You might be worrying that you'll forget what to do next. You might find yourself typing git status and seeing that you've modified 20 files and you can't quite remember what it was that you were trying to do. Or you might have a big long branch with tons of commits from late at night saying like whip and fix this and I changed my mind and I need to redo this later. So those are some of the symptoms of this problem I'm talking about. But why does this problem happen? I think one of the reasons why people get into this situation is just that they're eager to make progress. They've got some big task in front of them and they just wanna charge right into it, get the work done so that they have the kind of psychological reward of being finished. And that comes from a good place. It's not a bad thing for someone to want, but ultimately it might cause this problem to happen even though the intentions are good. Another way to get into this situation is to be unsure how big a job is gonna be. When you first start working on something, you might not realize how large the task is, in which case it's quite easy to accidentally end up in this situation where suddenly you've taken on way more complexity and detail than you originally intended to. And that's happened because you didn't have a good sense of the size of the problem up front. A related cause of this problem is that even if you do know how big the job is gonna be, you might be unsure how far through it you are when you're working on it. So even if you thought at the start that this would be about a day or about a week's worth of work, then unless you have some kind of map of the territory, then you might end up working on it without having any real sense of how close you are to being finished. And that kind of lack of visibility tends to feed that anxiety and worry and fear of having to put your work down and pick it up again later. And as I mentioned before, there's this idea that's quite prevalent in tech culture that programmers are somehow special among knowledge workers in the kind of work that we do. Now that idea is very flattering to programmers. In fact, I think it's successful because it's flattering because it reassures us that we're special. Our work is kind of intricate and difficult so it requires special attention and focus and the people around us need to understand that and make space for us to do that kind of complicated intellectual work. And they have to understand that our needs are different and accept that they can't expect us to drop whatever we're doing just because they have a question or want to have a conversation with us. But that's misguided for a couple of reasons. Most significantly, none of this is specific to programmers or like geeks or whatever. All knowledge workers need time to concentrate on the job that they're doing. All humans dislike being interrupted when they're right in the middle of something. Most rational people, myself included, wish that they could go to fewer meetings. So we probably shouldn't allow ourselves to be sort of seduced too much by this idea that programmers are operating on a kind of higher mental plane and therefore should expect special treatment from the rest of the world. The other reason that idea is misguided is that interruptions and distractions do have an upside. They can be opportunities for empathy and collaboration. Now, I'm not arguing in favor of them. Nobody likes being interrupted or distracted and interruptions and distractions can present a serious obstacle to people with a learning disability or anyone else who isn't neurotypical. So we should still try to reduce them as much as possible, but the reality of the work we do is that interruptions and distractions are extremely difficult to avoid entirely and you'll miss out on useful information if you don't find ways to accept them and work around them. In other words, if someone wants to talk to you, it might be helpful to talk to them. If literally nobody ever interrupted or distracted you, you could end up completely isolated from other people's questions and priorities and perspectives and feelings and that might help you concentrate better today, but it probably won't help you be a good programmer in the long run. People who are beginners at programming tend to view the main work of programming as kind of typing out the solution because that's the most obvious thing they find difficult initially. But to become more effective, you have to widen your skills to include understanding and caring about what other people are thinking and what their needs are. So now that I've explained the problem, I'd like to tell you about some remedies for it. Now, like spoilers, I don't have a magic solution that will make the whole problem go away altogether, but over many years of working with great developers, I have picked up a lot of strategies for coping with it. And so these are a few examples of things that I've seen work for other people and I hope that if I share them with you, you might find one or more of them helpful too or you might be able to think of some of your own. Now, each of these examples could be an entire talk in its own right, so I hope you'll forgive me for just kind of quickly advertising the ideas rather than properly explaining them in any detail. The first remedy to this problem is planning ahead. It's only possible for you to do small things. You know, you can write a method, you can write a test, you can fix a bug, you can create a commit. And if you want all those small things to add up to a big thing, you need to have some kind of plan about how that's gonna happen. Now, you don't necessarily need to do all the small things immediately one after another, you just need to know how they fit into the plan so that you can work through them steadily over time and gradually make overall progress towards your goal. Story mapping's one good way to put together a high level plan of how lots of small things are gonna add up to make a big thing. And story mapping sounds a bit like a thing, a consultant would try to sell you, but it's really just a simple game that you can play with post-it notes. It was invented by a guy called Jeff Patton about 10 years ago. So let me show you an example quickly of how story mapping works. Let's imagine you're building an e-commerce, you know, shopping website and you wanna map out a particular story which is a customer buys a product. And you start by getting a group of people together and asking everyone to write out individual small tasks that might happen over the course of that story, one task per post-it, as many as you can think of. And a task is just someone doing something. It doesn't matter who's doing it, it might be the customer or the software or the company or whoever. So you might write tasks like view product page, add product to basket, view basket page, enter payment details, enter shipping details, confirm order, ship product, cancel order. And at this point you're just trying to get all of the ideas out of your heads and written down. So you keep going, you think of other stuff, remove product from basket, update old payment details, request refunds, save product for later, update product quantity in basket, browse related products, search all products, add product to wish list. So you get the idea, anything you can think of that someone might conceivably want to do at some point in this process, you get it out of your head and onto a post-it. And once you have a load of tasks written down like this, you will try to stick them on the wall, arranged sort of roughly chronologically. And tasks that happen around the same time can stack up vertically. And where these tasks kind of naturally form groups, you can label the groups and we usually call them activities, so an activity might be finding a product, deciding whether to buy it, actually buying it, being shipped the product or whatever. And once you've done that, you should be able to tell the overall story by reading through the tasks from left to right. So you should be able to say, you know, a customer searches all products and then they view one of them and then they add the product to their basket and then they enter their payment details and so on. And one advantage of mapping out a story like this is it gives you a visualization of where the kind of complicated task heavy activities are. You can see at a glance that there are more tasks that can happen at certain times. And another advantage is that putting your brain into story telling mode helps you to spot holes in your story. If one task doesn't follow naturally from another or if the story is missing obvious important details, you can go back and add more tasks to fill in the blanks. So you might have forgotten about actually charging and refunding the credit card or sending confirmation emails or sorting and filtering search results or vouchers and offers and so on. So you can go back to your story map and fill in the blanks with the other things you've thought of until you feel confident that you've got the complete set of tasks that you could ever build to satisfy this particular story. Once you've filled in those blanks, you can pick a minimal set of those tasks to form the first version of the thing that you're gonna try to build. So you might pick, for example, view product page, add product to basket, enter payment details and ship product as the first really basic set of tasks that you're gonna try to build. This is called slicing the story map. It gives you the minimum set of tasks that lets you build something that makes coherent sense just to get yourself started. So you go off and build some software that does just those few things. And then once that's done, you can come back to your story map and slice off another internally consistent set of tasks that makes sense to add in a kind of second iteration. Now this is useful because slicing the story map in this way gives you a way of iterating your way to the complete thing via a series of stable intermediate points. By having this big problem broken down into small achievable sub-problems, it gives you a much better sense of how large the job is and also a much better sense of how much progress you're making towards completing it. Or if your priorities change, you can stop at any point and live with the slices you've built so far and move on to building something different. So that's enough about story mapping. Another remedy I want to suggest is learning to use Git to maintain a clean and clear and coherent history of your work. As programmers, we're lucky to have access to tools like Git that other people in other professions might never feel comfortable working with. Git gives us a lot of freedom to revise and control the history of our work and that can really help to avoid a task becoming overwhelmingly complicated. Here's one simple thing you can do to get a better history, make small focused commits. That makes it way easier to understand what you've done so far and why you did it. So rather than having several independent changes all kind of smushed together into a single diff, if you commit the smallest thing you can, the smallest self-contained change, it makes it a lot easier to understand rather than trying to understand 10 different changes and understand why those changes have to go together into a single commit. Small commits also make it easier to see the causal relationship between changes. If you need to implement A so that you can implement B so that you can implement C, you can do that in three separate commits and then it's obvious from the order of them which things depend on what. Again, if they're all smushed together into one it's not obvious just by looking at that change what the relationship is between those different parts. It's also very helpful to write commit messages that explain your thinking. At the time when you make a change you're very likely to have the best possible information about why you're making that change. It might be because you're fixing a bug that a customer complained about or it might be because you overheard someone else saying that it was bad to do things in a particular way or maybe you had a meeting where someone told you that you have to upgrade this dependency because in a month we're gonna need a new feature for something. If you can put that information into the commit message it makes it much more likely that when you pick this work up again you're gonna remember what you were thinking. You might be picking it up in an hour after your lunch break or in two days after the weekend. So anything that you can get out of your head about why you are making this change and write it down in the commit message is gonna be beneficial to you when you come to pick it up again later. The diff inside the commit already explains like what change you made but it doesn't tell you what you were thinking when you did it. Your history will be much more useful if you invest some time to keep your branch in good shape. While you're working on something a branch might live for hours or days or even weeks if you're working on something really big. You should always set aside time to make sure that that branch is healthy and in good shape and as close to being ready as it's possible for it to be at that point in time. Rather than treating your branch as this kind of big messy scratch space and saving up one huge piece of work at the end to make it shippable or mergeable or whatever that means for the work that you do. And there are a few different ways of keeping your branch healthy and exactly what this means for you depends a lot on your workflow and how you like to work with Git. So for example, it makes sense to try to not diverge too much from the master branch or whatever you call your mainline development branch. When I'm writing code I like to avoid diverging from master by constantly rebasing on top of it. So if I'm working with other people every hour or two, I'll make sure I fetch the upstream master and take a minute to rebase my work on top of it. Now, people will want to argue about whether rebasing is better than merging. They might prefer to regularly merge master back into their branch, for example. But, you know, bad luck. I'm the one with the microphone and I'm going to seize this opportunity to promote my opinion that rebasing is a much better way of keeping your branch small and easy to understand. And I think that's more important than other considerations. Sort of constant rebasing does generate more work during the life of your branch because it spreads out the effort of understanding how to incorporate upstream changes into the changes that you want to make. But that's exactly what keeps the risk low and keeps your branch healthy and straightforward at all times. Anyway, this sort of rebasing or merging doesn't really matter. Just do whatever works for you to try and avoid a situation where it's been hours or days or weeks since you last got information about what was happening on the branch that you're ultimately going to try and land your work on. It's also worth looking for opportunities to cherry-pick bits of your work back onto the master branch to reduce your branch's size and keep it completely focused on relevant changes. It's very common to do some, like, preparatory refactoring as part of the work you're trying to do. You know, make the change easy, then make the easy change, as Kent Beck put it. So you might decide to rename a class or tidy up some messy code before you try to change its behavior or just fix some white space that's been bugging you. And if you create a commit like that, one that improves the code base independently of the overall task you're doing, that's an ideal candidate for cherry-picking onto the master branch, getting it out there for other people to use and then rebasing your branch on top of it so that it's not part of your work in progress anymore. And if you're constantly doing this and maintaining a small as possible amount of work that you're holding back for merging in the future, then it's gonna make it much easier for you to keep your branch focused and coherent. It's gonna make it easier to land that work on master when you're done and it'll allow other people to enjoy the benefits of your refactoring or cleaning up or renaming or whatever much sooner. You should get more comfortable with interactive rebasing and taking time to regularly have a look at the list of your commits and either reorder or split or combine them or rewrite the commit messages to keep the story of what you're doing as clear and linear and natural as possible. For example, if you change your mind about something halfway through your branch rather than just leaving it that way forever, you can use interactive rebasing to fix it. If you introduce a thing called foo and then later on rename it to bar, then use interactive rebase to reorder your commits to put those things together in time and then you can squash them together and remove all evidence of your indecision. And then whoever picks that work up, whether it's you the next day or someone else who's trying to work on it in the future can read a shorter and less complicated story about what you've changed without having to pay attention to this extra detail that's ultimately irrelevant. My final piece of get advice is to practice improving your get hygiene by regularly switching away from your branch and just doing something else for a bit. Rather than allowing yourself to only have one branch checked out for days at a time, maybe do a bit of work on it and then whenever it's convenient for you to pause, switch away from it and do something different. When you come back to it, you'll have a much better sense of whether the work you're doing there makes sense and whether you can sit down and read it in order and understand it without sweating blood. A little bit of time away can give you a much better sense of perspective on what you're doing. And when you switch back to it, pay attention to how easy or hard you find it to pick up the thread again and why that is. If you realize that the commit messages or documentation or tests are unclear, then fix that while you still remember and it'll be way easier for you to pick it up next time. Here's another programmer tool that we're fortunate to have access to, test-driven development. One way that you can lean on test-driven development to remedy this big problem that I'm talking about is to become comfortable with switching between the different mental modes of red-green refactor. I'm not gonna talk too much about that now, but the idea of test-driven development is that you're either in the red phase where you're thinking about what do I want the code to do and you write a failing test, try and express that, or you're in the green phase where you're thinking about how do I write the code to do that and then you actually write the implementation, or you're in the refactor phase where you're thinking about how do I make this code better? So having made your test pass, you go back and revisit the work you've done to try and make it more expressive or give it better names or remove unnecessary duplication or whatever. A lot of people forget to use this as a kind of mind hack to focus your attention on what you're trying to do right now. It's worth being aware of this and consciously thinking about what am I trying to do right now? I'm in the red phase, I'm trying to write a failing test and I'm not gonna allow myself to get sucked into doing something different until I'm done with that and I'm convinced that my test is testing the thing I want it to. And then when you get into the green phase, try to stay focused on what you need to do to make the test pass and not get distracted by kind of doing other things you haven't written a test for yet or getting too sucked into thinking of the perfect names for things. The whole point of the green phase is just to get the test to pass, you know what Sandy Metz calls kind of shameless green. And similarly, make sure you give yourself time to do that kind of refactoring phase where you're not worried about what problem you're solving and you're not worried about how you're going to solve it. You can just focus completely on how you're gonna do a better job of that. You know, now that I've got code that works, how can I get myself to a place where I've got good code that works? Another piece of test-driven development advice that's relevant here is to try working outside in with acceptance tests and by acceptance tests I mean what people might call end-to-end tests or system tests or feature tests or even integration tests. And that's because outside in testing or acceptance test-driven development or whatever you wanna call it, always tells you what the next thing to do is. If you've got a convincing acceptance test that is trying to use your software from the outside, you know, I'm gonna put a product in my basket and then I'm gonna enter my credit card details and then I'm gonna place my order or whatever, then that gives you a top-level plan for what work you're gonna have to do to deliver that feature. And you can always run that acceptance test and you always know how far you are towards your final goal because of how far that test gets before it fails. And if it fails immediately because there's, you know, no user interface for viewing a product, then that tells you that you need to be working on that now and you can go and work on it and put unit tests around it and get that bit working. And then if you can't remember what you were supposed to be doing next, you can take a step back, run the acceptance test again, see the first part of it pass and then there'll be a new failure that's telling you what to work on next. And you always know what the next big piece of work is and when you're doing that piece of work, you should always know what you're currently working on because you have a failing unit test as well. So if you work in this style where you have one big end-to-end or acceptance test and you run individual unit tests as you go, then whenever you're interrupted or you step away from your computer, when you get back to it, you should always either have a failing unit test, which means that you're trying to get that small piece working or all of your unit tests are passing and you've got a failure in your acceptance test, which means that now you have to write a new unit test to push that acceptance test one step closer to completely passing. It's fine if you've got no idea why I'm talking about here with this outside NTDD stuff, I'm gonna link to some proper resources in a minute. Incidentally, I was talking to my friend Murray about this and he said that he never walks away from his computer without a failing test. And that means when he sits down again, he can always get straight back into what he was doing before, which was making the test pass. I think that's good advice, so I'm gonna pretend that I thought of it. I'm gonna pretend that I thought of it. Thanks Murray, hope you're enjoying being in London where it's probably raining. Finally on TDD, write tests that really do check what you care about rather than paying lip service to like doing the tests, particularly after the implementation, just as a kind of box ticking chore that isn't adding any value. Tests should help to focus your attention on what aspects of your software's behavior you actually care about. They're a very important tool for clarifying your thinking and communicating it to other people. And in particular, remember that code that's hard to test will be hard to use and hard to change later. So if it's hard to make a clear test, then take the time to improve the design of your implementation now instead of saving up trouble for the future. The final remedy I'm gonna suggest is to use notes and conversations. And these things are super powerful, but they seem so obvious it's really easy to forget to lean on them. While you're working, you can practice taking notes and writing down things, so like questions and mysteries and tangential problems as you find them. Rather than letting them distract you from the primary goal that you're working towards, just get them out of your brain and put them on a bit of paper. You can always come back to them later once you've finished what you were supposed to be doing. This is one of the main things that can help you to avoid like tangents and rabbit holes. So for example, when you're meant to be focusing on the red phase of TDD, then you spot something that needs refactoring or an unrelated bug that needs fixing. If you feel confident that you've seen a problem out the corner of your eye, you've written it down on a bit of paper and you've promised yourself that when you finish this piece of work, you're gonna go back to your notes and work through all of those little edge cases and weird problems. It's much less likely that you're gonna get bogged down in them as you go. You should practice working with other people and explaining your train of thought rather than keeping it all kind of scrunched up inside your brain. Use conversations with other people to externalize your current to-do list, your current goal, your plan to make progress towards that goal, the things that you're worrying about right now and so on. Like pairing is one way of making sure that all of that stuff is getting regularly explained and verbalized. It's important to do that because the more you explain the contents of your brain to other people, the more chance there is that you're gonna notice that they don't make sense or they're too ambitious or too risky or you're trying to take on too much at once or you're getting too caught up in the wrong aspect of the problem somehow. However you choose to do it, you should step away from your work regularly to talk to other people about what it is that you're doing and why you're doing it. And pairing is one way to do that. Another way is to have some kind of code review process or use pull requests or whatever and another is just to chat to people by the coffee machine or on Slack about what you're doing at the moment. Different things work for different people and personality types and working preferences but whatever your preferences are you shouldn't forget about the value of just talking to people and rehearsing your own understanding of what it is that you're doing. So to recap, those are a few techniques that you can use to avoid that kind of dangerous typewriter walking feeling. You can make plans so you always know where you are and can easily pick up the thread again. You can use gets more advanced features like interactive rebasing to keep your history straightforward and obvious and free from incidental complexity. You can use test-driven development to focus your attention and you can get ideas out of your head by writing notes and coming back to them later if you need to. You can clarify your ideas by having conversations, speaking them out loud, seeing how they feel when you have to concretely articulate them rather than just sort of think them in the abstract. Now these tools and strategies that I've mentioned today are just the examples that I could remember off the top of my head from my own experiences working with other people. I'm not an expert in you. I don't know anything about your job or your work style or your psychological and physiological needs. So I'm sure you'll have other different, better strategies than the ones I've mentioned here. But more important than any of my specific suggestions is the overall technique, the meta-level way of approaching the way that you work on big things. And the meta-level strategy is to notice the risk and break it down. To remember to spot the problem of taking on too much at once. When you're working on something, pay attention to how you're feeling and notice when you start to put yourself into a risky situation where you feel like you're stepping out onto that long, unstable tightrope. You're keeping a lot in your head. There are lots of separate things that need to happen before you're safe again. You're getting nervous and stressed and praying that nobody distracts you and brings it all crashing down before you reach the other end. And then once you notice that it's happening, get off the tightrope and figure out which of your skills to use to break down the problem and approach it as a series of small, safe stepping stones instead of one giant leap. So here are a few links to resources for the ideas I briefly mentioned. Jeff Patton's got a user story mapping page that links to a book that he wrote about it and blog posts and stuff like that. One of my colleagues at FutureLearn wrote a blog post about using your get history to tell stories, which is very useful. The growing object-oriented software guided by Testbook is all about this kind of outside-in TDD process, if you're interested in learning how to do that. And the new aspect book that just came out recently has got stuff in it about writing these kind of effective high-value tests. There've also been several good talks at RubyConf on these topics, or by coincidence, and you should watch them if you haven't already seen them. So yesterday, Ashley gave a great talk called Get Driven Refactoring, where she explained a lot better than I have in a lot more detail how Git can help you to spot problems in your code and document your work as part of your commit history. And on testing, earlier this afternoon, Valerie gave a talk that's a useful introduction to unit testing if you haven't done it before and literally right before this talk, Noel gave a talk about sort of high-value tests which goes into more detail on some of the points I mentioned about TDD. Now, just to wrap up, I've just spent over half an hour talking about this tightrope walking problem. Why did I choose to come all the way here from beautiful rainy London to tell you about it? Like, why is getting off the tightrope important? Well, I wanted to talk about this because based on what I've seen so far in my career, I believe it's what makes great developers great. When you first begin as a developer, you need to learn how to write code, but at some point, maybe years later, you start getting diminishing returns on that skill. You can learn the syntax and behavior and standard library of your favorite programming language and framework, but then how do you get better once you've done that? And I think that skills and tools like the ones I've told you about today are what makes the difference between someone who's good at writing code and someone who's great at being a developer. As you get more experienced as a developer, you learn these strategies for coping with the complexities of the problems you face and the shortcomings of the human brain by being determined and bloody-minded about applying those strategies. You can make progress on problems that other people find too intimidating to work on. Other people will come to you with questions because they think you already know the answers when actually you're just more persistent at breaking an impossible question down into smaller, more answerable questions and working patiently and methodically towards their solutions. Now, this might sound blindingly obvious to you because you're probably smarter than I am, but it came as a real surprise to me when I realized it. And I still have to keep reminding people to stop stressing themselves out by trying to do too much at once. So unfortunately, it's not yet obvious enough for me to shut up about it. This is one of the main differentiators of experienced developers, their ability to cope with large problems by using lots of different strategies and tools to break them down into manageable pieces. These strategies and tools are learnable and they become second nature if you practice them as if you were learning to ride a bike or play the piano. And I'm here to tell you that I believe that's worth doing. Like, don't wait to get better at this by accident. When you go back to work after this talk, think consciously about how to cultivate this skill and make time to develop your own strategies and allow them to become second nature. If you can learn some of these strategies, learn to spot when you feel yourself walking out onto that dangerous tightrope and practice stepping back to a place of calm and safety and methodical progress, you'll create better software and be less stressed and frustrated while you're doing it. Thanks very much.