We hear a lot about Ada Lovelace being the first computer programmer, but that may not be her most impressive computing first. When I read Steven Johnson's The Tech Innovators of the Victorian Age I learned that she may have been the first modern person to envision the digital computer as a vehicle for an intelligent machine.
Though I have heard about Ada's work with Charles Babbage before, I didn't know any of the details. An engineer had written an essay about the Analytical Engine in Italian, and Lovelace set out to translate it into English. But she also added her own comments to the text as footnotes. It was in a footnote that she recorded "a series of elemental instruction sets that could be used to direct the calculations of the Analytical Engine". When people say Lovelace was the first computer programmer, they are referring to this footnote.
Some people contend that Lovelace did not write this program; rather, Babbage had outlined some procedures and that she refined them. If that is true, then Lovelace and Babbage still conspired on a noteworthy act: they were the first people to collaborate on a program. How fitting that the first computer program was a team effort.
That is only the beginning. Writes Johnson,
But her greatest contribution lay not in writing instruction sets but, rather, in envisioning a range of utility for the machine that Babbage himself had not considered. "Many persons," she wrote, "imagine that because the business of the engine is to give its results in numerical notation, the nature of its processes must consequently be arithmetical and numerical, rather than algebraical and analytical. This is an error. The engine can arrange and combine its numerical quantities exactly as if they were letters or any other general symbols."
Lovelace foresaw the use of computation for symbol manipulation, analytical reasoning, and even the arts:
"Supposing, for instance, that the fundamental relations of pitched sounds in the science of harmony and musical composition were susceptible of such expressions and adaptations, the Engine might compose elaborate and scientific pieces of music of any degree of complexity or extent."
The Analytical Engine could be used to simulate intelligent behavior. Lovelace imagined artificial intelligence.
Johnson calls this perhaps the most visionary footnote in the history of print. That may be a bit over the top, but can you blame him? Most people of the 19th century could hardly conceive of the idea of a programmable computer. By the middle of the 20th century, many people understood that computers could implement arithmetic processes that would change many areas of life. But for most people, the idea of an "intelligent machine" was fantastic, not realistic.
In 1956, a group of visionary scientists organized the Dartmouth conferences to brainstorm from the belief that "every aspect of learning or any other feature of intelligence can in principle be so precisely described that a machine can be made to simulate it". The Darmouth summer project may have been a seminal event in the history of AI. However, over a century earlier, Ada Lovelace saw the potential that a computing machine could partake in language and art. That may have been the first seminal moment in AI history.
Because they will remember better! This Science Alert summarizes research which shows that "our minds actively reward us for seeking out the information we're most interested in". When people attain something they find intrinsically valuable, their brains release a dose of dopamine, which increases the learner's energy level and seems to enhance the connections between cells that contribute to remembering.
What I found most interesting, though, was this unexpected connection, as reported in this research paper from the journal Neuron (emphasis added):
People find it easier to learn about topics that interest them, but little is known about the mechanisms by which intrinsic motivational states affect learning. We used functional magnetic resonance imaging to investigate how curiosity (intrinsic motivation to learn) influences memory. In both immediate and one-day-delayed memory tests, participants showed improved memory for information that they were curious about and for incidental material learned during states of high curiosity.
This study suggests that when people are curious about something, they remember better what they learn about it, but they also remember better other information they come into contact with at the same time.
So, it might be worth opening class with a question or challenge that excites students and primes their curiosity, even if it is only tangentially related to the course material. In the process of learning the material they find interesting, they may learn better the material we find interesting.
When trying to teach students about loops or variables or functional decomposition, it is worth the effort to find and cultivate good problems to apply the concept to. If the problem piques the students' interest, it may increase their brains' receptiveness to learning the computational ideas.
Administrative and teaching duties have been keeping me busy of late, but I've enjoyed following along with tilde.club, a throwback, shell-based, Unix community started by Paul Ford and blogged about by him on his ~ford page there.
tilde.club feels like 1986 to me, or maybe 2036. In one sense, it is much less than today's social networks. In many other ways, it is so much more. The spirit of learning and adventure and connecting are more important there than glitzy interface and data anlytics and posturing for a public that consists of hundreds of Facebook 'friends' and Twitter 'followers'.
Ford mentions the trade-off in his long Medium article:
It's not like you can build the next Facebook or Twitter or Google on top of a huge number of Internet-connected Linux servers. Sure, Facebook, Twitter, and Google are built on top of a huge number of loosely connected Linux servers. But you know what I mean.
This project brings to mind a recent interview with writer William Gibson, in which he talks about the future and the past. In particular, this passage expresses a refreshingly different idea of what knowledge from the future would be most interesting -- and useful -- today:
If there were somehow a way for me to get one body of knowledge from the future -- one volume of the great shelf of knowledge of a couple of hundred years from now -- I would want to get a history. I would want to get a history book. I would want to know what they think of us.
I often wonder what the future will think of this era of computing, in which we dream too small and set the bar of achievement too low. We can still see the 1960s and 1970s in our rearview mirror, yet the dreams and accomplishments of that era are forgotten by so many people today -- even computer scientists, who rarely ever think about that time at all.
tilde.club is the sort of project that looks backward and yet enables us to look forward. Eliminate as much noise as possible and see what evolves next. I'm curious to see where it goes.
Many people in and out of the software world think of design and programming as separate activities, which is a natural result of analogies that compare software development to engineering disciplines. I've never been fond of separating these tasks in my mind. When I build software with other people, there is too much fluidity between designing software and writing code to make separate roles productive.
In The Myth of the Builder, Soroush Khanlou objects to the analogy for a different reason: designers and programmers are really doing the same sort of thing, only at different levels of detail:
... We know that the designer is not doing the building; if programmer is also not doing the building, how is software turning from idea into reality?
What is happening is that the designer presents the software as very high-level blueprints to the programmer. The programmer then takes those and creates a lower-level set of blueprints for the compiler.
Thinking in terms of blueprints at a higher or lower level helps make sense of how it feels to be:
We can think of design and programming as different tasks, but not really as different kinds of task.
Khanlou goes a step farther:
(Incidentally, the compiler is producing an even lower-level blueprint, called the Intermediate Representation, which is translated in to a final set of blueprints, the specific instructions for different CPUs. It's blueprints all the way down.)
That's a catchy phrase, with a nod to other parts of computing culture. (I first saw the phrase it's turtles all the way down in Gödel, Escher, Bach, though I think its use in computing goes back farther.) Fortunately for software developers and compiler writers, we eventually hit the bottom turtle. When we write most programs, we don't have to worry about that, though.
Khanlou's blog ends with a useful reminder, echoing "Structure and Interpretation of Computer Programs":
It's not valuable to think of software as a bridge; it's too weird for that.
Analogies from software development to various engineering disciplines can take us only so far. Software is different.
There has been some controversy on my campus recently about a slew of hurtful posts made on the social media application Yik Yak. The following is something I wrote for my intro CS students, with minor changes.
Computing is often in the news, but we don't talk much about current events in class. That's not the focus of this course, and we have plenty to do...
But the recent news story in the Northern Iowan about Yik Yak has been on my mind. Yik Yak is a social media app that lets people make comments anonymously and vote on other people's comments. This kind of app has many possible uses, some of which are positive. Many people live under conditions where they need to be able to communicate anonymously.
Unfortunately, some people in the UNI area have been using it to post hurtful comments about various groups. This behavior is simply mean.
Yik Yak is a social app, so the controversy is about people and how they behave. In this regard, my reaction has been similar to so many others' reactions. I am always sad to be reminded that people actually think such things, and sadder to know that they feel compelled to say them out loud. To do so anonymously is an act of cowardice.
But this controversy is also about what we do, because Yik Yak is a program. We call it an "app", but that's just the term du jour. It is a computer program. Programmers wrote it.
We could have an interesting discussion about apps like this: their uses, the good and bad they enable, how to grow and guide communities of users, and so on. I do not use Yik Yak and am not a member of its community. I don't know much beyond what has been reported about it in the media. However, I have been part of Internet-based communities since I was in college, and they all seem to have a lot in common with one another. So this situation feels quite familiar to me.
I am not going to lecture a group of young people about the ways they communicate and congregate on-line. Let me just say this.
When you learn to program, you inherit power to affect the world. You can make things, programs and apps and services that real people use. You can choose to use your power to do good things, to make the world better. Or you can not choose to. Not choosing may mean creating something whose effects you did not consider, or whose community behaves in ways you did not intend.
Please take your power seriously. Think about the effects of what you do when you write a program. Choose wisely.
... is determined by the moments when something happens.
In the end, a person doesn't view his [or her] life as merely the average of its moments -- which, after all, is mostly nothing much, plus some sleep. Life is meaningful because it is a story, and a story's arc is determined by the moments when something happens.
So writes Atul Gawande in Being Mortal: Medicine and What Matters in the End. When I am deep in a semester, preparing a course and doing all the things that a department head must do, both big small, the pace of life reaches a point where my mind is prone to go into cruise control. That's when I need to remind myself not to let my story become a stretch of uninterrupted white noise. I have to consciously step out of the blur and make something worthwhile -- and memorable -- happen.
In The Wave in the Mind, a collection of talks and essays, Ursula Le Guin describes Ernest Hemingway as "someone who did Man right". She also gives us insight to Hemingway's preferences in programming languages. Anyone who has read Hemingway knows that he loved short sentences. Le Guin tells us more:
Ernest Hemingway would have died rather than have syntax. Or semicolons.
So, Java and C are out. Python would fit. Or maybe Lisp. All the greats know Lisp.
... on how the world evolves.
On the evolution of education in the Age of the Web. Tyler Cowen, in Average Is Over, via The Atlantic:
It will become increasingly apparent how much of current education is driven by human weakness, namely the inability of most students to simply sit down and try to learn something on their own.
I'm curious whether we'll ever see a significant change in the number of students who can and do take the reins for themselves.
On the evolution of the Web. Jon Udell, in A Web of Agreements and Disagreements:
The web works as well as it does because we mostly agree on a set of tools and practices. But it evolves when we disagree, try different approaches, and test them against one another in a marketplace of ideas. Citizens of a web-literate planet should appreciate both the agreements and the disagreements.
Some disagreements are easier to appreciate after they fade into history.
Eventually a software project becomes a small amount of useful logic hidden among code that copies data between incompatible JSON libraries
Not all citizens of a web-literate planet appreciate disagreements between JSON libraries. Or Ruby gems.
On the evolution of start-ups. Rands, in The Old Guard:
... when [the Old Guard] say, "It feels off..." what they are poorly articulating is, "This process that you're building does not support one (or more) of the key values of the company."
I suspect the presence of incompatible JSON libraries means that our software no longer supports the key values of our company.
I see this in the lab every week. One minute, my students sit peering at their monitors, their heads buried in their hands. They can't do anything right. The next minute, I hear shouts of exultation and turn to see them, arms thrust in the air, celebrating their latest victory over the Gods of Programming. Moments later I look up and see their heads again in their hands. They are despondent. "When will this madness end?"
Last week, I ran across a tweet from Christina Cacioppo that expresses nicely a feeling that has been vexing so many of my intro CS students this semester:
I still find programming odd, in part, because I'm either amazed by how brilliant or how idiotic I am. There's no normal-person feeling.
Christina is no beginner, and neither am I. Yet we know this feeling well. Most programmers do, because it's a natural part of tackling problems that challenge us. If we didn't bounce between feeling puzzlement and exultation, we wouldn't be tackling hard-enough problems.
What seems strange to my students, and even to programmers with years of experience, is that there doesn't seem to be a middle ground. It's up or down. The only time we feel like normal people is when we aren't programming at all. (Even then, I don't have many normal-person feelings, but that's probably just me.)
I've always been comfortable with this bipolarity, which is part of why I have always felt comfortable as a programmer. I don't know how much of this comfort is natural inclination -- a personality trait -- and how much of it is learned attitude. I am sure it's a mixture of both. I've always liked solving puzzles, which inspired me to struggle with them, which helped me get better struggling with them.
Part of the job in teaching beginners to program is to convince them that this is a habit they can learn. Whatever their natural inclination, persistence and practice will help them develop the stamina they need to stick with hard problems and the emotional balance they need to handle the oscillations between exultation and despondency.
I try to help my students see that persistence and practice are the answer to most questions involving missing skills or bad habits. A big part of helping them this is coaching and cheerleading, not teaching programming language syntax and computational concepts. Coaching and cheerleading are not always tasks that come naturally to computer science PhDs, who are often most comfortable with syntax and abstractions. As a result, many CS profs are uncomfortable performing them, even when that's what our students need most. How do we get better at performing them? Persistence and practice.
The "no normal-person feeling" feature of programming is an instance of a more general feature of doing science. Martin Schwartz, a microbiologist at the University of Virginia, wrote a marvelous one-page article called The importance of stupidity in scientific research that discusses this element of being a scientist. Here's a representative sentence:
One of the beautiful things about science is that it allows us to bumble along, getting it wrong time after time, and feel perfectly fine as long as we learn something each time.
Scientists get used to this feeling. My students can, too. I already see the resilience growing in many of them. After the moment of exultation passes following their latest conquest, they dive into the next task. I see a gleam in their eyes as they realize they have no idea what to do. It's time to bury their heads in their hands and think.
Maybe We Just Need to Teach Better
A couple of weeks ago, I wrote Skills We Can Learn in response to a thread on the SIGCSE mailing list. Mark Guzdial has now written a series of posts in response to that thread, most recently Teaching Computer Science Better To Get Better Results. Here is one of the key paragraphs in his latest piece:
I watch my children taking CS classes, along with English, Chemistry, Physics, and Biology classes. In the CS classes, they code. In the other classes, they do on-line interactive exercises, they write papers, they use simulations, they solve problems by-hand. Back in CS, the only activity is coding with feedback. If we only have one technique for teaching, we shouldn't be surprised if it doesn't always work.
Mark then offers a reasonable hypothesis: We get poor results because we use ineffective teaching methods.
That's worthy of a new maxim of the sort found in my previous post: If things aren't going well in my course, it's probably my fault. Mark's hypothesis sounds more professional.
A skeptic might say that learning to program is like learning to speak a new human language, and when we learn new human languages we spend most of our time reading, writing, and speaking, and getting feedback from these activities. In an introductory programming course, the programming exercises are where students read, write, and get feedback. Isn't that enough?
For some students, yes, but not for all. This is also true in introductory foreign language courses, which is why teachers in those courses usually include games and other activities to engage the students and provide different kinds of feedback. Many of us do more than just programming exercises in computer science courses, too. In courses with theory and analysis, we give homework that asks students to solve problems, compute results, or give proofs for assertions about computation.
In my algorithms course, I open most days with a game. Students play the game for a while, and then we discuss strategies for playing the game well. I choose games whose playing strategies illustrate some algorithm design technique we are studying. This is a lot more fun than yet another Design an algorithm to... exercise. Some students seem to understand the ideas better, or at least differently, when they experience the ideas in a wider context.
I'm teaching our intro course right now, and over the last few weeks I have come to appreciate the paucity of different teaching techniques and methods used by a typical textbook. This is my first time to teach the course in ten years, and I'm creating a lot of my own materials from scratch. The quality and diversity of the materials are limited by my time and recent experience, with the result being... a lot of reading and writing of code.
What of the other kinds of activities that Mark mentions? Some code reading can be turned into problems that the students solve by hand. I have tried a couple of debugging exercises that students seemed to find useful. I'm only now beginning to see the ways in which those exercises succeeded and failed, as the students take on bigger tasks.
I can imagine all sorts of on-line interactive exercises and simulations that would help in this course. In particular, a visual simulator for various types of loops could help students see a program's repetitive behavior more immediately than watching the output of a simple program. Many of my students would likely benefit from a Bret Victor-like interactive document that exposes the internal working of, say, a for loop. Still others could use assistance with even simpler concepts, such as sequences of statements, assignment to variables, and choices.
In any case, I second Mark's calls to action. We need to find more and better methods for teaching CS topics. We need to find better ways to make proven methods available to CS instructors. Most importantly, we need to expect more of ourselves and demand more from our profession.
When things go poorly in my classroom, it's usually my fault.
I was putting together a short exercise for my students to do in class today. "Maybe this is too difficult. Should I make it easier?"
If you ever ask yourself this question, there is only one answer.
When in doubt, make it simpler.
On the days when I trust its wisdom and worry that I've made things too easy to be interesting, I am usually surprised by how well things go. On the days when I get lazy, or a little cocky, and stick with something that caused me to wonder, there is usually very little surprise.
I was in St. Paul this weekend to visit my younger daughter for the first time since she started college six weeks ago. (It is hard to believe I dropped my older daughter off at school for the first time three years ago.)
Friday night, my daughter treated us to a performance by Buckets and Tap Shoes. The group blended dance, music, and seductive showmanship to create a show that kept me bouncing in rhythm for two hours. The dance and music were heavy on tap and drums, which let the performers play with rhythms. They also interacted with the crowd throughout the show, which set them up for an encore finale with twenty or more audience members on stage drumming, dancing, and generally into the rhythm. Impressive.
We like her school, and the Highland Park neighborhood is quite nice, but the Twin Cities are too big and busy for my tastes. I'm glad to live where I live.
In A Fresh Look at Rust, Armin Ronacher tells us that some of what inspires him about Rust:
For me programming in Rust is pure joy. Yes I still don't agree with everything the language currently forces me to do but I can't say I have enjoyed programming that much in a long time. It gives me new ideas how to solve problems and I can't wait for the language to get stable.
Rust is inspiring for many reasons. The biggest reason I like it is because it's practical. I tried Haskell, I tried Erlang and neither of those languages spoke "I am a practical language" to me. I know there are many programmers that adore them, but they are not for me. Even if I could love those languages, other programmers would never do and that takes a lot of enjoyment away.
I enjoy reading personal blog entries from people excited by a new language, or newly excited by a language they are visiting again after a while away. I've only read Rust code, not written it, but I know just how Ronacher feels. These two paragraphs touch on several truths about how languages excite us:
Many programmers make a point of learning a new language periodically. When we do, we are often most struck by a language that teaches us new ways to think about problems and how to solve them. These are usually the languages that have the most teach us at the moment.
As Kevin Kelly says, progress sometimes demands that we let go of problems. We occasionally have to seek new problems, in order to be excited by new ways to answer them.
This all is very context-specific, other. How wonderful it is to live in a time with so many languages available to learn from. Let them all flourish, I say.
In a thread on motivating students on the SIGCSE mailing list, a longtime CS prof and textbook author wrote:
Over the years, I have come to believe that those of us who can become successful programmers have different internal wiring than most in the population. We know you need problem solving, mathematical, and intellectual skills but beyond that you need to be persistent, diligent, patient, and willing to deal with failure and learn from it.
These are necessary skills, indeed. Many of our students come to us without these skills and struggle to learn how to think like a computer scientist. And without persistence, diligence, patience, and a willingness to deal with failure and learn from it, anyone will likely have a difficult time learning to program.
Over time, it's natural to begin to think that these attributes are prerequisites -- things a person must have before he or she can learn to write programs. But I think that's wrong.
As someone else pointed out in the thread, too many people believe that to succeed in certain disciplines, one must be gifted, to possess an inherent talent for doing that kind of thing. Science, math, and computer science fit firmly in that set of disciplines for most people. Carol Dweck has shown that having such a "fixed" mindset of this sort prevents many people from sticking with these disciplines when they hit challenges, or even trying to learn them in the first place.
The attitude expressed in the quote above is counterproductive for teachers, whose job it is to help students learn things even when the students don't think they can.
When I talk to my students, I acknowledge that, to succeed in CS, you need to be persistent, diligent, patient, and willing to deal with failure and learn from it. But I approach these attributes from a growth mindset:
Persistence, diligence, patience, and willingness to learn from failure are habits anyone can develop with practice. Students can develop these habits regardless of their natural gifts or their previous education.
Aristotle said that excellence is not an act, but a habit. So are most of the attributes we need to succeed in CS. They are habits, not traits we are born with or actions we take.
Donald Knuth once said that only about 2 per cent of the population "resonates" with programming the way he does. That may be true. But even if most of us will never be part of Knuth's 2%, we can all develop the habits we need to program at a basic level. And a lot more than 2% are capable of building successful careers in the discipline.