May 31, 2017 2:28 PM

Porting Programs, Refactoring, and Language Translation

In his commonplace book A Certain World, W.H. Auden quotes C.S. Lewis on the controversial nature of tramslation:

[T]ranslation, by its very nature, is a continuous implicit commentary. It can become less tendentious only by becoming less of a translation.

Lewis was merely acknowledging a truth about language: Translators must have a point of view, and often that point of view will be controversial.

I once saw Kurt Vonnegut speak with a foreign language class here many years ago. One of the students asked him what he thought about the quality of the translations done for his book. Vonnegut laughed and said that his books were so peculiar and so steeped in Americana that translating one was akin to writing a new book. He said that his translators deserved all the royalties from the books they created by translating him. They had to write brand new works.

These memories came to mind again recently while I was reading Tyler Cowen's conversation with Jhumpa Lahiri, especially when Lahiri said this:

At one point I was talking about this idea, in antiquity: in Latin, the word for "translator" is "interpreter". I teach translation now, and I talk a lot to my students about translation being the most intimate form of reading and how there was the time when translating and interpreting and analyzing were all one thing.

As my mind usually does, it began to think about computer programs.

Like many programmers, I often find myself porting a program from one language to another. This is clearly translation but, as Vonnegut and and Lahiri tell us, it is also a form of interpretation. To port a piece of code, I have to understand its meaning and express that meaning in a new language. That language has its own constructs, idioms, patterns, and set of community practices and expectations. To port a program, one must have a point of view, so the process can be, to use Lewis's word, tendentious.

I often refactor code, too, both my own programs and programs written by others. This, too, is a form of translation, even though it leaves the new code written in the same language as the original. Refactoring is necessarily an opinionated act, and thus tendentious.

Occasionally, I refactor a program in order to learn what it does and how it does it. In those cases, I'm not judging the original code as anything but ill-suited to my current state of knowledge. Even so, when I get done, I usually like my version better, if only a little bit. It expresses what I learned in the process of rewriting the code.

It has always been hard for me to port a program without refactoring it, and now I understand why. Both activities are a kind of translation, and translation is by its nature an activity that requires a point of view.

This fall, I will again teach our "Translation of Programming Languages" course. Writing a compiler requires one to become intimate not only with specific programs, the behavior of which the compiler must preserve, but also the language itself. At the end of the project, my students know the grammar, syntax, and semantics of our source language in a close, almost personal way. The target language, too. I don't mind if my students develop a strong point of view, even a controversial one, along the way. (I'm actually disappointed if the stronger students do not!) That's a part of writing new software, too.


Posted by Eugene Wallingford | Permalink | Categories: General, Patterns, Software Development, Teaching and Learning

May 30, 2017 4:28 PM

Learning by Guided Struggle

A few years ago, someone asked MathOverflow, "Why do so many textbooks have so much technical detail and so little enlightenment?" Some CS textbooks suffer from this problem, too, though these days the more likely case is that the book tries to provide too much context. They try to motivate so much that they drown the reader in a lot of unhelpful words.

The top answer on MathOverflow (via Brian Marick) points out that the real problem does not usually lie in the lack of motivation or context provided by textbooks. The real goal is to learn how to do math, not "know" it. That is even more true of software developent. A textbook can't really teach to write programs; most of that is learned through doing itself. Perhaps the best purpose that the text can serve, says the answer, is to show the reader what he or she needs to learn. From there, the reader must go off and practice.

How does learning occur from there?

Based on my own experience as both a student and a teacher, I have come to the conclusion that the best way to learn is through "guided struggle". You have to do the work yourself, but you need someone else there to either help you over obstacles you can't get around despite a lot of effort or provide you with some critical knowledge (usually the right perspective but sometimes a clever trick) you are missing. Without the prior effort by the student, the knowledge supplied by a teacher has much less impact.

Some college CS students seem to understand this, or perhaps they simply get lucky because they are motivated to program for some other reason. They go off and try to do something using the knowledge they have. Then they come to class, or to the prof's office hours, to ask questions about what does not go smoothly. Students who skip the practice and hope that lectures will soak into them like a magic balm generally find that they don't know much when they attempt problems after class.

