Breaking Down Problems: It’s hard when you’re learning to code

This week, I’ve had a bunch of students ask me for help. With at least four of them I’ve found myself going through an almost identical process: even though their problems were very different.

The conversation went something like this…

Student: So I’m trying to write this function that reverses every other word in a string. I’m totally stuck. 🤯

Me: Cool. So we’ve already been given the signature and we know the expected input/output. Let’s write an empty function based on what we know.

Student: 👩‍💻

Me: Awesome. We should probably write a test for this, but let’s leave that for now. What should we do next?

Student: I dunno 😕

Me: Okay, let’s break it down and write the steps in plain english, as comments inside the function.

Student: Err, wat?

Me: We’ve got this string called string and we only want to do stuff to every other word. Can we easily get at every second word right now?

Student: No. Oh. We need to break it down into words. Maybe an array?

Me: Cool. Write that down.

Student: 👩‍💻

Me: What next?

Student: We want to loop over all the words, right?

Me: Sounds sensible. And what should we do with each word in the loop?

Student: If the index is odd we should change it so it’s reversed. If the index is even, we should just ignore it. I’m not sure how to do that, though.

Me: Cool. I’m not sure how to do that either. For now, write down what you just said.

Student: 👩‍💻

Me: What next?

Student: (gaining confidence) Now we’ve reversed the right things, we just need to join all the words back together. But I don’t know how to do that either.

Me: That’s fine. Let’s write that down. Think about what the function should return.

Student: 👩‍💻

Me: Sweet. Now we have a plan. How can we do the first step?

Student: I’ve no idea, but I can google it, maybe?

Student: 👩‍💻

Me: Cool. Reckon you can work out the rest with some help from Google?

Student: Yeah. I’ll have a go.

Student, ten minutes later: 👩‍💻 How’s this?

Me: Brilliant. Maybe clean it up a bit and remove the comments?

Student: 👩‍💻

Student: Sweet. Thanks so much for for the help!

Me: If you read our conversation 👆 again you’ll see I didn’t really give you much help. Good job!


So What’s the lesson here then?

The fact that this happened four times in as many days (with a bunch of different problems) has sparked a few thoughts for me:

  • People new to coding often don’t know where to start — even if they’ve been given a starting point (in this case a method signature and expected I/O). This can lead to panic.
  • When they stop panicking and get “out of the code”, it turns out they often do know where to start and what to do, though they might not know exactly how to do it in code. This is fine.
  • Googling small, well-defined general-case problems turns up much better results than googling bigger, more specific problems (eg. Reverse every other word in a string vs Split a string into words array). It’s very easy to spend time googling the former and getting lost in irrelevant stackoverflow threads.
  • I go through this process every time I write a function, though I mostly do it in my head these days.
  • I don’t encourage my students to step back from the code often enough. I think I do this more than a lot of teachers, but I still don’t do it enough.
  • Breaking big scary unknown problems into small manageable ones is a core skill for developers. And unlike syntax, it can’t be easily learned from google.

This last point should be obvious to anyone who’s been coding for a while. In our industry we talk a lot about breaking big things into smaller ones. We break epics into stories and stories into smaller ones. We model complex things on whiteboards, which inevitably leads us to break them into smaller things. We extract tiny things like Value Objects, and bigger things like microservices. We know that dissecting big complex things is the only way we can make comprehensible mental models of them. This is all obvious to most experienced developers I know.

Because of this, I’ve always tried to stress the whole “Take a step back and simplify” thing when teaching people to code.

In fact, teaching itself is pretty similar. Done well, it involves breaking complex ideas into tiny digestible things which can be tackled and internalised one at a time. Then progressively stitching them back together in the right way, until they’re understood holistically. This breaking down and re-stitching is the basis of progressive practice, and all ultimately of all progressive learning. (Aside: I’ve seen so many curriculums that do this badly, and it always makes me 😞)

Yup. I’m definitely rambling.

Any actionable advice then, Danny? 🤔

Yes. I’ll get to the point.

This need to break scary problems into smaller, less-scary ones isn’t exactly a surprise to me. What is surprising is the difficulty people have in applying this at a low level — modules, classes and functions.

So, here is my hastily concocted advice…

If you are learning to code…

  1. Don’t let a blank page freak you out. You’ve got this! 👊
  2. Start with the concrete stuff you know: What does the function need to take in and spit out? What methods does the class need to implement? What is the module supposed to do? Write empty boilerplate and worry about implementation later.
  3. Start with plain english. Break down the steps you think you need to take. Write them as comments, as though you were telling someone out-loud. Avoid descending into psuedocode —it’s probably too low-level.
  4. If you’re gonna ask a colleague for help, a plain-english plan describing what you intend to do is much easier to explain than actual code. And it’s easier to change, too.
  5. Iterate on your plain-english steps. If they still seem kinda big, take them one at a time and break them down further. Focus on what you are trying to do, not the syntax required to do it.
  6. When you’re happy with your plan, tackle each step one-at-a-time. Turn the english into code. Google is your friend.
  7. When you’re done: refactor. (And maybe write some tests, if you didn’t do that already.)
  8. Finally: Don’t feel bad about taking time to think, draw pictures and talk to other people. Working out your approach to a problem and what steps you need to take is 💯 the most challenging thing in programming (at least for me).

If you are teaching people who are learning to code…

  1. Run a session on the whole write steps in plain english thing. Do this early.
  2. Teaching problem-solving/modelling/flowcharts/psuedocode etc is great, but don’t neglect the transition from that to program code.
  3. If you live code anything non-trivial, start with plain-english comments. Ideally, elicit the “what do we need to do” from your students, then use your experience to help them with the how.
  4. Liberally refactor plain-english comments before turning it into code. This is a great way to teach more advanced design thinking in a context where your students feel comfortable.
  5. Endlessly remind that programing is hard because it requires us to solve ill-defined problems with unknown solutions. Our job is to invent the solutions. Coding is inherently creative; and like all creative pursuits, mastery can’t be attained simply by knowing stuff. So feeling lost is okay.
  6. Consider teaching BDD/TDD early. (This isn’t really related to my point here because black-box BDD rarely tells you how to implement things. But it does provide a nice safety net, and forces you to clearly define the external interface to your thing from the start.)

If you’ve got any thoughts on this––especially if you’re learning to code or teaching people to code––hit me up on twitter. I’d love to hear from you.

Oh, and sign up to my mailing list below. 👇 No spam, I promise 🙂


Notes

The example I used was from this Kata on Codewars…

It’s not super readable, but here’s a one-liner to solve it:

str.split(' ').each_with_index.map{|w,i| i.odd? ? w.reverse : w }.join(' ')