A Starting Problem Solving Toolkit

by Elliott Hauser

03 Nov 2022

This page is a starter kit for building your own personal collection of tools that really work for you. It's also a menu of things to try out throughout this course and beyond.

The 4 Rs

In Chapter 1, the textbook started you off with four things to try when working with code:

  • Reading. Examine your code, read it back to yourself, and check that it says what you meant to say. Note: Reading is a critical foundation for all problem solving skills. But make sure you don't get stuck just reading, and especially don't get stuck reading and writing a lot of new code without Running. See also Start Small below.
  • Running. Experiment by making changes and running different versions. Often if you display the right thing at the right place in the program, the problem becomes obvious, but sometimes you have to spend some time to build scaffolding. Note: if running is your go-to, and you're not as efficient as you'd like to be, try balancing it with Ruminating!
  • Ruminating. Take some time to think! What kind of error is it: syntax, runtime, semantic? What information can you get from the error messages, or from the output of the program? What kind of error could cause the problem you’re seeing? What did you change last, before the problem appeared? Note: If ruminating is your go-to, and you find you're not as efficient as you'd like to be, try balancing it with Running!
  • Retreat. At some point, the best thing to do is back off, undoing recent changes, until you get back to a program that works and that you understand. Then you can start rebuilding. Note: Retreating might also mean it's time to take a break! 

My Big Three

These are three strategies I've found helpful for students in my past teaching. I also use them myself.

  • Work smart (aka "Pace and Space"). Good coding cannot happen at the last minute or in marathon sessions. Learning how to pace yourself, by taking regular breaks, and space your work, by working across multiple days or sessions, is a huge benefit for every coder and student I've ever met. If there's a stronger way to recommend you try out this strategy and make it a part of how you approach this course and coding more broadly I don't know what it is. Pomodoro technique is a popular way of doing this, using a timer to take regular breaks. Pomodoro sessions are typically 25 minutes on, 5 minute break, or 50 minutes on, 10 minute break. After 3-5 sessions, take a longer break. If you need to go the distance doing any kind of intellectually demanding work, try Pomodoros.
  • Go in the Right Direction. I've been there: an hour or more into trying to accomplish something with my code I realize that even if I were able to accomplish it, it's not going to achieve my overall goal. Keeping a good record of what you're doing, and periodically asking yourself why you're doing it will help make sure your efforts will contribute to you solving your problem and/or achieving your programming goals. This might also involve questioning your assumptions or even using print to make sure the data you're working is really is what you think it is. If you use Pomodoros or any other form of Pace and Space technique, the beginning of a session is a great time to check in with yourself: What am I doing? Why am I doing it? How can I be sure this is what I should be doing?
  • Use Your Resources Well. You're building an expanding set of resources for learning, starting with the textbook, my lectures, and your notes. You'll find other resources as you go. Learn when to use each kind of resource. Once we review how to read the official Python documentation, think about when that's the right resource. Same deal with tutorials, youtube videos, and, yes, Google (which often leads to StackOverflow). In this class, your use of resources will inform how you design and populate your Personal Coding Manual, which will be a little like an uber-resource for you, containing all the things you find most useful and helpful and pointing you off to others as needed.

Avoiding Problems in the First Place

Avoiding problems created by bugs, or by your own coding process, is an excellent problem solving strategy! In Chapter 3, the text suggests three strategies for this:

  1. Understand the Problem You must have a firm grasp on what you are trying to accomplish but not necessarily how to do it. You do not need to understand the entire problem. But you must understand at least a portion of it and what the program should do in a specific circumstance – what output should be produced for some given input. This will allow you to test your progress. You can then identify if a solution is correct or whether there remains work to do or bugs to fix. This is probably the single biggest piece of advice for programmers at every level.

  2. Start Small It is tempting to sit down and crank out an entire program at once. But, when the program – inevitably – does not work, you have a myriad of options for things that might be wrong. Where to start? Where to look first? How to figure out what went wrong? I’ll get to that in the next section. So, start with something really small. Maybe just two lines and then make sure that runs. Hitting the run button is quick and easy. It gives you immediate feedback about whether what you have just done works or not. Another immediate benefit of having something small working is that you have something to turn in. Turning in a small, incomplete program, is almost always better than nothing.

  3. Keep Improving It Once you have a small part of your program working, the next step is to figure out something small to add to it – how can you move closer to a correct solution. As you add to your program, you gain greater insight into the underlying problem you are trying to solve.

    If you keep adding small pieces of the program one at a time, it is much easier to figure out what went wrong. (This of course means you must be able to recognize if there is an error. And that is done through testing.)

    As long as you always test each new bit of code, it is most likely that any error is in the new code you have just added. Less new code means its easier to figure out where the problem is.

