As I look toward 2013, I've been thinking about Alan Kay's view of CS as science [ link ]:
I believe that the only kind of science computing can be is like the science of bridge building. Somebody has to build the bridges and other people have to tear them down and make better theories, and you have to keep on building bridges.
In 2013, what will I build? What will I break down, understand, and help others to understand better?
One building project I have in mind is an interactive text. One analysis project in mind involves functional design patterns.
Matthew Ward, in the Translator's Note to "The Stranger" (Vintage Books, 1988):
I have also attempted to venture further into the letter of Camus's novel, to capture what he said and how he said it, not what he meant. In theory, the latter should take care of itself.
This approach works pretty well for most authors and most books, I imagine.
Following an old link to Ridiculous Fish's Unix shell fish, I recently stumbled upon the delightful cdecl, a service that translates C declarations, however inscrutable, into plain English (and vice versa). As this introductory post says,
Every C declaration will be as an open book to you! Your coworkers' scruffy beards and suspenders will be nigh useless!
The site even provides permalinks so that you can share translations of your thorniest C casts with friends and family.
These pages are more than three years old, so I'm surely telling you something you already know. How did I just find this?
I don't program in C much these days, so cdecl itself is of use to me only as humorous diversion. But it occurs to me that simple tools like this could be useful in a pedagogical setting. Next semester, my students will be learning Scheme and functional programming style. The language doesn't have much syntax, but it does have all those parentheses. Whatever I say or do, they disorient many of my students for a while. Some them will look at even simple code such as
(let ((x (square 4)) (y 7)) (+ x y))
... and feel lost. We spend time in class learning how to read code, and talk about the semantics of such expressions, which helps. But in a pinch, wouldn't it be nice for a student to hit a button and have that code translated into something more immediately comprehensible? Perhaps:
Let x be the square of 4 and y be 7 in the sum of x and y.
This might be a nice learning tool for students as they struggle with a language that seems to them -- at least early on -- to be gibberish on a par with char (*(*(* const x)()))(int).
Some Scheme masters might well say, "But the syntax and semantics of a let are straightforward. You don't really need this tool." At one level, this is true. Unfortunately, it ignores the cognitive and psychological challenges that most people face when they learn something that is sufficiently unfamiliar to them.
Actually, I think we can use the straightforwardness of the translation as a vehicle to help students learn more than just how a let expression works. I have a deeper motive.
Learning Scheme and functional programming are only a part of the course. Its main purpose is to help students understand programming languages more generally, and how they are processed by interpreters and compilers.
When we look at the let expression above, we can see that translating it into the English expression is not only straightforward, it is 100% mechanical. If it's a mechanical process, then we can write a program to do it for us! Following a BNF description of the expression's syntax, we can write an interpreter that exposes the semantics of the expression.
In many ways, that is the essence of this course.
At this point, this is only a brainstorm, perhaps fueled by holiday cooking and several days away from the office. I don't know yet how much I will do with this in class next term, but there is some promise here.
Of course, we can imagine using a cdecl-like tool to help beginners learn other languages, too. Perhaps there are elements of writing OO code in Java that confuse students enough to make a simple translator useful. Surely public static void main( String args) deserves some special treatment! Ruby is complex enough that it might require dozens of little translators to do it justice. Unfortunately, it might take Matz's inside knowledge to write them.
(The idea of translating inscrutable code into language understandable by humans is not limited to computer code, of course. There is a popular movement, to write laws and other legal code in Plain English. This movement is occasionally championed by legislators -- especially in election years. The U.S. Securities and Exchange Commission has its own Plain English Initiative and Plain English Handbook. At seventy-seven pages, the SEC handbook is roughly the same size as R6RS description of Scheme.)
Interest in VoodooPad 5 far surpassed my expectations for it. I know that VoodooPad has a lot of fans out there, but I guess I just hadn't heard from them in a while.
Gus is a Mac developer with a solid following and a couple of very popular titles, the wiki editor VoodooPad and the image editor Acorn. I am a long-time user of VoodooPad and an occasional user of Acorn's progenitor, FlySketch, and so have experienced firsthand Gus's open relationship with the users of his products.
If even he can't predict which features his users will like most and least, there isn't a lot of hope for the rest of us. Our best strategy is to follow the agile advice: release often, get feedback soon and frequently, and learn from what our the users of our software tell us.
Anil Dash, on the web we lost:
... today's social networks, they've brought in hundreds of millions of new participants to these networks, and they've certainly made a small number of people rich.
But they haven't shown the web itself the respect and care it deserves, as a medium which has enabled them to succeed. And they've now narrowed the possibilities of the web for an entire generation of users who don't realize how much more innovative and meaningful their experience could be.
I've never warmed to Facebook, for much this reason. I enjoy Twitter, but I treat it as a source of ephemera. Anything that I want to last gets cached in a file of links, shared with colleagues or friends by e-mail, or -- best of all -- blogged about.
I sometimes wonder if blog readers will weary of finding links to things they've already seen via Twitter, or if Twitter has trained too many of us not to want to read someone's comments on such articles in blog entries. But this seems one of the great and lasting values of a blog, one that will remain even after Facebook and Twitter have gone the way of Usenet and GeoCities. The social web is more, and I want to remain a part of it.
My students spent the last three weeks of the semester implementing some of the infrastructure for a Twitter-like messaging app. They grew the app in three iterations, with new and changed features at each step. In the readme file for one of the versions, a student commented:
I wound up having a lot of code of the sort
I smiled and remembered again that even students who would never write such code in a smaller, more focused setting can be lulled into writing it in the process of growing a big, complicated program. I made a mental note to pay a little extra attention the next time I teach the course to the Law of Demeter.
I actually don't talk much about the Law of Demeter in this sophomore-level course, because it's a name we don't need. But occasionally I'd like to point a student to a discussion of it, and there don't seem to be a lot of resources at the right level for these students. So I decided to draft the beginnings of a simple reference. I welcome your suggestions on how to make it better.
You might also check out The Paperboy, The Wallet, and The Law Of Demeter, a nice tutorial I recently came across.
What is the Law of Demeter?
The Law of Demeter isn't a law so much as a general principle for software design. It is often referred to in the context of object-oriented programming, so you may see it phrased in terms of objects:
Objects should have short reach.
An object should not try to know too much, or need to.
The law's Wikipedia entry has a nice object-free formulation:
Only talk to your immediate friends.
If those are too squishy for you, the Wikipedia entry also as a more formal summary:
The fundamental notion is that a given object should assume as little as possible about the structure or properties of anything else (including its subcomponents).
Framed this way, the Law of Demeter is just a restatement of OOP 101. Objects are independent. They encapsulate their state and behavior. Instance variables are private, and we should be suspicious of getter methods.
As a matter of programming style, I often introduce this principle in a pragmatic way:
An operation should live with the data it uses.
Those are all general statements of the Law of Demeter. You will sometimes see a much more specific, formal statement of this sort:
A method m of an object obj may send messages only to these objects:
- obj itself
- obj's instance variables
- m's formal parameters
- any objects created within m
This version of the Law is actually an enumeration of specific ways that we can obey the more general principle. In the case of existing code, this version can help us recognize that the general principle has been violated.
Why is the Law of Demeter important?
This principle is often pitched as being about loose coupling: we should minimize the amount of knowledge that any component has about the implementation of any other component.
Another way to think about this principle from the perspective of the receiver. Some object wants access to its parts in order to do its job. From this angle, the Law of Demeter is fundamentally about encapsulation. The receiver's implementation should be private, and chained messages tend to leak implementation detail. When we hide those details from the object's collaborators, we shield other parts of the system from changes to the implementation.
How can we follow the Law of Demeter?
Consider my student's example from above:
The simplest way to eliminate the sender's need to know about thisInsideCollection and thisAttribute is to
Coming up with a good name for the new message doSomething forces us to think about what this behavior means in our program. Many times, finding a good name helps us to clarify how we think about the objects that make up our program.
Notice that the new method in thisCollection might still violate our design principle, because thisCollection needs to know that thisInsideCollection is implemented in terms of thisAttribute and that thisAttribute responds to thisMethod(). That's okay. You can apply the same process again, looking for a way to push the behavior that operates on thisAttribute into the object that knows about it.
More generally, when you notice yourself violating the Law of Demeter, think of the violation as an opportunity to rethink the objects in your program and how they relate to one another. Why is this object performing this task? Why doesn't its collaborator provide that service? Perhaps we can give this responsibility to another object. Who knows how to help this object with this task?
Sometimes, we even find that we can move thisMethod() into thisCollection and take our object out the loop entirely, letting the object that sent us the message communicate directly with thisCollection. That is a great way to make our code less tightly coupled.
A Potential Wrinkle
There is a potential problem when we program in a language like Java, though. What if thisCollection is a primitive Java class, say, a Vector or a HashMap? If so, you cannot add a new method to the class. This is sign of another problem looking in your program. This object depends on your choice of data structure for thisCollection. What role does thisCollection play in your domain? Maybe it's a catalog of users, or the set of users that follow another user.
Make a new class that represents this domain object, and make your data structure an instance variable in that class. Now you can write your program in terms of the domain object, not the Java primitive. This makes solves several problems for you:
This new wrinkle is sometimes called Primitive Obsession. OO masters know to beware its temptations. I sometimes like to play a little game in which every base type and every primitive class has been pushed down to the bottom layer of my program and wrapped in a domain object. This is often overkill -- taking a good thing too far -- but such an exercise can help you see just how often it really is a good thing to hide implementation detail and program in terms of the objects in your domain.
Some people say that programming isn't for everyone, just as knowing how to tinker under the hood of one's car isn't for everyone. Some people design and build cars; other people fix them; and the rest of us use them as high-level tools.
Douglas Rushkoff explains why this analogy is wrong:
Programming a computer is not like being the mechanic of an automobile. We're not looking at the difference between a mechanic and a driver, but between a driver and a passenger. If you don't know how to drive the car, you are forever dependent on your driver to take you where you want to go. You're even dependent on that driver to tell you when a place exists.
This is CS Education week, "a highly distributed celebration of the impact of computing and the need for computer science education". As a part of the festivities, Rushkoff was scheduled to address members of Congress and their staffers today about "the value of digital literacy". The passage quoted above is one of ten points he planned to make in his address.
As good as the other nine points are -- and several are very good -- I think the distinction between driver and passenger is the key, the essential idea for folks to understand about computing. If you can't program, you are not a driver; you are a passenger on someone else's trip. They get to decide where you go. You may want to invent a new place entirely, but you don't have the tools of invention. Worse yet, you may not even have the tools you need to imagine the new place. The world is as it is presented to you.
Don't just go along for the ride. Drive.
The programmers and teachers among you surely know this feeling well:
As I drift back to sleep, I can't help thinking that it's a wonderful thing to be right about the world. To weigh the evidence, always incomplete, and correctly intuit the whole, to see the world in a grain of sand, to recognize its beauty, its simplicity, its truth. It's as close as we get to God in this life, and we reside in the glow of such brief flashes of understanding, fully awake, sometimes, for two or three seconds, at peace with our existence. And then we go back to sleep.
Or tackle the next requirement.
(The passage is from Richard Russo's Straight Man, an enjoyable send-up of modern man in an academic life.)
The advantage of knowing how to program is that you can. The danger of knowing how to program is that you will want to.
From Paul Graham's How to Get Startup Ideas:
Knowing how to hack also means that when you have ideas, you'll be able to implement them. That's not absolutely necessary..., but it's an advantage. It's a big advantage, when you're considering an idea ..., if instead of merely thinking, "That's an interesting idea," you can think instead, "That's an interesting idea. I'll try building an initial version tonight."
Writing programs, like any sort of fleshing out of big ideas, is hard work. But what's the alternative? Not being able to program, and then you'll just need a programmer.
If you can program, what should you do?
[D]on't take any extra classes, and just build things. ... But don't feel like you have to build things that will become startups. That's premature optimization. Just build things.
Even the professor in me has to admit this is true. You will learn a lot of valuable theory, tools, and practices in class. But when a big idea comes to mind, you need to build it.
As Graham says, perhaps the best way that universities can help students start startups is to find ways to "leave them alone in the right way".
Of course, programming skills are not all you need. You'll probably need to be able to understand and learn from users:
When you find an unmet need that isn't your own, it may be somewhat blurry at first. The person who needs something may not know exactly what they need. In that case I often recommend that founders act like consultants -- that they do what they'd do if they'd been retained to solve the problems of this one user.
That's when those social science courses can come in handy.
Alan Kay talks about programming languages quite a bit in this wide-ranging interview. (Aren't all interviews with Kay wide-ranging?) I liked this fuzzy bifurcation of the language world:
... a lot of them are either the agglutination of features or ... a crystallization of style.
My initial reaction was that I'm a crystallization-of-style guy. I have always had a deep fondness for style languages, with Smalltalk at the head of the list and Joy and Scheme not far behind.
But I'm not a purist when it comes to neat and scruffy. As an undergrad, I really liked programming in PL/I. Java never bothered me as much as it bothered some of my purist friends, and I admit unashamedly that I enjoy programming in it.
These days, I like Ruby as much as I like any language. It is a language that lies in the fuzz between Kay's categories. It has an "everything is an object" ethos but, man alive, is it an amalgamation of syntactic and semantic desiderata.
I attribute linguistic split personality to this: I prefer languages with a "real center", but I don't mind imposing a stylistic filter on an agglutinated language. PL/I always felt comfortable because I programmed with a pure structured programming vibe. When I program in Java or Ruby now, somewhere in the center of my mind is a Smalltalk programmer seeing the language through a Smalltalk lens. I have to make a few pragmatic concessions to the realities of my tool, and everything seems to work out fine.
This semester, I have been teaching with Java. Next semester, I will be teaching with Scheme. I guess I can turn off the filter.