Today, in my RubyStory class, I attempted to introduce the kids to Ruby functions. I won’t go so far as to say it was a disaster, but it didn’t go particularly well. They just didn’t get it.
OK. Functions are a pretty big concept for a new programmer to grasp.
I also made a major mistake: too much talking, not enough coding. The kids are much happier and seem to understand better when actually writing code, making things happen and experimenting on their own.
I did experiment with a different kind of example, however, and it seemed to bring some fun and understanding: “human functions.” Basically, the kids became functions and we interactively ran the program by talking to each other. Here’s how it worked.
First, I took one of the students, Sophie, aside and gave her some secret instructions: “Take the word you’re given and use it in a sentence.”
Then, one of the other students would “call” her with a word: “Sophie: donuts.” Sophie would respond “I love to eat donuts.”
We had some fun with it, as 10 year old kids will, and changed up the examples a bit. As I explained, this pretty much equates to the following code.
def sophie(word) puts "I love to eat " + word end sophie("donuts")
This seemed to help the kids understand a lot better. I think next class we’ll start out with more exercises like this before moving to the code. We could get multiple human functions involved to demonstrate how functions generalize tasks within a program.
For example, here’s a simplified version of our storytelling program.
def prompt(choice1, choice2) print "Which do you choose (%s or %s): " % [choice_1, choice_2] answer = gets.chomp return answer end def story puts "A zombie appears. Do you run or fight?" action = prompt("run", "fight") if action == "run" puts "Chicken! Bawk bawk bawk!" elsif action == "fight" winorlose end end def winorlose puts "Rolling the dice..." diceroll = 1 + rand(6) if diceroll > 3 puts "Yay! You win!" else puts "Sorry, you lose." end end
My human functions can run this program.
- Kendall starts the story, and passes the the prompt to Arden.
- Arden asks Teddy the question and returns his answer to Kendall.
- Kendall either ends the story (“run”) or calls Sophie (“fight”).
- Sophie rolls a die and, depending on the roll, tells Teddy whether he won or lost.
We’ll have to see how it works. Looks like I’ve got a bit of writing and scheming to do before the next lesson.
TL;DR version: I wrote some course materials and sample code for teaching the basics of Ruby programming to middle-school kids. The course is called RubyStory and teaches just enough Ruby to create a choose-your-own-adventure style storytelling game.
Last year my older daughter started fifth grade and brought home a school-supplied MacBook. Which is great. I think it’s important to give kids a chance at an early head start to develop technology and programming skills — an early taste, anyway, to see if they like it — particularly the girls.
I set about looking for an appropriate learning resource to teach my daughter. There’s a lot out there. Unfortunately, none of it quite appealed to my preferences.
I wanted something easy for me to read, parse out what was being taught, and know what to pass on to students. Many of the course materials I reviewed required a lot of up-front reading, then I’d have to create my own teaching notes.
Adults and older children might be motivated to learn programming for its own sake, but I think younger kids (8-13 at least) don’t have the same motivation (exceptions discussed below).
Learning while doing something fun, however, seems to work. So I wanted to start with an interesting goal and make sure each step along the way was both educational and fun.
Finally, the laptops at my daughter’s school are locked down, so I needed something that required no software not already installed on the machines.
Ultimately, it seemed easier to create my own materials. As a bonus, as mentioned in my posts about writing about code, I’d probably learn a lot in the process. And I did.
The result is a course I wrote called RubyStory and you can grab all of the materials from Github. The details are covered in the readme.
The course materials are intended for teaching to kids. I suppose they could be used for self-instruction, but my assumption is that kids who are ready and motivated to learn programming on their own are probably also ready and motivated enough to learn from a book or a more traditional tutorial.
The RubyStory materials are intentionally sparse. There’s an outline and sample code and handouts. There’s a slide deck, but it’s mostly just to show the code examples, which students can then type on their own.
The outline provides a concise overview of the topics to teach, but be prepared to fill in details, answer questions and riff a bit as your students require.
I wrote this course with the assumption that the teacher already has some basic programming knowledge. You don’t need much:
- Creating and using variables
- Strings and integers
- Basic math and Boolean logic
- Printing messages to the terminal
- Capturing input from the command line
- If statements
That’s all we use. Even if you know nothing about Ruby, you should be able to pick it up quickly. (I knew almost nothing about Ruby before starting this project.)
As you can tell from the minimal set of programming concepts covered by RubyStory, it’s hardly language specific nor does it really “teach Ruby.” In this case, Ruby is a convenient tool.
First, Ruby is already installed on every recent MacBook. The version installed is not important.
We don’t need any special tools to program with Ruby, just Terminal and a text editor. TextEdit isn’t the tool I’d prefer — syntax coloring would be a nice feature — but we can live with it for simplicity. (The slides do include syntax highlighting.)
Ruby has very simple syntax and very little necessary punctuation. Whitespace and semicolons aren’t that important and there are very few parentheses and brackets to worry about. I’ve found that kids have enough trouble with accurate typing. Simple syntax makes troubleshooting much easier.
Plus, I wanted to learn some Ruby. And I did.
Please fork the RubyStory repo and give teaching a try. I am continually updating the materials as I teach and learn from the kids — what the enjoy, what they build, what questions they ask, where I can help them go next. Let me know what you learn while teaching with RubyStory.
As written, RubyStory should be easily adapted to Linux systems, but I haven’t yet into what additional material would be needed for Chromebooks or Windows. It’s on my to do list.
Other than that, I’m now focused on using RubyStory for teaching in my community. I hope you will, too.
Bonus: Mike Wats merged my pull request, and now the new archive code is part of the core staticDimension code on Github.
Not bad for a first attempt at coding in public.
But it never really clicked for me. Until this year, when I started to put some real effort into not just learning about coding, but actually putting fingers to the keyboard and making something — anything! — execute and do something — anything!
I’ll write a bit more about the experience of putting years of theory into action another time. Right now I’m going to share my experience of doing one of my first real coding projects, however small it may be, right out in public for everyone to see.
As I mentioned in the previous post, my primary goal for this project was to create a simpler, easier to navigate archive of my blog posts that no longer appeared on the home page. Simple solution: create a single page with a listing of past posts. In the unlikely event that someone wanted to find one of my old posts, it would be easy to simply go to the archive page and either scroll the list or Command-F find the desired post title — responsibilty on me to write relevant post titles.
The quick-and-easy plan for adjusting the code was to comment out the archive code that I didn’t want to use and replace it with a modified version of the code used to create the home page. It just needed to grab the titles and bylines (including publishing dates) and make the title a link.
There were a few other details, such as including a link at the end of the home page to archive, so the intrepid reader who scrolled all the way down could fine more posts. And that was about it for version 1.
Making it Work for Anyone
Those tweaks would have sufficed for my site, but I felt a need to take the next step in my development as a developer: write code good enough for other people to use, not just me.
To my mind, that meant three things:
Make my changes a new, additional feature to the existing project, not just a tweaked version.
Write my feature in a way that defaults back to the standard functionality if anything goes wrong.
Try not to add much additional overhead to site updates.
As a bonus, I thought it would be interesting to submit a pull request and see if Mike would add my feature to his codebase.
I’m not all that self-conscious of the triviality of my changes. It adds a feature I want, it works, it doesn’t remove any functionality other users might use. The first part was pretty easy. The second part added a bit of a challenge.
After thinking about the problem, it seemed like the most straightforward approach would be to add a setting. If it’s set to true, my new feature gets used. A setting of false or any other value reverts to the default behavior.
/* Single-page Archive This setting enables a single-page archive instead of the default day-month-year folder archives... A value of 'true' enables single-page archives. Any other value currently uses the default archive format. */ $this->settings['singlePageArchive'] = true;
I left this as false by default as well, so anyone who pulled the code to an existing site would not be surprised by new, unexpected archive page creation. This was an important point for me: it should not break anyone’s existing site!
From there it was a fairly straightforward task to put in my new archive creation code (adapted from Mike’s original home page cration code) along with a test for the singlePageArchive setting.
That took care of my first two goals, adding new features on top of the existing ones, and not breaking the old, default features.
This is probably old hat to many programmers, but it was a pretty big step for a guy who’s worked with programmers for many years, yet never written anything comprising more than 20 or 30 lines of rudimentary Python.
For starters, I’d never spent much time wading around in PHP before, and what I had done was mostly cut-and-paste coding to quickly solve a problem. The contact page on this site [ed: deprecated in a redesign] is a great example: someone elses’s code example with a few tweaks to suit my needs.
The good news is that, over the course of many years, enough programming logic permeated my thick skull that I could follow the code, understand what it was doing, and find the interaction of functions I needed to modify — even though it was in a foreign language.
The moral of this story is that you can achieve quite a bit with a little knowledge, reference material on the web, some careful reading and persistent effort.
What I’d Like to Do Better
There’s definitely room for improvement. I have few illusions about that. So there are a few goals for the future:
Testing is something I’ve read much about, but haven’t done properly yet. This is a high-priority area to learn and incorporate into my future projects.
My third goal was to avoid adding overhead to site operation, and that may be one area where I’ve failed. As implemented, any action that adds, changes or removes articles updates the entire site to make sure the archive page gets updated. A better way to handle this would be to test whether the changes actually affect the archive and only update the affected pages instead of rebuilding the site.
For a small site, this probably isn’t an issue, but it would be more “right” in my mind.
Finally, I’ve been wanting the ability to update menus and sidebars without having to edit each page template individually — a source of several errors. So expanded templating would be nice and is on the to do list.
Polished Is Not a Requirement
Now, while I saw putting some spit and polish on my code as a prerequisite to sharing, it’s certainly not a requirement. In my case, I felt it set a reasonably high bar for my own work as well as making sure my contribution played well with someone else’s existing project.
This seems to be the quality bar many others set for contributing to existing projects. Play nice. Make your changes clear. Provide passing tests. It’s just good manners.
But there are plenty of cases where putting code up in public for other people to see, play with and discuss can help move an idea forward. The sentiment is pretty well summed up in this exchange between Kelly and Brandon:
@kellabyte always. Code doesn't mature in privacy.— Brandon Williams (@faltering) September 16, 2012
That led to Kelly posting her initial swag at writing her own home-brew column-oriented database, Dazzle, an attempt at understanding the inner workings of Cassandra by implementing her own version of it.
One thing I’ve learned from posting Dazzle on GitHub & code pastes in the past, embarrassed about your code only holds your progression back— Kelly Sommers (@kellabyte) September 26, 2012
Success or failure, the kinds of fast, constructive feedback loops enabled by Github and similar tools are great for learning. So there’s very little reason to not share your code.
I never doubted that public code repositories were a great idea, and the proliferation of choices — Bitbucket, Github, Google Code, SourceForge and others — indicates it’s a pretty popular and successful model for collaboration. And though I’d downloaded code and applications many times from these services, I never thought I’d write any code worth pushing back.
But my tiny triumph underscores how important it to just dig in and try something new. You can keep it to yourself if you want, but striving to make something you’re willing to share sets the bar high, and sharing opens the door to feedback, learning and improving. Whether it’s coding or writing or drawing… whatever floats your boat. Create. Share. Grow. Repeat.