We’ve been helping J- with her culminating project in Grade 11 programming class, a text-based blackjack game. She was getting stuck because she wasn’t comfortable enough with Java or programming. She didn’t know where to start or what to do. I didn’t write the program for her (and that was never on the table, anyway), but I offered to guide her through the process. More experienced learners can do that kind of planning on their own, but when you’re new to a subject (and especially if you’re under time pressure), it helps to have that kind of scaffolding.
The first thing I did was to properly set up Eclipse on her computer. She had already tried setting it up, but it kept quitting with a cryptic error message. I realized that she didn’t have the Java software development kit installed. Once we added that, Eclipse started working.
Then I set up a sequence of tiny, tiny steps that she could implement with a little guidance. This was not the same sequence of events that would be in the final game: betting, shuffling, dealing, scoring, and so on. Instead, I focused on the steps she could build on bit by bit. It went something like this:
- Display a random number.
- Initialize the deck array based on the face array and suit array J- had already set up. This would contain strings like “ace of hearts”.
- Print the deck array.
- Set up a parallel array of card values, and print that as well. This would contain integers such as 1 for ace.
- Shuffle the deck by swapping each card with a random card, swapping the same card’s value as well.
- Write a function that takes an array of card values and returns the value of the hand.
- Modify the function to take aces into account, since aces could be either 1 or 11.
- Handle the initial dealing of two cards each by keeping track of the top card and updating a status array.
- Display the cards for a specified hand based on the status array.
- Update the hand value function to take the status array into account.
- Deal cards to the player as requested.
- Check if the player has lost.
- Follow the rules for dealing additional cards to the dealer.
- Check if the dealer has lost.
- Figure out who won that round.
- Read the bet.
- Update the bet after the player has won or lost the round.
- Check if the player has doubled their money or lost all their money.
- Add more error-checking.
- Add more flexibility.
This sequence meant that she could write and test the less-interactive parts first (preparing the deck, shuffling the cards, calculating the score) before slowing down her compile-run-test cycle with input. It also let her work on the simplest parts first without writing a lot of redundant code and with just a little prompting from me.
Instead of this zigzag path, we could have followed the chronological flow of the program, especially if I introduced her to the practice of stubbing functions until you’re ready to work on them. This shuffled order felt a bit better in terms of demonstrable progress, and she seems to have been able to follow along with the construction process. In retrospect, the chronological flow might have been easier for her to learn and apply to other projects, though, since breaking down and shuffling the order of tasks is a skill that programming newbies probably need a while to develop.
Anyway, helping J- with her project got me thinking about how I work my way through programming challenges on my personal projects and in my consulting. I tend to try to figure things out by myself instead of asking mentors or the Internet. I also tend to write things in a bottom-up instead of top-down order: starting with small things I can write and test quickly, and then gradually building more elaborate processes around them.
I think of the process of breaking down tasks and organizing them into a useful order as “sequencing”, which is part of the general domain of problem-solving. There’s probably an official term for it, but until I find it, that’s the term makes sense to me. When I was teaching undergraduate computer science, I noticed that students often struggled with the following aspects:
- Imagining a good goal, if they were doing a self-directed project (not too big, not too small, etc.)
- Fleshing out their goal into specifications
- Identifying possible chunks along the path
- Breaking those chunks down into smaller chunks as needed
- Figuring out how to bridge those chunks together
- Prioritizing chunks
- Re-evaluating paths, progress, and goals as they learned more
- Managing motivation
- Finding resources
- Translating or adapting those resources to what they needed to do
- Figuring out what they could start with (what they already knew, or that first hand-hold on a chunk)
I sometimes have a hard time with these aspects too, especially when I’m learning a new toolkit or language. I think I’m getting better at picking ridiculously tiny steps and celebrating that progress instead of getting frustrated by blocks. When I can’t figure tiny steps out, I know that going through tutorials and reading other people’s code will help me build my vocabulary. That way, I can get better at finding resources and planning chunks. I have a better idea of what’s out there, what things are called, and maybe even what’s probably harder and what’s probably easier.
Programming gives me plenty of opportunities to develop my sequencing skills. By writing notes with embedded code snippets and TODOs, I can break large chunks down into smaller chunks that fit in my working memory. Sometimes I read programming documentation or source code without any particular project in mind, just collecting ideas and expanding my imagination. If I focus on writing tiny chunks that start off as “just good enough” rather than making them as elaborate as I can, that lets me move on to the rest of the program and get feedback faster. Saving snippets of unused or evolving code (either manually in my notes or automatically via a version contro system) lets me reuse them elsewhere.
I imagine that getting even better at sequencing might involve:
- Sharing intermediate or neighbouring products to get feedback faster and create more value
- Figuring out (and remembering!) sequences for getting into various areas such as Angular or D3
- Becoming fluent with many styles of sequencing, like working top-down instead of just bottom-up
- Building reliable automated tests along the way, even as my understanding of the project evolves
What about helping other people get better at sequencing?
- If I share a pre-defined sequence, that helps people with less experience follow a possibly more efficient path.
- If I customize the sequence for someone I’m helping, that’s even more useful.
- Talking about how we’re customizing the sequence exposes sequencing as a skill.
- Guiding someone through the breakdown of a small chunk (from a task to pseudocode, for example) can help them get the hang of turning things into specifics.
- Guiding someone through the breakdown of a larger chunk into smaller chunks helps them think of larger chunks as doable.
- Once someone has identified a few chunks, I can help with prioritizing them based on effort, relationship between chunks, etc.
- In preparation for independent learning, it’s good to practice the skill of figuring out those prioritization factors: small experiments, research, and so on.
- And at some point (woohoo!), I can help someone reflect on and tweak a plan they developed.
I’m not yet at the point of being able to do even step 1 well, but maybe someday (with lots of practice)!
Since this is a super-useful skill and not everyone’s into programming, it might be interesting to look around for non-programming situations that can help develop sequencing skills.
On the passive side, it’s interesting to learn about how things work or how they’re made. Better yet, you can actively practise sequencing with math problems, video games with quests… Writing is like this too, if you think of key points and use tools such as outlines or index cards. Making things involves imagining what you want and figuring out lots of small steps along the way. Life is filled with little opportunities for everyday problem-solving.
I’d love to learn more about this. Chunk decomposition? Problem-solving order? Problem decomposition? Step-wise refinement? I’m more comfortable with bottom-up problem-solving, but top-down solving has its merits (focus, for one), so maybe I can practice that too. Using both approaches can be helpful. (Ooh, there’s a Wikipedia article on top-down and bottom-up design…) Time to check out research into the psychology of problem-solving!