The MathOverflow answer matches up pretty well with my experience. Teachers and written material can have strong positive effect on learning, but they are most effective once the student has engaged with the material by trying to solve problems or write code. The teacher's job then has two parts: First, create conditions in which students can work productively. Second, pay close attention to what students are doing, diagnose misconceptions and mistakes, and help students get back onto a productive path by pointing out missing practices or bits of knowledge.

All of this reminds me of some of mymore effective class sessions teaching novice programmers, using design patterns. A typical session looks something like this:

  • I give the students a problem to solve.
  • Students work on a solution, using techniques that have worked in the past.
  • They encounter problems, because the context around the problem has shifted in ways that they can't see given only what they know.
  • We discuss the forces at play and tease out the underlying problem.
  • I demonstrate the pattern's solution.
  • Ahhhh.

This is a guided struggle in the small. Students then go off to write a larger program that lets them struggle a bit more, and we discuss whatever gets in their way.

A final note... One of the comments on the answer points out that a good lecture can "do" math (or CS), rather than "tell", and that such lectures can be quite effective. I agree, but in my experience this is one of the hardest skills for a professor to develop. Once I have solved a problem, it is quite difficult for me to make it look to my students as if I am solving it anew in class. The more ingrained the skill, the harder it is for me to lecture about it in a way that is more helpful than telling a story. Such stories are an essential tool in the teacher's toolbox, but their lies more in motivating students than in teaching them how to write programs. Students still have to go off and do the hard work themselves. The teacher's job is to guide them through their struggles.


Posted by Eugene Wallingford | Permalink | Categories: Patterns, Software Development, Teaching and Learning

May 23, 2017 2:50 PM

Becoming a Manager Changed My Perspective

My perspective on the way the university works changed after I became department head. This paragraph describes rather well one of the changes:

The other major challenge is coming to terms with all of the constraints within which decisions are made. From the outside, it's often easy to criticize actual decisions when contrasted when imagined ideal outcomes. But when you know why those ideals have to be imaginary, and you have to maneuver within much narrower confines than you might have imagined, you start to understand the "why" behind some patterns. That can be frustrating, but if you treat it as a series of puzzles, it can be fun. Any idiot can get good results with infinite resources and discretion, but how can you improve results with flat funding, contradictory policies, and prickly personalities? That's where the challenge comes in.

Yes, the university could do everything in its power to meet the needs and desires of Computer Science. It turns out, though, that other departments have needs and desires, too. Sometimes, those needs are more critical at this moment than our are.

You would think that CS faculty, who identify and measure trade-offs as a part of their academic discipline, would grok the notion of trade-offs inside the institution more easily. It took me a while to really get. Now, a big part of my job is helping other faculty to see it, too, all the while advocating effectively for my department.

The paragraph quoted above is by Matt Reed, from How to.... This sentence from the same piece expresses one of the biggest challenges to my peace of mind and daily sense of accomplishment after becoming department head:

The victories in administrative roles tend to be vicarious, rather than personal or direct.

The way I help faculty and students most as department head is by helping to reduce or eliminate friction that slows them down and wastes their energy. My biggest wins are usually when our faculty and students accomplish something big.

The other most salient challenge to my professional peace of mind: lack of closure. Almost nothing is ever finished, no battle ever won; it all starts again tomorrow.


Posted by Eugene Wallingford | Permalink | Categories: Managing and Leading

May 21, 2017 10:07 AM

Computer Programs Have Much to Learn, and Much to Teach Us

In his recent interview with Tyler Cowen, Garry Kasparov talks about AI, chess, politics, and the future of creativity. In one of the more intriguing passages, he explains that building databases for chess endgames has demonstrated how little we understand about the game and offers insight into how we know that chess-playing computer programs -- now so far beyond humans that even the world champion can only score occasionally against commodity programs -- still have a long way to improve.

He gives as an example a particular position with a king, two rooks, a knight on one side versus a king and two rooks on the other. Through the retrograde analysis used to construct endgame databases, we know that, with ideal play by both sides, the stronger side can force checkmate in 490 moves. Yes, 490. Kasparov says:

