May 25, 2013 12:12 PM
Getting the Right Relationship with a Class of Students
Thinking back over the semester, both about my course and about conversations I've had with colleagues about theirs, I'm reminded of a short passage from Keith Johnstone's "Impro: Improvisation and the Theatre":
There seems no doubt that a group can make or break its members, and that it's more powerful than the individuals in it. A great group can propel its members forward so that they achieve amazing things. Many teachers don't seem to think that manipulating a group is their responsibility at all. If they're working with a destructive, bored group, they just blame the students for being 'dull', or uninterested. It's essential for the teacher to blame himself if the group isn't in a good state.
It is hard to predict when a group of students will come together on its own and propel its members forward to achieve amazing things. Sometimes it happens almost spontaneously, as if by magic. I doubt it's magic, though, as much as students with the right attitudes and with skills for working with others. Sometimes, we don't know our students as well as we think. In any case, we teachers love to be around when the lightning strikes.
Bad teachers too often blame their students, or external circumstances, when a class dynamic turns destructive. Good teachers know it's their job to mold the group. They pay attention to attitudes and interactions, and they work to steer the group toward cohesiveness and accomplishment. Great teachers deliver consistently, within the constraints of their environments.
I'd love to say that I aspire to greatness, but that's too lofty a goal. These days, I still have to work hard just to get a peek at good every now and then. Being aware that the group dynamic is part of the teacher's responsibility is a good first step.
May 23, 2013 3:57 PM
Bad Examples Are Everywhere
... even in the Java class libraries.
Earlier today, @fogus joked:
The java.awt.Point class was only created because someone needed a 1st example to show how to make an object for a book they were writing.
My response was only half-joking:
And I use it as an example of how not to make a class.
If you have ever seen the Point class, you might understand why. Two public instance variables, seven methods for reading and writing the instance variables, and only one method (translate) that could conceivably be considered a behavior. But it's not; it's just a relative writer.
When this is the first class we show our students and ask them to use, we immediately handicap them with an image of objects as buckets of data and programs as manipulation of values. We may as well teach them C or Pascal.
This has long been a challenger for teaching OOP in CS1. If a class has simple enough syntax for the novice programmer to understand, it is generally a bad example of an object. If a class has interesting behavior, it is generally too complex for the novice programmer to understand.
This is one of the primary motivations for authors to create frameworks for their OOP/CS1 textbooks. One of the earliest such frameworks I remember was the Graphics Package (GP) library in Object-Oriented Programming in Pascal, by Connor, Niguidula, and van Dam. Similar approaches have been used in more recent books, but the common thread is an existing set of classes that allow users to use and create meaningful objects right away, even as they learn syntax.
A lot of these frameworks have a point objects as egregious as Java's GP included. But with these frameworks, the misleading Point class need not be the first thing students see, and when seen they are used in a context that consist of rich objects interacting as objects should.
These frameworks create a new challenge for the legacy CS profs among us. We like to "begin with the fundamentals" and have students write programs "from scratch", so that they "understand the entire program" from the beginning. Because, you know, that's the way we learned to program.
May 21, 2013 3:05 PM
Exercises in Exercises in Style
I just registered for Strange Loop 2013, which doesn't happen until this fall. This has become a popular conference, deservedly so, and it didn't seem like a good idea to wait to register and risk being shut out.
One of the talks I'm looking forward to is by Crista Lopes. I mentioned Crista in a blog entry from last year's Strange Loop, for a talk she gave at OOPSLA 2003 that made an analogy between programming language and natural language. This year, she will give a talk called Exercises in Style that draws inspiration from a literary exercise:
Back in the 1940s, a French writer called Raymond Queneau wrote an interesting book with the title Exercises in Style featuring 99 renditions of the exact same short story, each written in a different style. This talk will shamelessly do the same for a simple program. From monolithic to object-oriented to continuations to relational to publish/subscribe to monadic to aspect-oriented to map-reduce, and much more, you will get a tour through the richness of human computational thought by means of implementing one simple program in many different ways.
If you've been reading this blog for long, you can image how much I like this idea. I even checked Queneau's book out of the library and announced on Twitter my plan to read it before the conference. From the response I received, I gather a lot of conferences attendees plan to do the same. You gotta love the audience Strange Loop cultivates.
I actually have a little experience with this idea of writing the same program in multiple styles, only on a much smaller scale. For most of the last twenty years, our students have learned traditional procedural programming in their first-year sequence and object-oriented programming in the third course. I taught the third course twice a year for many years. One of things I often did early in the course was to look at the same program in two forms, one written in a procedural style and one written in OOP. I hoped that the contrast between the programs would help them see the contrast between how we think about programs in the two styles.
I've been teaching functional programming regularly for the last decade, after our students have seen procedural and OO styles in previous courses, but I've rarely done the "exercises in style" demo in this course. For one thing, it is a course on languages and interpreters, not a course on functional programming per se, so the focus is on getting to interpreters as soon as possible. We do talk about differences in the styles in terms of their concepts and the underlying differences (and similarities!) in their implementation. But I think about doing so every time I prep the next offering of the course.
Not doing "exercises in style" can be attractive, too. Small examples can mislead beginning students about what is important, or distract them with concepts they'd won't understand for a while. The wrong examples can damage their motivation to learn. In the procedural/object-oriented comparison, I have had reasonable success in our OOP course with a program for simple bank accounts and a small set of users. But I don't know how well this exercise would work for a larger and more diverse set of styles, at least not at a scale I could use in our courses.
I thought of this when @kaleidic tweeted, "I hope @cristalopes includes an array language among her variations." I do, too, but my next thought was, "Well, now Crista needs to use an example problem for which an array language is reasonably well-suited." If the problem is not well suited to array languages, the solution might look awkward, or verbose, or convoluted. A newcomer to array languages is left to wonder, "Is this a problem with array languages, or with the example?" Human nature as it is, too many of us are prone to protect our own knowledge and assume that something is wrong with the new style.
An alternative approach is to get learners to suspend their disbelief for a while, learn some nuts and bolts, and then help them to solve bigger problems using the new style. My students usually struggle with this at first, but many of them eventually reach a point where they "get" the style. Solving a larger problem gives them a chance to learn the advantages and disadvantages of their new style, and retroactively learn more about the advantages and disadvantages of the styles they already know well. These trade-offs are the foundation of a really solid understanding of style.
I'm really intrigued by Queneau's idea. It seems that he uses a small example not to teach about each style in depth but rather to give us a taste. What does each style feel like in isolation? It is up to the aspiring writer to use this taste as a starting point, to figure out where each style might take you when used for a story of the writer's choosing.
That's a promising approach for programming styles, too, which is one of the reasons I am so looking forward to Crista's talk. As a teacher, I am a shameless thief of good ideas, so I am looking forward to seeing the example she uses, the way she solves it in the different styles, and the way she presents them to the crowd.
Another reason I'm looking forward to the talk is that I love programs, and this should be just plain fun.
May 18, 2013 12:52 PM
I bought a new bike this week, a refurbished 1989 Schwinn Le Tour:
I've been riding Le Tours for thirty years, even before they hit their stride as a great bike. Last September, I had an unexpected encounter with a fallen tree on the bike trail and bent the frame on my latest model, circa 1985. I was glad to find another in such fine condition. It has a lighter, sleeker body than my older model, and the guy who refurbished it installed nicer accessories than I'm used to.
After many months outdoors on foot and indoors on an exercise bike, I was psyched to get out on the road. For my first ride, I chose an old friend, a scenic 12-mile route north of town that I used to run regularly, but which I hadn't been on for two and a half years. The ride brought a mix of sensations: newness, nostalgia, and a familiar burn in my legs. A good ride to christen my new old bike and my new old legs.
2011 was the year of surgery. 2012 was the year of rehabilitation and recovery. I spent a lot of time getting my right knee and quadriceps back into a shape that supports a normal life. My mind, too.
2013 is the year in which I become a cyclist -- that is, if I am ever to become a cyclist in a way that resembles the way I used to be a runner. It's time.
I have a lot to learn, and re-learn. Some things are relatively big, such as how to train for long rides and how to pace myself in the midst of training. Others are as simple as how to dress in different weather conditions. This kind of learning is part of the fun for me.
The marathoner lying dormant within me is already setting goals, deep in the recesses of my mind... maybe a trip down the Cedar Valley Nature Trail to Cedar Rapids. I have a lot of work to do before I'm ready for such an ambitious ride. That's part of the fun for me, too.
May 17, 2013 3:26 PM
Pirates and Tenure
[Kare's] skull-and-crossbones design would come in handy when Jobs issued one of his infamous motivational koans to the Mac team: "It's better to be a pirate than join the Navy."
For some reason, that line brought to mind a favorite saying of one of my friends, Sid Kitchel:
Real men don't accept tenure.
If by some chance they do accept tenure, they should at least never move into administration, even temporarily. It's a bad perch from which to be a pirate.
May 14, 2013 2:35 PM
An Unusual Scheme-ism This Semester
While grading final projects and final exams in my Programming Languages courses this week, I noticed my students using an unusual Scheme construction. Instead of writing:
(cons new-item result-of-recursive-call)
... a few troubled souls fell into the habit of writing:
(append (list new-item) result-of-recursive-call)
We have been using Scheme in this course for many years, and this may be the first semester that I've ever seen this. It is certainly the first time I saw it enough to notice it and wonder, "What's up with that?"
Of course, in previous semesters, a few students have always used a similar construction when putting new items at the back of the list:
(append result-of-recursive-call (list new-item))
This semester, though, a handful used (append ... (list ... all over the place. When I asked one of them about it after seeing it on an earlier homework assignment, he didn't have much to say, so we talked about the more direct solution a bit and moved on.
But after seeing it multiple times on the final exam, I have to wonder what is going on. Maybe they simply adopted this form as a mental shorthand, a one-size-fits-all tool that gave them one fewer thing to think about when writing code. Maybe, though, it masks a systematic error in thinking that I might address.
Out of curiosity, I ran a quick experiment to see what sort of time advantage (cons ... has over (append ... (list .... Surely, initializing the cdr field of a new list's cons cell to null, then asking append to walk there and set it to point to the other list wastes time. But how much?
In Racket, the penalty is actually quite small, in the ballpark of 40ms for every million executions. That's not surprising, given that append must examine only one cell before reaching the end of its first argument. This stands in contrast to the more general case of wrapping an O(n) append operation inside another O(n) operation, which my students encounter when learning how to implement more efficient algorithms using an accumulator variable.
More important than any speed penalty, though, is the misunderstanding that enables or encourages a student to think about reassembling a structure of this sort with anything other than a straightforward call to cons. Seeing an anti-pattern of this sort in my students' code makes me want to uncover the pathology at play and root it out.
May 10, 2013 4:03 PM
Using Language to Understand a Data Set
Today was our twice-annual undergraduate research presentation day. Every B.S. student must do an undergraduate research project and present the results publicly. For the last few years, we have pooled the presentations on the morning of the Friday in finals week, after all the exams are given and everyone has a chunk of time free to present. It also means that more students and professors can attend, which makes for more a more engaging audience and a nice end to everyone's semester.
I worked with one undergraduate research student this spring. As I mentioned while considering the role of parsing in a compilers course, this student was looking for patterns in several years of professional basketball play-by-play data. His ultimate goal was to explore ways of measuring the impact of individual defensive performance in the NBA -- fairly typical MoneyBall stuff applied to an skill that is not well measured or understood.
This project fell into my hands serendipitously. The student had approached a couple of other professors, who upon hearing the word "basketball" immediately pointed him to me. Of course, the project is really a data analytics project that just happens to involve a dataset from basketball, but... Fortunately, I am interested in both the approach and the domain!
As research sometimes does, this problem led the student to a new problem first. In order to analyze data in the way he wanted, he needed data of a particular sort. There is plenty of play-by-play data available publicly on the web, but it's mostly prepared for presentation in HTML. So he first had to collect the data by scraping the web, and then organize it into a data format amenable to analysis.
This student had taken my compiler course the last time around, and his ability to parse several files of similar but just-different-enough data proved to be invaluable. As presented on sites like nba.com, the data is no where near ready to be studied.
As the semester wore on, he and I came to realize that his project this semester wouldn't be the data analysis he originally intended to do. It was a substantial project simply to make sense of the data he had found.
As he presented his work today, I realized something further. He was using language to understand a data set.
He started by defining a grammar to model the data he found, so that he could parse it into a database. This involved recognizing categories of expression that were on the surface of the data, such as made and missed field goals, timeouts, and turnovers. When he ran this first version of his parser, he found unhandled entries and extended his grammar.
Then he looked at the semantics of the data and noticed discrepancies deeper in the data. The number of possessions his program observed in a game differed from the expected values, sometimes wildly and with no apparent pattern.
As we looked deeper, we realized that the surface syntax of the data often obscured some events that would extend or terminate a possession. A simple example is a missed FT, which sometimes ends a possession and sometimes not. It depends in part on the next event in the timeline.
To handle these case, the student created new syntactic categories that enabled his parser to resolve such issues by recognized composite events in the data. As he did this, his grammar grew, and his parser became better at building a more accurate semantic model of the game.
This turned out to be a semester-long project in its own right. He's still not done and intends to continue with this research after graduation. We were both a bit surprised at how much effort it took to corral the data, but in retrospect we should not have been too surprised. Data are collected and presented with many different purposes in mind. Having an accurate deep model of the underlying the phenomenon in question isn't always one of them.
I hope the student was pleased with his work and progress this semester. I was. In addition to its practical value toward solving a problem of mutual interest, it reminded me yet again of the value of language in understanding the world around us, and the remarkable value that the computational ideas we study in computer science have to offer. For some reason, it also reminded me, pleasantly, of the Racket Way. As I noted in that blog entry, this is really the essence of computer science.
Of course, if some NBA team were to give my student the data he needs in suitable form, he could dive into the open question of how better to measure individual defensive performance in basketball. He has some good ideas, and the CS and math skills needed to try them out.
Some NBA team should snatch this guy up.
May 08, 2013 12:11 PM
Not So Random Sentences
I start with a seemingly random set of sentences to blog about and, in the process of writing about them, find that perhaps they aren't so random after all.
An Era of Sharing Our Stuff
Property isn't theft; property is an inefficient distribution of resources.
Will ownership turn out to be largely a hack people resorted to before they had the infrastructure to manage sharing properly?
Open-source software, the Creative Commons, crowdsourcing. The times they are a-changin'.
An Era of Observing Ourselves
If the last century was marked by the ability to observe the interactions of physical matter -- think of technologies like x-ray and radar -- this century is going to be defined by the ability to observe people through the data they share.
... from The Data Made Me Do It.
I'm not too keen on being "observed" via data by every company in the world, even as understand the value it can brings the company and even me. But I like very much the idea that I can observe myself more easily and more productively. For years, I collected and studied data about my running and used what I learned to train and race better. Programmers are able to do this better now than ever before. You can learn a lot just by watching.
An Era of Thinking Like Scientist
... which leads to this line attributed to John C. Reynolds, an influential computer scientist who passed away recently:
Well, we know less than we did before, but more of what we know is actually true.
It's surprising how easy it is to know stuff when we don't have any evidence at all. Observing the world methodically, building models, and comparing them to what we observe in the future helps to know less of the wrong stuff and more of the right stuff.
Not everyone need be a scientist, but we'd all be better off if more of us thought like a scientist more often.
May 03, 2013 3:37 PM
A Participator in the Panorama of Nature
John Burroughs, in "The Exhilarations of the Road" (1895):
[The walker] is not isolated, but one with things, with the farms and industries on either hand. The vital, universal currents play through him. He knows the ground is alive; he feels the pulses of the wind, and reads the mute language of things. His sympathies are all aroused; his senses are continually reporting messages to his mind. Wind, frost, ruin, heat, cold, are something to him. He is not merely a spectator of the panorama of nature, but a participator in it. He experiences the country he passes through--tastes it, feels it, absorbs it; the traveller in his fine carriage sees it merely.
Knee surgery ended my avocation as a runner. I used to walk a lot, too, but these days I walk even more than I used to. For more than a year, I have walked to and from work almost every day, even through the Iowa winter. As both runner and walker, I recognize the exhilaration Burroughs describes. I find that I appreciate the elements rather than curse them. Wind and frost, rain and snow, heat and cold all matter. Why complain about a driving rain? The world is alive around me.
(I found Burroughs's passage in Solvitur Ambulando, a discourse on the virtues of walking in the spirit of Thoreau. I love the title as well as the essay.)
April 30, 2013 4:53 PM
A student stopped in for a chat late last week to discuss the code he was writing for a Programming Languages assignment. This was the sort of visit a professor enjoys most. The student had clearly put in plenty of time on his interpreter and had studied the code we had built in class. His code already worked. He wanted to talk about ways to make his code better.
Some students never reach this point before graduation. In Coders at Work, Bernie Cosell tells a story about leading teams of new hires at BBN:
I would get people -- bright, really good people, right out of college, tops of their classes -- on one of my projects. And they would know all about programming and I would give them some piece of the project to work on. And we would start crossing swords at our project-review meetings. They would say, "Why are you complaining about the fact that I have my global variables here, that I'm not doing this, that you don't like the way the subroutines are laid out? The program works."
They'd be stunned when I tell them, "I don't care that the program works. The fact that you're working here at all means that I expect you to be able to write programs that work. Writing programs that work is a skilled craft and you're good at it. Now, you have to learn how to program.
I always feel that we have done our students well if we can get them to the point of caring about their craft before they leave us. Some students come to us already having this mindset, which makes for a very different undergraduate experience. Professors enjoy working these students, too.
But what stood out to me most from this particular conversation was something the student said, something to this effect:
When we built the lexical addresser in class a few weeks ago, I didn't understand the idea and I couldn't write it. So I studied it over and over until I could write it myself and understand exactly why it worked. We haven't looked at lexical addressing since then, but the work I did has paid off every time we've written code to process programs in our little languages, including this assignment. And I write code more quickly on the exams now, too.
When he finished speaking, I could hardly contain myself. I wish I could bottle this attitude and give to every student who ever thinks that easy material is an opportunity to take it easy in a course for a while. Or who thinks that the best response to difficult material is to wait for something easier to come along next chapter.
Both situations are opportunities to invest energy in the course. The returns on investment are deeper understanding of the material, sharper programming skills, and the ability to get stuff done.
This student is reaping now the benefits of an investment he made five weeks ago. It's a gift that will keep on giving long after this course is over.
I encourage students to approach their courses and jobs in this way, but the message doesn't always stick. As Clay Stone from City Slickers might say, I'm happy as a puppy with two peters whenever it does.
While walking this morning, I coined a word for this effect: exceleration. It's a portmanteau combining "excellence" and "acceleration", which fits this phenomenon well. As with compound interest and reinvested dividends, this sort of investment builds on its self over time. It accelerates learners on their path to mastering their craft.
Whatever you call it, that conversation made my week.