They sum this up with the mantra "Get something working and keep improving it." Good advice, and something many programmers practice. To be effective at these strategies, you need to be good at starting small. What "small" looks like is very dependent upon the problem you're solving and the relevant skills you have. Luckily, you'll get lots of experience breaking things down in this class, so it's very likely you'll also get good at starting small.

Another sense of "small" to keep in mind here is the amount of code you write between running it to confirm it does what you think it does. This gets more and more difficult with complex programs, which is why Sketching is important.

Sketch Ideas and Questions in Code

Write small bits of code that isolate the thing you're trying to do or understand from as many other parts of a program is possible. If you do this, you will leave many very small, very useless pieces of code in your wake. That's great! Just like a great artist leaves many small, partial sketches in their wake when painting a masterpiece. 

If you do this when learning from the textbook, you'll be able to create your own examples to test and confirm your understanding of concepts the authors have presented.

If you do this when writing complex programs, you'll know how each piece works and will be able to incorporate them more effectively and quickly than if you only ever add new code to your ever-complexifying program.

Ask Python Questions, In Python Code

Above I said you could sketch ideas and questions in code. What's a question in code?

Well, if you forgot the syntax for something, you could open a new program and create a quick sketch with what you think the right syntax is. If it produces the result you're expecting, you've confirmed your understanding. If it doesn't, or it throws an error, try your next idea.

Yes, you could also look this up somewhere, but the more you ask your questions of Python in Python the faster you'll become fluent in the language.

Syntax is a simple one. What about the state of a variable in a loop? You could Read and Ruminate, but when you print that variable you're getting the answer, right from your program. 

Printing is great, but what about flow of control? If you want Python to stop and wait for you, a quick input() will pause the program until you press enter.

And so on. The wonderful thing about this strategy is that it also makes you better at asking for help from people and at using other resources. If you can state your question in code, and Python can't answer it (or you don't understand the answer), the person who helps you will be much better able to. Note: this is part of the reason that StackExchange and other Q&A sites require code examples alongside questions. It's also why bug reporting systems often require precise steps, including code, to reproduce a bug. It's also part of the principle behind writing software tests; tests are essentially a list of questions developers ask their programs, confirming the answers are as expected. You get the picture: this is an important skill that connects to a lot of important practices in programming.

Mental Self-Awareness 

Note: this section on mental self-awareness is intended to address common experiences that feel unpleasant but tractable. It is not a substitute for mental health care, and I encourage all students to utilize the resources listed in the syllabus if they know or suspect that their mental health is becoming an issue in class or is otherwise negatively impacting their experience. Mental health challenges are nothing to be ashamed of, and are nevertheless outside the scope of what I'm talking about here.

We do all our thinking and all our learning and all our problem solving with our minds. Knowing what state they're in, and how to help them be more effective, is critically helpful for problem solving. Here are techniques that work for me and that many students have found helpful:

  1. Check in with yourself. Notice how you are feeling. Over time, this will get easier but it's often quite hard when we're doing hard mental tasks. When we think hard a default is to push aside any mental states to try to think more clearly. This sometimes works in the short term, but over the long term can build up a lot of resistance, which makes learning unpleasant and encourages procrastination.
  2. Name your mental state. You don't have to use labels everyone else does, but I find them helpful. This is a step beyond noticing something like "I feel tense" into a specific named feeling: tension could come from anxious, scared, overwhelmed, or something else. With that name in hand, you have a little bit more specificity and are ready to try to address the feeling.
  3. Have a go-to plan for mental states that get in your way. This will be different for everyone. For me, when I'm anxious, physical activity helps. When I'm overwhelmed, taking a short break and then planning or otherwise getting an overview helps. If I'm scared (in the context of coding or work), usually just naming the specific fear I have will help me feel better, because I will then see I've blown it out of proportion. Even though each of these mental states can make me tense, I have a different  go-to plan for each. I tested these out over time, noticed what worked best, and now I've got a playbook for how to clear my mind not just for the short term, but sustainably.