Now, I can tell you that -- even being a very decent player -- for the first 400 moves, I could hardly understand why these pieces moved around like a dance. It's endless dance around the board. You don't see any pattern, trust me. No pattern, because they move from one side to another.
At certain points I saw, "Oh, but white's position has deteriorated. It was better 50 moves before." The question is -- and this is a big question -- if there are certain positions in these endgames, like seven-piece endgames, that take, by the best play of both sides, 500 moves to win the game, what does it tell us about the quality of the game that we play, which is an average 50 moves? [...]
Maybe with machines, we can actually move our knowledge much further, and we can understand how to play decent games at much greater lengths.

But there's more. Do chess-playing computer programs, so much superior to even the best human players, understand these endgames either? I don't mean "understand" in the human sense, but only in the sense of being able to play games of that quality. Kasparov moves on to his analysis of games between the best programs:

I think you can confirm my observations that there's something strange in these games. First of all, they are longer, of course. They are much longer because machines don't make the same mistakes [we do] so they could play 70, 80 moves, 100 moves. [That is] way, way below what we expect from perfect chess.
That tells us that [the] machines are not perfect. Most of those games are decided by one of the machines suddenly. Can I call it losing patience? Because you're in a position that is roughly even. [...] The pieces are all over, and then suddenly one machine makes a, you may call, human mistake. Suddenly it loses patience, and it tries to break up without a good reason behind it.
That also tells us [...] that machines also have, you may call it, psychology, the pattern and the decision-making. If you understand this pattern, we can make certain predictions.

Kasparov is heartened by this, and it's part of the reason that he is not as pessimistic about the near-term prospects of AI as some well-known scientists and engineers are. Even with so-called deep learning, our programs are only beginning to scratch the surface of complexity in the universe. There is no particular reason to think that the opaque systems evolved to drive our cars and fly our drones will be any more perfect in their domains than our game-playing programs, and we have strong evidence from the domain of games that programs are still far from perfect.

On a more optimistic note, advances in AI give us an opportunity to use programs to help us understand the world better and to improve our own judgment. Kasparov sees this in chess, in the big gaps between the best human play, the best computer play, and perfect play in even relatively simple positions; I wrote wistfully about this last year, prompted by AlphaGo's breakthrough. But the opportunity is much more valuable when we move beyond playing games, as Cowen alluded in an aside during Kasparov's explanation: Imagine how bad our politics will look in comparison to computer programs that do it well! We have much to learn.

As always, this episode of Conversations with Tyler was interesting and evocative throughout. If you are a chess player, there is an special bonus. The transcript includes a pointer to Kasparov's Immortal Game against Veselin Topalov at Wijk aan Zee in 1999, along with a discussion of some of Kasparov's thoughts on the game beginning with the pivotal move 24. Rxd4. This game, an object of uncommon beauty, will stand as an eternal reminder why, even in the face of advancing AI, it will always matter that people play and compete and create.

~~~~

If you enjoyed this entry, you might also like Old Dreams Live On. It looks more foresightful now that AlphaGo has arrived.


Posted by Eugene Wallingford | Permalink | Categories: Computing, General

May 16, 2017 10:57 AM

The Big O

I recently ran across a newspaper column about triple-doubles, a secondary statistic in basketball that tracks when a player reaches "double figures" in three of the major primary stats. The column included this short passage about the great Oscar Robertson:

You probably know that Robertson averaged triple-doubles for an entire season, 1961-62. But did you know that he averaged triple-doubles over the cumulative first five seasons of his NBA career, from 1960-61 through '64-65? In that stretch Robertson averaged 30.3 points, 10.4 rebounds, and 10.6 assists.

This is indeed an amazing accomplishment. But it was not news to me.

I grew up in Indiana, a hotbed of basketball, with the sort of close personal attachment to Robertson that only a young sports fan can have. Like me, the "Big O" was from Indianapolis. He had led Crispus Attacks High School to two straight state championships in the late 1950s and helped lead the University of Cincinnati to national prominence in the early 1960s. When I first became aware of basketball as a young boy, Robertson was deep into a stellar pro career. He was one of my early sports idols.

Later, Robertson and his legacy played an unexpected role in my life. When I interviewed for the scholarship that would pay my way through college, I found that the interviewer, the dean of the Honors College, was a former Division III basketball player from Michigan who had gone on to earn a PhD in history from the University of Maryland. Our conversation quickly turned to basketball and our mutual admiration for the Big O, but it was not all sports talk. Robertson's career as a black player in the 1950s and '60s launched us into a discussion of urban segregation, race relations, and the role of sport in culture.

