Students Don’t Need Simple Examples
They need clear ones
In my post about coding for predictions, I wrote a sentence that was edited out of the final draft, but that’s played on repeat in my head ever since.
Students don’t need simple examples. They need clear ones.
I’m realizing that this catchy little antithesis is essentially my whole teaching philosophy rolled up into one line.
Pseudocontext
Before we get too much further, I need to introduce some vocabulary to you that I’ve come to rely on. I borrowed the word “pseudocontext” from master teacher and founder of Desmos, Dan Meyer, who in turn borrowed it from education researcher Jo Boaler.
You should absolutely go and read their more-thoughtfully crafted definitions of the word, but if you’re in a rush, I’ll share my favorite example.
Dan Meyer explains pseudocontext with the following word problem. It is from a section of the textbook called “real-world connections” but I’ll let you decide how “real-world” it really is:
In January of the year 2000, I was one more than eleven times as old as my son William. In January of 2009, I was seven more than three times as old as him. How old was my son in January of 2000?
I’ve compiled a non-comprehensive list of complaints I have for this real-world problem’s narrator:
- Why do we care how old your son was in January 2000?
- Why don’t you know how old your son was?
- Wouldn’t birth years be an easier way of computing ages at a given time?
- Who honestly keeps track of ages in terms of multiples of other ages, but doesn’t keep track of actual ages??
- As a math teacher, I know you want me to use this system of equations:
A = 1 + 11(S) and (A+9) = 7 + 3(S+9), but even knowing what you want me to do, I’m not going to do it, because your method is actually a lot harder than plugging in and guessing.
I could go on, but you get my drift.
From this example, we can derive a working definition of Pseudocontext that we can use to examine CS tasks.
- Pseudocontext: A learning task or situation where the question being asked is not the most natural and interesting question, and the tools available are not the most natural and useful tools.
So here’s the thesis of this article: Any time your code snippets for students use non-meaningful placeholders like “foo” or “bar”, you’ve created pseudocontext.
Real Context
Looking at the definition of pseudocontext, we can reverse engineer its antonym.
- Real Context: A learning task where the question being asked is the most natural and interesting question, and the tools available are the most natural tools.
You may notice that by this definition, real context doesn’t actually require using intricate technical best practices — it just requires thinking about whether or not the user is being asked to do something that they might, even without your direction, still choose to do out of curiosity.
So now that we’ve got our working definition in place, let’s examine some code snippets.
In theory, a code snippet is an example of the concept “in action,” and so a lot of learn-to-code guides seem to be written with the assumption that seeing any code snippet at all counts as real-world context. But if those code snippets include strings like "foo"
and "bar"
or variable names like my_str
or my_list
, then that’s a good sign that the code lacks any real context.
All of the following example code snippets are taken from well-respected online guides and resources intended for beginners. I’ve withheld the names of the specific sources and authors because this blog isn’t meant to roast them— indeed some of those guides are overall very useful. But I have some ideas for how to improve each example before using it with a class of students.
Example 1: Strings
If I ever write “foo” or “bar” in my code, I know I’ve messed up.
Here’s what I mean:
str1 = "foo"
str2 = "bar"str3 = str1 + str2
print(str3)
The structure of this example is actually really wonderful. You’re showing concatenation in action. But because we’ve stripped this code of all its context, there’s no reason a first-time learner would intuit what’s happening here.
Here’s the revision:
first_name = "Ada"
last_name = "Lovelace"full_name = first_name + last_name
print(full_name)
You’ve shown the exact same mechanical operation as before, only now you’re allowing your students to apply their intuition about the external world to their programming.
This isn’t making things easier — it’s making them clearer.
Example 2: Functions
If I find myself using the name my_function
I’ve definitely missed the mark.
Here’s an example from a really well-respected online Python guide:
def my_function():
print("Hello from a function")my_function()
This is a function in its most atomic form, and so in theory it makes sense as the starting point. But starting here means that a first time learner can’t figure out why this would ever be useful. From their perspective, we’ve just written three lines of code to print a string — something we could already do in a single line.
I’m not just being critical from my high horse; I made this exact mistake the first few times I taught functions. When I used say_hello()
as my introductory example, my beginners started to suspect that functions don’t add any utility. One of them even put it to me really directly: “This seems like print statements with extra steps…”
Layering in functionality after that took about 10 more examples, and about 45 minutes, and that’s just simply too long to make using functions feel helpful. Even though students self-reported that they “mostly understood” the lesson in their exit tickets, their performance the following day revealed that most of them were still confused.
Here’s a revision that adds some context:
def get_permissions(name, age):
permissions = ["G", "PG"]
if age > 12:
permissions.append("PG-13")
if age > 17:
permissions.append("R")
print(f'Permissions granted for {name}')
return permissionsuser1_permissions = get_permissions("Yessenia", 17)
user2_permissions = get_permissions("Grace", 14)print(user2_permissions)
This setup is complicated, but in my experience, not prohibitively so. If students have some working knowledge of lists, they’re ready to tackle this example with the support of some scaffolded questions:
How many times am I defining
get_permissions
? How did you know?
How many times am I calling (using/running)get_permissions
?In this example, how old is Yessenia? Which movies should she be allowed to see?
What’s the name of the variable where I’m storing Yessenia’s permissions?When I run
get_permissions
for Grace, which movies should be in her list?When I run this code, why will I see Grace’s list, but not Yessenia’s?
After we run this example, I find it helpful to play with it a bit more: “Okay, Javi, let’s do yours. You’re 18, correct? We’ll make you user 3.”
After that, students may not have recognized the full extent of how powerful functions can be, but they will have a really firm grasp of how get_permissions
works. With that working understanding established, they’ll be ready to pin down important vocabulary like functions, calls, arguments, parameters, and return in a far more meaningful way.
We can conclude this intro with a conversation about how we could do this without using a function, and why this approach is far more efficient. In total, it takes about half the time to teach functions starting with this more complex example, and I have significantly fewer students who finish the day confused.
Example 3: Object Orientation
I think in general, OO is an interesting topic to examine, because we’ve already improved so much as a community. I haven’t seen this specific example in a while, but it still sticks out to me pretty vividly.
class Foo: def __init__(self, bar):
self.bar = bar
foo = Foo("Bar")print(foo.bar)
The wildest part: this example is simultaneously too broad and too specific. It’s using the same two placeholders foo
and bar
as five different things: a class, a variable, a string, a parameter, and an instance variable, and the very specific mapping of a string to an identically-named instance variable means that a student has no opportunity to draw any connections themselves.
They might very reasonably assume that print(foo.elephant)
would produce the string “Elephant” because there’s no reason, rhyme, or rationale for why this code snippet operates the way it does.
Instead, what about this?
class User:
def __init__(self, name, email):
self.name = name
self.email = emailuser1 = User("Jeff", "Jj123@gmail.com")
user2 = User("Beyonce", "TheBoss@beyonce.com")print(user2.email)
We’ve named our instance variables something intuitive, and we’ve passed in some strings that a student can parse really easily.
Furthermore, by using two instances instead of one, and using variable names user1
and user2
, we’ve already hinted at the idea that the User class serves as a blueprint/archetype used to create instances, even without explicitly offering those terms.
Bonus Topic: When to Use Bad Names
(updated 1/30)
I got some excellent feedback on this post from Jesse Farmer and others about something I do, but didn’t mention: after a few good examples, show something absurd so that students start to recognize the value of naming variables well.
I usually hit this topic really hard on day 1, and then touch on it more briefly later, so I’ll reuse the string example from above, and change the variables
x = "Ada"
y = "Lovelace"
z = x + y
print(z)
Usually I ask “will this still work?”
Students make predictions, we run the code, and we draw some conclusions. Even still, since this draws a tiny bit on math prior knowledge, sometimes students may have a limited understanding of what variables can be called. I usually follow up with this example:
pineapple = "Ada"
mango = "Lovelace"
fruit_salad = pineapple + mango
print(fruit_salad)
We finish up with our last round of questions.
“Will this still work?”
“Well then out of all these options,
first_name
,x
, andpineapple
, if they all work, which one should we use? Why?”
Students almost always answer in a way that proves they have, in one 90-second example, grasped both the full extent of the freedom they have with variables, as well as the rationale for naming them well.
Later on, we talk about language-specific nuances & no-nos like capital letters and 1st_favorite_food
when these issues pop up in student work. Generally, though, students are more likely to over-match the teacher’s conventions rather than under-match them, so these issues tend to be the exception, not the rule.
The Takeaway
When you’re working with beginners, “Foo”
and “Bar”
should be red flags that your examples need reworking. Their less sinister but more pervasive counterparts s
, c
, i
, and arr
should also be signals that your code lacks context.
That said, I don’t mean to imply that Beyonce’s fake email or my function to get movie permissions belong on w3schools or in any official Python documentation — these examples are specific to me and to my students, and those more formal resources have to be useful for audiences of all ages, the world over.
I do think that if you lift your code snippets directly from documentation or tutorials without modifying them to leverage your students’ existing working knowledge of the world around them, you may be missing opportunities to make students feel powerful and intellectually satisfied.
Students don’t need simple examples, they just needs clear ones. They need examples that let them use their intuition instead of asking them to check it at the door.