If it sounds like overkill to you to talk about mental self-awareness as a problem solving technique, you might not be admitting to yourself when your mental state has gotten in your way in the past. The next time you have negative thoughts about yourself or others during intellectual work stop and see if there's a mental state that could be causing them. We all have times when we're less kind to ourselves or others than we could be. For me, upon reflection, there's been a mental state getting in the way of me acting the way I want to towards myself or others nearly every time. Mental Self-Awareness is a problem solving skill that just might help you outside of class as well.

Physical Self-Care

Note: this section is on general physical self-care and wellness, and it not intended as a replacement for skilled medical care for specific conditions. Also, I want to acknowledge that students may have a range of physical abilities, conditions, and capacities. The overall point of this section is to call out how personal health impacts the cognitive functioning needed for effective problem solving. Healthcare or treatment for specific diseases or conditions may drastically alter individual capacities. The overall point is that, whatever your capacity or conditions, seeking optimal physical health for you, and removing any physical discomfort where possible, will benefit your learning.

If you buy that your mental states are important to your success in problem solving while coding, then you've got to accept that physical self care has an important place as well. Quite simply, your physical body is your mind (it's pretty hard to separate the nervous system from the rest of you). If you don't like that way of putting it, I can prove my point even if you'll only accept that your mind is inside your physical body. Your brain runs on energy, needs to reset itself through sleep, and has difficulty focusing if you're in discomfort. So, in that order:

  • Seek sustainable energy. Yes, there's always coffee or other stimulating drinks, but I'm talking here about nutrition. Make sure you're well fed when your brain needs to be at its best. If you're taking breaks as I suggest above, you'll be amazed at how having a snack during a break will improve your cognitive abilities if you've been so focused you didn't notice you were hungry. Hydration is important as well and has the convenient side effect of forcing you to take regular bathroom breaks. Yes, we're talking about the basics here, food and water, and yes they absolutely matter when you're trying to solve hard problems with code. This is different for everyone, but I find that junk food really gets in the way of my best thinking, while complex carbs and proteins enhance it. Notice the patterns for yourself and use them to give your brain what it needs to do its best for you. Finally, if you don't have exercise or regular physical activity in your life, adding it in will up your metabolism which mean your body will put more goodies for your brain into your blood stream.
  • Get regular rest. Everyone has different needs, rhythms, and demands on their time but getting around 8 hours of sleep a night is ideal for most people. When you sleep deeply and dream your brain gets to reset. Synapses get recharged and will fire faster. Without sufficient sleep your synapses will literally have a weaker electrical charge, be less likely to recall what you've learned, and slower to form new pathways. Sleep is a critical part of having a brain.
    Since sleep and physical activity sometimes compete for our time, I can report that, for me, 30-60m of exercises can replace and even exceed the benefits of sleeping in an equivalent amount of time. So, even if I'm up late for some reason, I still try to exercise rather than sleep in.
  • Treat pain and discomfort. Pain and discomfort are unavoidable sometimes, and they can really hurt our ability to focus. I've had back pain for years, and learned to work through it best I could. I've become so much more effective at intellectual tasks by getting treatment and regularly doing the exercise that minimizes this pain. If you have pain or discomfort from a health condition, see it as a potential barrier to your cognitive performance and do whatever you've found to be most effective in minimizing it.

 

Elliott Hauser is an Assistant Professor at the UT Austin iSchool. He's hacking education as one of the cofounders of Trinket.io. Find Elliott Hauser on Twitter, Github, and on the web.