After the interview, I wondered if it had been wise tactially to talk so much about basketball. I guess the conversation went well enough, though.

Folks today can have Michael Jordan and LeBron. They are undeniably great players, but Oscar Robertson will always be my standard for all-around play -- and a touchpoint in my own life.


Posted by Eugene Wallingford | Permalink | Categories: Personal

May 09, 2017 1:22 PM

Pair Programming, Script Writing Edition

Screenwriter Ken Levine answers one of his Friday Questions about how he and writing partner David Isaacs worked:

We always worked on the same script. And we always worked together in the room. Lots of teams will divide up scenes, write separately, then return to either polish it together or rewrite each other's scenes on their own. We wrote head-to-head. To us the value of a partnership is to get immediate feedback from someone you trust, and more importantly, have someone to go to lunch with.

It sounds like Levine and Isaacs (MASH, Cheers, Frasier, ...) discovered the benefits of pair programming in their own line of work.

I liked the second part of his answer, too, about whether they ever gave up on a script once they starting writing it:

Nothing gets done unless both team members are committed to it. Once we began to write a spec there was never any discussion of just junking or tabling it to work on something else. We would struggle at times with the story or certain jokes but we always fought our way through it. Wrestling scripts to the ground is excellent training for when you do go on staff.

Wrestling code to the ground is excellent training for what you have to do as a developer, too. On those occasions when what you thought was a good idea turns out to be a bad one, it is wise to pitch it and move on. But it's too easy to blame difficulty in the trenches on the idea. Often, the difficulty is a hint that you need to work harder or dig deeper. Pairing with another programmer often provides the support you need to stick with it.


Posted by Eugene Wallingford | Permalink | Categories: Software Development

May 04, 2017 4:07 PM

Tweak

In an essay in The Guardian, writer George Saunders reflects on having written his first novel after many years writing shorter fiction. To a first approximation, he found the two experiences to be quite similar. In particular,

What does an artist do, mostly? She tweaks that which she's already done.

I read this on a day when I had just graded thirty-plus programming assignments from my junior/senior-level Programming Languages courses, and this made me think of student programmers. My first thought was snarky, and only partly tongue-in-cheek: Students write and then submit. Who has the time or interest to tweak?

My conscience quickly got the better of me, and I admitted that this was unfair. In a weak moment at the end of a long day, it's easy to be dismissive and not think about students as people who face all sorts of pressures both in and out of the classroom. Never forget Hanlon's Razor, my favorite formulation of which is:

Never attribute to malice or stupidity that which can be explained by moderately rational individuals following incentives in a complex system of interactions.

Even allowing the snark, my first thought was inaccurate. The code students submit is often the end result of laborious tweaking. The thing is, most students tweak only while the code gives incorrect answers. In the worst case, some students tweak and tweak, employing an age-old but highly inefficient software development methodology: Make another change and see if it works.

This realization brought to mind Kent Beck's Rules of Simple Design:

  1. passes the tests
  2. reveals intention
  3. has no duplication
  4. has the fewest elements possible

Most students are under time pressures that make artistry a luxury good; they are happy to find time to make their code work at all. If the code passes the tests, it's probably good enough for now.

But there is more to the student's willingness to stop tinkering so soon than just external pressures. It takes a lot of programming experience and a fair amount of time to come to even appreciate Rules 2 through 4. Why does it matter if code reveals the programmer's intention, in terms of either art or engineering? What's the big deal about a little duplication? The fewest elements? -- making that happen takes time that could be spent on something much more interesting.

I am coming to think of Kent's rules as a sort of Bloom's taxonomy for the development of programming expertise. Students start at Level 1, happy to write code that achieves its stated purpose. As they grow, programmers move through the rules, mastering deeper levels of understanding of design, simplicity, and, yes, artistry. They don't move through the stages in a purely linear fashion, but they do tend to master the rules in roughly the order listed above.

Today is a day of empathy for my novice programmers. As I write this, they are writing the final exam in my course. I hope that in a few weeks, after the blur of a busy semester settles in their minds, they reflect a bit and see that they have made progress as programmers -- and that they can now ask better questions about the programming languages they use than they could at the beginning of the course.


Posted by Eugene Wallingford | Permalink | Categories: Software Development, Teaching and Learning